From b775be2ef720462117a534ab2d6507e14635a9a1 Mon Sep 17 00:00:00 2001 From: ExampleWasTaken <58574351+ExampleWasTaken@users.noreply.github.com> Date: Wed, 29 May 2024 11:16:49 +0200 Subject: [PATCH 01/82] add eslint v9/tseslint v8 - 827 errors --- eslint.config.mjs | 21 + .eslintrc.json => old.eslintrc.json | 0 package-lock.json | 3012 ++++++--------------------- package.json | 8 +- 4 files changed, 710 insertions(+), 2331 deletions(-) create mode 100644 eslint.config.mjs rename .eslintrc.json => old.eslintrc.json (100%) diff --git a/eslint.config.mjs b/eslint.config.mjs new file mode 100644 index 00000000..11c0371d --- /dev/null +++ b/eslint.config.mjs @@ -0,0 +1,21 @@ +import eslint from '@eslint/js'; +import tseslint from 'typescript-eslint'; +import prettierPlugin from 'eslint-plugin-prettier'; +import prettierConfig from 'eslint-config-prettier'; + +export default tseslint.config( + eslint.configs.recommended, + ...tseslint.configs.strictTypeChecked, + prettierConfig, + { + plugins: { + prettierPlugin, + }, + languageOptions: { + parserOptions: { + project: true, + tsconfigRootDir: import.meta.dirname, + } + }, + } +); \ No newline at end of file diff --git a/.eslintrc.json b/old.eslintrc.json similarity index 100% rename from .eslintrc.json rename to old.eslintrc.json diff --git a/package-lock.json b/package-lock.json index 5700a273..d0ded7e3 100644 --- a/package-lock.json +++ b/package-lock.json @@ -23,19 +23,22 @@ "winston": "^3.3.4" }, "devDependencies": { - "@flybywiresim/eslint-config": "^0.1.0", + "@eslint/js": "^9.3.0", "@types/bad-words": "^3.0.3", "@types/config": "^3.3.1", "@types/jsdom": "^21.1.6", "@types/node": "^18.0.0", "@types/node-fetch": "^2.6.10", - "@typescript-eslint/eslint-plugin": "^6.18.0", "@typescript-eslint/parser": "^6.18.0", "dotenv": "^16.0.0", - "eslint": "^7.29.0", + "eslint": "^8.57.0", + "eslint-config-prettier": "^9.1.0", + "eslint-plugin-prettier": "^5.1.3", "nodemon": "^3.0.2", + "prettier": "^3.2.5", "ts-node": "^10.4.0", - "typescript": "^5.0.3" + "typescript": "^5.4.5", + "typescript-eslint": "^7.11.0" }, "engines": { "node": "18.x" @@ -1467,121 +1470,6 @@ "node": ">=14.0.0" } }, - "node_modules/@babel/code-frame": { - "version": "7.12.11", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.11.tgz", - "integrity": "sha512-Zt1yodBx1UcyiePMSkWnU4hPqhwq7hGi2nFL1LeA3EUl+q2LQx16MISgJ0+z7dnmgvP9QtIleuETGOiOH1RcIw==", - "dev": true, - "dependencies": { - "@babel/highlight": "^7.10.4" - } - }, - "node_modules/@babel/helper-validator-identifier": { - "version": "7.22.20", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz", - "integrity": "sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/highlight": { - "version": "7.23.4", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.23.4.tgz", - "integrity": "sha512-acGdbYSfp2WheJoJm/EBBBLh/ID8KDc64ISZ9DYtBmC8/Q204PZJLHyzeB5qMzJ5trcOkybd78M4x2KWsUq++A==", - "dev": true, - "dependencies": { - "@babel/helper-validator-identifier": "^7.22.20", - "chalk": "^2.4.2", - "js-tokens": "^4.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/highlight/node_modules/ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "dependencies": { - "color-convert": "^1.9.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/highlight/node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/highlight/node_modules/color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dev": true, - "dependencies": { - "color-name": "1.1.3" - } - }, - "node_modules/@babel/highlight/node_modules/color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", - "dev": true - }, - "node_modules/@babel/highlight/node_modules/escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", - "dev": true, - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/@babel/highlight/node_modules/has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/highlight/node_modules/supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/runtime": { - "version": "7.23.8", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.23.8.tgz", - "integrity": "sha512-Y7KbAP984rn1VGMbGqKmBLio9V7y5Je9GvU4rQPCPinCyNfUcToxIXl06d59URp/F3LwinvODxab5N/G6qggkw==", - "dev": true, - "dependencies": { - "regenerator-runtime": "^0.14.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, "node_modules/@colors/colors": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.6.0.tgz", @@ -1735,23 +1623,26 @@ } }, "node_modules/@eslint/eslintrc": { - "version": "0.4.3", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-0.4.3.tgz", - "integrity": "sha512-J6KFFz5QCYUJq3pf0mjEcCJVERbzv71PUIDczuh9JkwGEzced6CO5ADLHB1rbf/+oPBtoPfMYNOpGDzCANlbXw==", + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.4.tgz", + "integrity": "sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==", "dev": true, "dependencies": { "ajv": "^6.12.4", - "debug": "^4.1.1", - "espree": "^7.3.0", - "globals": "^13.9.0", - "ignore": "^4.0.6", + "debug": "^4.3.2", + "espree": "^9.6.0", + "globals": "^13.19.0", + "ignore": "^5.2.0", "import-fresh": "^3.2.1", - "js-yaml": "^3.13.1", - "minimatch": "^3.0.4", + "js-yaml": "^4.1.0", + "minimatch": "^3.1.2", "strip-json-comments": "^3.1.1" }, "engines": { - "node": "^10.12.0 || >=12.0.0" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" } }, "node_modules/@eslint/eslintrc/node_modules/brace-expansion": { @@ -1764,15 +1655,6 @@ "concat-map": "0.0.1" } }, - "node_modules/@eslint/eslintrc/node_modules/ignore": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", - "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", - "dev": true, - "engines": { - "node": ">= 4" - } - }, "node_modules/@eslint/eslintrc/node_modules/minimatch": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", @@ -1785,6 +1667,15 @@ "node": "*" } }, + "node_modules/@eslint/js": { + "version": "9.3.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.3.0.tgz", + "integrity": "sha512-niBqk8iwv96+yuTwjM6bWg8ovzAPF9qkICsGtcoa5/dmqcEMfdwNAX7+/OHcJHc7wj7XqPxH98oAHytFYlw6Sw==", + "dev": true, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, "node_modules/@fastify/busboy": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/@fastify/busboy/-/busboy-2.1.0.tgz", @@ -1793,21 +1684,6 @@ "node": ">=14" } }, - "node_modules/@flybywiresim/eslint-config": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/@flybywiresim/eslint-config/-/eslint-config-0.1.0.tgz", - "integrity": "sha512-j+uT0ZtI2vjfSVSr57vZxNMaT9i3Y4BIf2ucx6NdOaeBn9hWUWBrrPMKPSRE68vjRvBQd7cqWvJyFwvswNS5dA==", - "dev": true, - "dependencies": { - "eslint-config-airbnb": "^18.2.1", - "eslint-plugin-import": "^2.22.1", - "eslint-plugin-jsx-a11y": "^6.3.1", - "eslint-plugin-react": "^7.21.5" - }, - "peerDependencies": { - "eslint": "^7.21.0" - } - }, "node_modules/@hokify/agenda": { "version": "6.3.0", "resolved": "https://registry.npmjs.org/@hokify/agenda/-/agenda-6.3.0.tgz", @@ -1825,14 +1701,14 @@ } }, "node_modules/@humanwhocodes/config-array": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.5.0.tgz", - "integrity": "sha512-FagtKFz74XrTl7y6HCzQpwDfXP0yhxe9lHLD1UZxjvZIcbyRz8zTFF/yYNfSfzU414eDwZ1SrO0Qvtyf+wFMQg==", + "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": "^1.2.0", - "debug": "^4.1.1", - "minimatch": "^3.0.4" + "@humanwhocodes/object-schema": "^2.0.2", + "debug": "^4.3.1", + "minimatch": "^3.0.5" }, "engines": { "node": ">=10.10.0" @@ -1860,10 +1736,23 @@ "node": "*" } }, + "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, + "engines": { + "node": ">=12.22" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, "node_modules/@humanwhocodes/object-schema": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz", - "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==", + "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/@jridgewell/resolve-uri": { @@ -1986,6 +1875,18 @@ "@octokit/openapi-types": "^19.1.0" } }, + "node_modules/@pkgr/core": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@pkgr/core/-/core-0.1.1.tgz", + "integrity": "sha512-cq8o4cWH0ibXh9VGi5P20Tu9XF/0fFXl9EUinr9QfTM7a7p0oTA4iJRCQWppXR1Pg8dSM0UCItCkPwsk9qWWYA==", + "dev": true, + "engines": { + "node": "^12.20.0 || ^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/unts" + } + }, "node_modules/@sapphire/async-queue": { "version": "1.5.1", "resolved": "https://registry.npmjs.org/@sapphire/async-queue/-/async-queue-1.5.1.tgz", @@ -2700,18 +2601,6 @@ "parse5": "^7.0.0" } }, - "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 - }, - "node_modules/@types/json5": { - "version": "0.0.29", - "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", - "integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==", - "dev": true - }, "node_modules/@types/node": { "version": "18.19.6", "resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.6.tgz", @@ -2730,12 +2619,6 @@ "form-data": "^4.0.0" } }, - "node_modules/@types/semver": { - "version": "7.5.6", - "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.6.tgz", - "integrity": "sha512-dn1l8LaMea/IjDoHNd9J52uBbInB796CDffS6VdIxvqYCPSG0V0DzHp76GpaWnlhg88uYyPbXCDIowa86ybd5A==", - "dev": true - }, "node_modules/@types/tough-cookie": { "version": "4.0.5", "resolved": "https://registry.npmjs.org/@types/tough-cookie/-/tough-cookie-4.0.5.tgz", @@ -2769,23 +2652,17 @@ "@types/node": "*" } }, - "node_modules/@typescript-eslint/eslint-plugin": { + "node_modules/@typescript-eslint/parser": { "version": "6.18.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.18.1.tgz", - "integrity": "sha512-nISDRYnnIpk7VCFrGcu1rnZfM1Dh9LRHnfgdkjcbi/l7g16VYRri3TjXi9Ir4lOZSw5N/gnV/3H7jIPQ8Q4daA==", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-6.18.1.tgz", + "integrity": "sha512-zct/MdJnVaRRNy9e84XnVtRv9Vf91/qqe+hZJtKanjojud4wAVy/7lXxJmMyX6X6J+xc6c//YEWvpeif8cAhWA==", "dev": true, "dependencies": { - "@eslint-community/regexpp": "^4.5.1", "@typescript-eslint/scope-manager": "6.18.1", - "@typescript-eslint/type-utils": "6.18.1", - "@typescript-eslint/utils": "6.18.1", + "@typescript-eslint/types": "6.18.1", + "@typescript-eslint/typescript-estree": "6.18.1", "@typescript-eslint/visitor-keys": "6.18.1", - "debug": "^4.3.4", - "graphemer": "^1.4.0", - "ignore": "^5.2.4", - "natural-compare": "^1.4.0", - "semver": "^7.5.4", - "ts-api-utils": "^1.0.1" + "debug": "^4.3.4" }, "engines": { "node": "^16.0.0 || >=18.0.0" @@ -2795,7 +2672,6 @@ "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "@typescript-eslint/parser": "^6.0.0 || ^6.0.0-alpha", "eslint": "^7.0.0 || ^8.0.0" }, "peerDependenciesMeta": { @@ -2804,27 +2680,43 @@ } } }, - "node_modules/@typescript-eslint/parser": { + "node_modules/@typescript-eslint/scope-manager": { "version": "6.18.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-6.18.1.tgz", - "integrity": "sha512-zct/MdJnVaRRNy9e84XnVtRv9Vf91/qqe+hZJtKanjojud4wAVy/7lXxJmMyX6X6J+xc6c//YEWvpeif8cAhWA==", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.18.1.tgz", + "integrity": "sha512-BgdBwXPFmZzaZUuw6wKiHKIovms97a7eTImjkXCZE04TGHysG+0hDQPmygyvgtkoB/aOQwSM/nWv3LzrOIQOBw==", "dev": true, "dependencies": { - "@typescript-eslint/scope-manager": "6.18.1", "@typescript-eslint/types": "6.18.1", - "@typescript-eslint/typescript-estree": "6.18.1", - "@typescript-eslint/visitor-keys": "6.18.1", - "debug": "^4.3.4" + "@typescript-eslint/visitor-keys": "6.18.1" }, "engines": { "node": "^16.0.0 || >=18.0.0" }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/type-utils": { + "version": "7.11.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-7.11.0.tgz", + "integrity": "sha512-WmppUEgYy+y1NTseNMJ6mCFxt03/7jTOy08bcg7bxJJdsM4nuhnchyBbE8vryveaJUf62noH7LodPSo5Z0WUCg==", + "dev": true, + "dependencies": { + "@typescript-eslint/typescript-estree": "7.11.0", + "@typescript-eslint/utils": "7.11.0", + "debug": "^4.3.4", + "ts-api-utils": "^1.3.0" + }, + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "eslint": "^7.0.0 || ^8.0.0" + "eslint": "^8.56.0" }, "peerDependenciesMeta": { "typescript": { @@ -2832,50 +2724,79 @@ } } }, - "node_modules/@typescript-eslint/scope-manager": { - "version": "6.18.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.18.1.tgz", - "integrity": "sha512-BgdBwXPFmZzaZUuw6wKiHKIovms97a7eTImjkXCZE04TGHysG+0hDQPmygyvgtkoB/aOQwSM/nWv3LzrOIQOBw==", + "node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/types": { + "version": "7.11.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.11.0.tgz", + "integrity": "sha512-MPEsDRZTyCiXkD4vd3zywDCifi7tatc4K37KqTprCvaXptP7Xlpdw0NR2hRJTetG5TxbWDB79Ys4kLmHliEo/w==", "dev": true, - "dependencies": { - "@typescript-eslint/types": "6.18.1", - "@typescript-eslint/visitor-keys": "6.18.1" - }, "engines": { - "node": "^16.0.0 || >=18.0.0" + "node": "^18.18.0 || >=20.0.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" } }, - "node_modules/@typescript-eslint/type-utils": { - "version": "6.18.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-6.18.1.tgz", - "integrity": "sha512-wyOSKhuzHeU/5pcRDP2G2Ndci+4g653V43gXTpt4nbyoIOAASkGDA9JIAgbQCdCkcr1MvpSYWzxTz0olCn8+/Q==", + "node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/typescript-estree": { + "version": "7.11.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.11.0.tgz", + "integrity": "sha512-cxkhZ2C/iyi3/6U9EPc5y+a6csqHItndvN/CzbNXTNrsC3/ASoYQZEt9uMaEp+xFNjasqQyszp5TumAVKKvJeQ==", "dev": true, "dependencies": { - "@typescript-eslint/typescript-estree": "6.18.1", - "@typescript-eslint/utils": "6.18.1", + "@typescript-eslint/types": "7.11.0", + "@typescript-eslint/visitor-keys": "7.11.0", "debug": "^4.3.4", - "ts-api-utils": "^1.0.1" + "globby": "^11.1.0", + "is-glob": "^4.0.3", + "minimatch": "^9.0.4", + "semver": "^7.6.0", + "ts-api-utils": "^1.3.0" }, "engines": { - "node": "^16.0.0 || >=18.0.0" + "node": "^18.18.0 || >=20.0.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" }, - "peerDependencies": { - "eslint": "^7.0.0 || ^8.0.0" - }, "peerDependenciesMeta": { "typescript": { "optional": true } } }, + "node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/visitor-keys": { + "version": "7.11.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.11.0.tgz", + "integrity": "sha512-7syYk4MzjxTEk0g/w3iqtgxnFQspDJfn6QKD36xMuuhTzjcxY7F8EmBLnALjVyaOF1/bVocu3bS/2/F7rXrveQ==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "7.11.0", + "eslint-visitor-keys": "^3.4.3" + }, + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/type-utils/node_modules/minimatch": { + "version": "9.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.4.tgz", + "integrity": "sha512-KqWh+VchfxcMNRAJjj2tnsSJdNbHsVgnkBhTNrW7AjVo6OvLtxw8zfT9oLw1JSohlFzJ8jCoTgaoXvJ+kHt6fw==", + "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/types": { "version": "6.18.1", "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.18.1.tgz", @@ -2918,84 +2839,177 @@ } }, "node_modules/@typescript-eslint/utils": { - "version": "6.18.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-6.18.1.tgz", - "integrity": "sha512-zZmTuVZvD1wpoceHvoQpOiewmWu3uP9FuTWo8vqpy2ffsmfCE8mklRPi+vmnIYAIk9t/4kOThri2QCDgor+OpQ==", + "version": "7.11.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.11.0.tgz", + "integrity": "sha512-xlAWwPleNRHwF37AhrZurOxA1wyXowW4PqVXZVUNCLjB48CqdPJoJWkrpH2nij9Q3Lb7rtWindtoXwxjxlKKCA==", "dev": true, "dependencies": { "@eslint-community/eslint-utils": "^4.4.0", - "@types/json-schema": "^7.0.12", - "@types/semver": "^7.5.0", - "@typescript-eslint/scope-manager": "6.18.1", - "@typescript-eslint/types": "6.18.1", - "@typescript-eslint/typescript-estree": "6.18.1", - "semver": "^7.5.4" + "@typescript-eslint/scope-manager": "7.11.0", + "@typescript-eslint/types": "7.11.0", + "@typescript-eslint/typescript-estree": "7.11.0" }, "engines": { - "node": "^16.0.0 || >=18.0.0" + "node": "^18.18.0 || >=20.0.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "eslint": "^7.0.0 || ^8.0.0" + "eslint": "^8.56.0" } }, - "node_modules/@typescript-eslint/visitor-keys": { - "version": "6.18.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.18.1.tgz", - "integrity": "sha512-/kvt0C5lRqGoCfsbmm7/CwMqoSkY3zzHLIjdhHZQW3VFrnz7ATecOHR7nb7V+xn4286MBxfnQfQhAmCI0u+bJA==", + "node_modules/@typescript-eslint/utils/node_modules/@typescript-eslint/scope-manager": { + "version": "7.11.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.11.0.tgz", + "integrity": "sha512-27tGdVEiutD4POirLZX4YzT180vevUURJl4wJGmm6TrQoiYwuxTIY98PBp6L2oN+JQxzE0URvYlzJaBHIekXAw==", "dev": true, "dependencies": { - "@typescript-eslint/types": "6.18.1", - "eslint-visitor-keys": "^3.4.1" + "@typescript-eslint/types": "7.11.0", + "@typescript-eslint/visitor-keys": "7.11.0" }, "engines": { - "node": "^16.0.0 || >=18.0.0" + "node": "^18.18.0 || >=20.0.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" } }, - "node_modules/@vladfrangu/async_event_emitter": { - "version": "2.2.4", - "resolved": "https://registry.npmjs.org/@vladfrangu/async_event_emitter/-/async_event_emitter-2.2.4.tgz", - "integrity": "sha512-ButUPz9E9cXMLgvAW8aLAKKJJsPu1dY1/l/E8xzLFuysowXygs6GBcyunK9rnGC4zTsnIc2mQo71rGw9U+Ykug==", + "node_modules/@typescript-eslint/utils/node_modules/@typescript-eslint/types": { + "version": "7.11.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.11.0.tgz", + "integrity": "sha512-MPEsDRZTyCiXkD4vd3zywDCifi7tatc4K37KqTprCvaXptP7Xlpdw0NR2hRJTetG5TxbWDB79Ys4kLmHliEo/w==", + "dev": true, "engines": { - "node": ">=v14.0.0", - "npm": ">=7.0.0" + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" } }, - "node_modules/abbrev": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", - "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", - "dev": true - }, - "node_modules/acorn": { - "version": "7.4.1", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", - "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", + "node_modules/@typescript-eslint/utils/node_modules/@typescript-eslint/typescript-estree": { + "version": "7.11.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.11.0.tgz", + "integrity": "sha512-cxkhZ2C/iyi3/6U9EPc5y+a6csqHItndvN/CzbNXTNrsC3/ASoYQZEt9uMaEp+xFNjasqQyszp5TumAVKKvJeQ==", "dev": true, - "bin": { - "acorn": "bin/acorn" + "dependencies": { + "@typescript-eslint/types": "7.11.0", + "@typescript-eslint/visitor-keys": "7.11.0", + "debug": "^4.3.4", + "globby": "^11.1.0", + "is-glob": "^4.0.3", + "minimatch": "^9.0.4", + "semver": "^7.6.0", + "ts-api-utils": "^1.3.0" }, "engines": { - "node": ">=0.4.0" + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } } }, - "node_modules/acorn-jsx": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", - "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "node_modules/@typescript-eslint/utils/node_modules/@typescript-eslint/visitor-keys": { + "version": "7.11.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.11.0.tgz", + "integrity": "sha512-7syYk4MzjxTEk0g/w3iqtgxnFQspDJfn6QKD36xMuuhTzjcxY7F8EmBLnALjVyaOF1/bVocu3bS/2/F7rXrveQ==", "dev": true, - "peerDependencies": { - "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + "dependencies": { + "@typescript-eslint/types": "7.11.0", + "eslint-visitor-keys": "^3.4.3" + }, + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" } }, - "node_modules/acorn-walk": { + "node_modules/@typescript-eslint/utils/node_modules/minimatch": { + "version": "9.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.4.tgz", + "integrity": "sha512-KqWh+VchfxcMNRAJjj2tnsSJdNbHsVgnkBhTNrW7AjVo6OvLtxw8zfT9oLw1JSohlFzJ8jCoTgaoXvJ+kHt6fw==", + "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/visitor-keys": { + "version": "6.18.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.18.1.tgz", + "integrity": "sha512-/kvt0C5lRqGoCfsbmm7/CwMqoSkY3zzHLIjdhHZQW3VFrnz7ATecOHR7nb7V+xn4286MBxfnQfQhAmCI0u+bJA==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "6.18.1", + "eslint-visitor-keys": "^3.4.1" + }, + "engines": { + "node": "^16.0.0 || >=18.0.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.2.4", + "resolved": "https://registry.npmjs.org/@vladfrangu/async_event_emitter/-/async_event_emitter-2.2.4.tgz", + "integrity": "sha512-ButUPz9E9cXMLgvAW8aLAKKJJsPu1dY1/l/E8xzLFuysowXygs6GBcyunK9rnGC4zTsnIc2mQo71rGw9U+Ykug==", + "engines": { + "node": ">=v14.0.0", + "npm": ">=7.0.0" + } + }, + "node_modules/abbrev": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", + "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", + "dev": true + }, + "node_modules/acorn": { + "version": "8.11.3", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.3.tgz", + "integrity": "sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==", + "dev": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true, + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/acorn-walk": { "version": "8.3.1", "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.1.tgz", "integrity": "sha512-TgUZgYvqZprrl7YldZNoa9OciCAyZR+Ejm9eXzKCmjsF5IKp/wgQ7Z/ZpjpGTIUPwrHQIcYeI8qDh4PsEwxMbw==", @@ -3031,15 +3045,6 @@ "url": "https://github.com/sponsors/epoberezkin" } }, - "node_modules/ansi-colors": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.3.tgz", - "integrity": "sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==", - "dev": true, - "engines": { - "node": ">=6" - } - }, "node_modules/ansi-regex": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", @@ -3084,54 +3089,10 @@ "dev": true }, "node_modules/argparse": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", - "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", - "dev": true, - "dependencies": { - "sprintf-js": "~1.0.2" - } - }, - "node_modules/aria-query": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.3.0.tgz", - "integrity": "sha512-b0P0sZPKtyu8HkeRAfCq0IfURZK+SuwMjY1UXGBU27wpAiTwQAIlq56IbIO+ytk/JjS1fMR14ee5WBBfKi5J6A==", - "dev": true, - "dependencies": { - "dequal": "^2.0.3" - } - }, - "node_modules/array-buffer-byte-length": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.0.tgz", - "integrity": "sha512-LPuwb2P+NrQw3XhxGc36+XSvuBPopovXYTR9Ew++Du9Yb/bx5AzBfrIsBoj0EZUifjQU+sHL21sseZ3jerWO/A==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "is-array-buffer": "^3.0.1" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/array-includes": { - "version": "3.1.7", - "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.7.tgz", - "integrity": "sha512-dlcsNBIiWhPkHdOEEKnehA+RNUWDc4UqFtnIXU4uuYDPtA4LDkr7qip2p0VvFAEXNDr0yWZ9PJyIRiGjRLQzwQ==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1", - "get-intrinsic": "^1.2.1", - "is-string": "^1.0.7" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } + "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 }, "node_modules/array-union": { "version": "2.1.0", @@ -3142,159 +3103,16 @@ "node": ">=8" } }, - "node_modules/array.prototype.findlastindex": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/array.prototype.findlastindex/-/array.prototype.findlastindex-1.2.3.tgz", - "integrity": "sha512-LzLoiOMAxvy+Gd3BAq3B7VeIgPdo+Q8hthvKtXybMvRV0jrXfJM/t8mw7nNlpEcVlVUnCnM2KSX4XU5HmpodOA==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1", - "es-shim-unscopables": "^1.0.0", - "get-intrinsic": "^1.2.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/array.prototype.flat": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.3.2.tgz", - "integrity": "sha512-djYB+Zx2vLewY8RWlNCUdHjDXs2XOgm602S9E7P/UpHgfeHL00cRiIF+IN/G/aUJ7kGPb6yO/ErDI5V2s8iycA==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1", - "es-shim-unscopables": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/array.prototype.flatmap": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.3.2.tgz", - "integrity": "sha512-Ewyx0c9PmpcsByhSW4r+9zDU7sGjFc86qf/kKtuSCRdhfbk0SNLLkaT5qvcHnRGgc5NP/ly/y+qkXkqONX54CQ==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1", - "es-shim-unscopables": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/array.prototype.tosorted": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/array.prototype.tosorted/-/array.prototype.tosorted-1.1.2.tgz", - "integrity": "sha512-HuQCHOlk1Weat5jzStICBCd83NxiIMwqDg/dHEsoefabn/hJRj5pVdWcPUSpRrwhwxZOsQassMpgN/xRYFBMIg==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1", - "es-shim-unscopables": "^1.0.0", - "get-intrinsic": "^1.2.1" - } - }, - "node_modules/arraybuffer.prototype.slice": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.2.tgz", - "integrity": "sha512-yMBKppFur/fbHu9/6USUe03bZ4knMYiwFBcyiaXB8Go0qNehwX6inYPzK9U0NeQvGxKthcmHcaR8P5MStSRBAw==", - "dev": true, - "dependencies": { - "array-buffer-byte-length": "^1.0.0", - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1", - "get-intrinsic": "^1.2.1", - "is-array-buffer": "^3.0.2", - "is-shared-array-buffer": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/ast-types-flow": { - "version": "0.0.8", - "resolved": "https://registry.npmjs.org/ast-types-flow/-/ast-types-flow-0.0.8.tgz", - "integrity": "sha512-OH/2E5Fg20h2aPrbe+QL8JZQFko0YZaF+j4mnQ7BGhfavO7OpSLa8a0y9sBwomHdSbkhTS8TQNayBfnW5DwbvQ==", - "dev": true - }, - "node_modules/astral-regex": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz", - "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, "node_modules/async": { "version": "3.2.5", "resolved": "https://registry.npmjs.org/async/-/async-3.2.5.tgz", "integrity": "sha512-baNZyqaaLhyLVKm/DlvdW051MSgO6b8eVfIezl9E5PqWxFgzLm/wQntEW4zOytVburDEr0JlALEpdOFwvErLsg==" }, - "node_modules/asynciterator.prototype": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/asynciterator.prototype/-/asynciterator.prototype-1.0.0.tgz", - "integrity": "sha512-wwHYEIS0Q80f5mosx3L/dfG5t5rjEa9Ft51GTaNt862EnpyGHpgz2RkZvLPp1oF5TnAiTohkEKVEu8pQPJI7Vg==", - "dev": true, - "dependencies": { - "has-symbols": "^1.0.3" - } - }, "node_modules/asynckit": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" }, - "node_modules/available-typed-arrays": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz", - "integrity": "sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==", - "dev": true, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/axe-core": { - "version": "4.7.0", - "resolved": "https://registry.npmjs.org/axe-core/-/axe-core-4.7.0.tgz", - "integrity": "sha512-M0JtH+hlOL5pLQwHOLNYZaXuhqmvS8oExsqB1SBYgA4Dk7u/xx+YdGHXaK5pyUfed5mYXdlYiphWq3G8cRi5JQ==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/axobject-query": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-3.2.1.tgz", - "integrity": "sha512-jsyHu61e6N4Vbz/v18DHwWYKK0bSWLqn47eeDSKPB7m8tqMHF9YJ+mhIk2lVteyZrY8tnSj/jHOv4YiTCuCJgg==", - "dev": true, - "dependencies": { - "dequal": "^2.0.3" - } - }, "node_modules/bad-words": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/bad-words/-/bad-words-3.0.4.tgz", @@ -3413,20 +3231,6 @@ "ieee754": "^1.1.13" } }, - "node_modules/call-bind": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.5.tgz", - "integrity": "sha512-C3nQxfFZxFRVoJoGKKI8y3MOEo129NQ+FgQ08iye+Mk4zNZZGdjfs06bVTr+DBSlA66Q2VEcMki/cUCP4SercQ==", - "dev": true, - "dependencies": { - "function-bind": "^1.1.2", - "get-intrinsic": "^1.2.1", - "set-function-length": "^1.1.1" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/callsites": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", @@ -3564,12 +3368,6 @@ "node": ">= 10.0.0" } }, - "node_modules/confusing-browser-globals": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/confusing-browser-globals/-/confusing-browser-globals-1.0.11.tgz", - "integrity": "sha512-JsPKdmh8ZkmnHxDk55FZ1TqVLvEQTvoByJZRN9jzI0UjxK/QgAmsphz7PGtqgPieQZ/CQcHWXCR7ATDNhGe+YA==", - "dev": true - }, "node_modules/create-require": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", @@ -3624,12 +3422,6 @@ "node": ">=18" } }, - "node_modules/damerau-levenshtein": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/damerau-levenshtein/-/damerau-levenshtein-1.0.8.tgz", - "integrity": "sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA==", - "dev": true - }, "node_modules/data-urls": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-5.0.0.tgz", @@ -3713,37 +3505,6 @@ "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", "dev": true }, - "node_modules/define-data-property": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.1.tgz", - "integrity": "sha512-E7uGkTzkk1d0ByLeSc6ZsFS79Axg+m1P/VsgYsxHgiuc3tFSj+MjMIwe90FC4lOAZzNBdY7kkO2P2wKdsQ1vgQ==", - "dev": true, - "dependencies": { - "get-intrinsic": "^1.2.1", - "gopd": "^1.0.1", - "has-property-descriptors": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/define-properties": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz", - "integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==", - "dev": true, - "dependencies": { - "define-data-property": "^1.0.1", - "has-property-descriptors": "^1.0.0", - "object-keys": "^1.1.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/delayed-stream": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", @@ -3757,15 +3518,6 @@ "resolved": "https://registry.npmjs.org/deprecation/-/deprecation-2.3.1.tgz", "integrity": "sha512-xmHIy4F3scKVwMsQ4WnVaS8bHOx0DmVwRywosKhaILI0ywMDWPtBSku2HNxRvF7jtwDRsoEwYQSfbxj8b7RlJQ==" }, - "node_modules/dequal": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz", - "integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==", - "dev": true, - "engines": { - "node": ">=6" - } - }, "node_modules/diff": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", @@ -3840,30 +3592,11 @@ "url": "https://github.com/motdotla/dotenv?sponsor=1" } }, - "node_modules/emoji-regex": { - "version": "9.2.2", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", - "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", - "dev": true - }, "node_modules/enabled": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/enabled/-/enabled-2.0.0.tgz", "integrity": "sha512-AKrN98kuwOzMIdAizXGI86UFBoo26CL21UM763y1h/GMSJ4/OHU9k2YlsmBpyScFo/wbLzWQJBMCW4+IO3/+OQ==" }, - "node_modules/enquirer": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.4.1.tgz", - "integrity": "sha512-rRqJg/6gd538VHvR3PSrdRBb/1Vy2YfzHqzvbhGIQpDRKIa4FgV/54b5Q1xYSxOOwKvjXweS26E0Q+nAMwp2pQ==", - "dev": true, - "dependencies": { - "ansi-colors": "^4.1.1", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8.6" - } - }, "node_modules/entities": { "version": "4.5.0", "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", @@ -3875,121 +3608,6 @@ "url": "https://github.com/fb55/entities?sponsor=1" } }, - "node_modules/es-abstract": { - "version": "1.22.3", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.22.3.tgz", - "integrity": "sha512-eiiY8HQeYfYH2Con2berK+To6GrK2RxbPawDkGq4UiCQQfZHb6wX9qQqkbpPqaxQFcl8d9QzZqo0tGE0VcrdwA==", - "dev": true, - "dependencies": { - "array-buffer-byte-length": "^1.0.0", - "arraybuffer.prototype.slice": "^1.0.2", - "available-typed-arrays": "^1.0.5", - "call-bind": "^1.0.5", - "es-set-tostringtag": "^2.0.1", - "es-to-primitive": "^1.2.1", - "function.prototype.name": "^1.1.6", - "get-intrinsic": "^1.2.2", - "get-symbol-description": "^1.0.0", - "globalthis": "^1.0.3", - "gopd": "^1.0.1", - "has-property-descriptors": "^1.0.0", - "has-proto": "^1.0.1", - "has-symbols": "^1.0.3", - "hasown": "^2.0.0", - "internal-slot": "^1.0.5", - "is-array-buffer": "^3.0.2", - "is-callable": "^1.2.7", - "is-negative-zero": "^2.0.2", - "is-regex": "^1.1.4", - "is-shared-array-buffer": "^1.0.2", - "is-string": "^1.0.7", - "is-typed-array": "^1.1.12", - "is-weakref": "^1.0.2", - "object-inspect": "^1.13.1", - "object-keys": "^1.1.1", - "object.assign": "^4.1.4", - "regexp.prototype.flags": "^1.5.1", - "safe-array-concat": "^1.0.1", - "safe-regex-test": "^1.0.0", - "string.prototype.trim": "^1.2.8", - "string.prototype.trimend": "^1.0.7", - "string.prototype.trimstart": "^1.0.7", - "typed-array-buffer": "^1.0.0", - "typed-array-byte-length": "^1.0.0", - "typed-array-byte-offset": "^1.0.0", - "typed-array-length": "^1.0.4", - "unbox-primitive": "^1.0.2", - "which-typed-array": "^1.1.13" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/es-iterator-helpers": { - "version": "1.0.15", - "resolved": "https://registry.npmjs.org/es-iterator-helpers/-/es-iterator-helpers-1.0.15.tgz", - "integrity": "sha512-GhoY8uYqd6iwUl2kgjTm4CZAf6oo5mHK7BPqx3rKgx893YSsy0LGHV6gfqqQvZt/8xM8xeOnfXBCfqclMKkJ5g==", - "dev": true, - "dependencies": { - "asynciterator.prototype": "^1.0.0", - "call-bind": "^1.0.2", - "define-properties": "^1.2.1", - "es-abstract": "^1.22.1", - "es-set-tostringtag": "^2.0.1", - "function-bind": "^1.1.1", - "get-intrinsic": "^1.2.1", - "globalthis": "^1.0.3", - "has-property-descriptors": "^1.0.0", - "has-proto": "^1.0.1", - "has-symbols": "^1.0.3", - "internal-slot": "^1.0.5", - "iterator.prototype": "^1.1.2", - "safe-array-concat": "^1.0.1" - } - }, - "node_modules/es-set-tostringtag": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.0.2.tgz", - "integrity": "sha512-BuDyupZt65P9D2D2vA/zqcI3G5xRsklm5N3xCwuiy+/vKy8i0ifdsQP1sLgO4tZDSCaQUSnmC48khknGMV3D2Q==", - "dev": true, - "dependencies": { - "get-intrinsic": "^1.2.2", - "has-tostringtag": "^1.0.0", - "hasown": "^2.0.0" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/es-shim-unscopables": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.0.2.tgz", - "integrity": "sha512-J3yBRXCzDu4ULnQwxyToo/OjdMx6akgVC7K6few0a7F/0wLtmKKN7I73AH5T2836UuXRqN7Qg+IIUw/+YJksRw==", - "dev": true, - "dependencies": { - "hasown": "^2.0.0" - } - }, - "node_modules/es-to-primitive": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", - "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", - "dev": true, - "dependencies": { - "is-callable": "^1.1.4", - "is-date-object": "^1.0.1", - "is-symbol": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/escape-string-regexp": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", @@ -4003,429 +3621,116 @@ } }, "node_modules/eslint": { - "version": "7.32.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-7.32.0.tgz", - "integrity": "sha512-VHZ8gX+EDfz+97jGcgyGCyRia/dPOd6Xh9yPv8Bl1+SoaIwD+a/vlrOmGRUyOYu7MwUhc7CxqeaDZU13S4+EpA==", - "dev": true, - "dependencies": { - "@babel/code-frame": "7.12.11", - "@eslint/eslintrc": "^0.4.3", - "@humanwhocodes/config-array": "^0.5.0", - "ajv": "^6.10.0", + "version": "8.57.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.57.0.tgz", + "integrity": "sha512-dZ6+mexnaTIbSBZWgou51U6OmzIhYM2VcNdtiTtI7qPNZm35Akpr0f6vtw3w1Kmn5PYo+tZVfh13WrhpS6oLqQ==", + "dev": true, + "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", + "@humanwhocodes/module-importer": "^1.0.1", + "@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.0.1", + "debug": "^4.3.2", "doctrine": "^3.0.0", - "enquirer": "^2.3.5", "escape-string-regexp": "^4.0.0", - "eslint-scope": "^5.1.1", - "eslint-utils": "^2.1.0", - "eslint-visitor-keys": "^2.0.0", - "espree": "^7.3.1", - "esquery": "^1.4.0", + "eslint-scope": "^7.2.2", + "eslint-visitor-keys": "^3.4.3", + "espree": "^9.6.1", + "esquery": "^1.4.2", "esutils": "^2.0.2", "fast-deep-equal": "^3.1.3", "file-entry-cache": "^6.0.1", - "functional-red-black-tree": "^1.0.1", - "glob-parent": "^5.1.2", - "globals": "^13.6.0", - "ignore": "^4.0.6", - "import-fresh": "^3.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", - "js-yaml": "^3.13.1", + "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.0.4", + "minimatch": "^3.1.2", "natural-compare": "^1.4.0", - "optionator": "^0.9.1", - "progress": "^2.0.0", - "regexpp": "^3.1.0", - "semver": "^7.2.1", - "strip-ansi": "^6.0.0", - "strip-json-comments": "^3.1.0", - "table": "^6.0.9", - "text-table": "^0.2.0", - "v8-compile-cache": "^2.0.3" + "optionator": "^0.9.3", + "strip-ansi": "^6.0.1", + "text-table": "^0.2.0" }, "bin": { "eslint": "bin/eslint.js" }, "engines": { - "node": "^10.12.0 || >=12.0.0" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" }, "funding": { "url": "https://opencollective.com/eslint" } }, - "node_modules/eslint-config-airbnb": { - "version": "18.2.1", - "resolved": "https://registry.npmjs.org/eslint-config-airbnb/-/eslint-config-airbnb-18.2.1.tgz", - "integrity": "sha512-glZNDEZ36VdlZWoxn/bUR1r/sdFKPd1mHPbqUtkctgNG4yT2DLLtJ3D+yCV+jzZCc2V1nBVkmdknOJBZ5Hc0fg==", + "node_modules/eslint-config-prettier": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-9.1.0.tgz", + "integrity": "sha512-NSWl5BFQWEPi1j4TjVNItzYV7dZXZ+wP6I6ZhrBGpChQhZRUaElihE9uRRkcbRnNb76UMKDF3r+WTmNcGPKsqw==", "dev": true, - "dependencies": { - "eslint-config-airbnb-base": "^14.2.1", - "object.assign": "^4.1.2", - "object.entries": "^1.1.2" - }, - "engines": { - "node": ">= 6" + "bin": { + "eslint-config-prettier": "bin/cli.js" }, "peerDependencies": { - "eslint": "^5.16.0 || ^6.8.0 || ^7.2.0", - "eslint-plugin-import": "^2.22.1", - "eslint-plugin-jsx-a11y": "^6.4.1", - "eslint-plugin-react": "^7.21.5", - "eslint-plugin-react-hooks": "^4 || ^3 || ^2.3.0 || ^1.7.0" + "eslint": ">=7.0.0" } }, - "node_modules/eslint-config-airbnb-base": { - "version": "14.2.1", - "resolved": "https://registry.npmjs.org/eslint-config-airbnb-base/-/eslint-config-airbnb-base-14.2.1.tgz", - "integrity": "sha512-GOrQyDtVEc1Xy20U7vsB2yAoB4nBlfH5HZJeatRXHleO+OS5Ot+MWij4Dpltw4/DyIkqUfqz1epfhVR5XWWQPA==", + "node_modules/eslint-plugin-prettier": { + "version": "5.1.3", + "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-5.1.3.tgz", + "integrity": "sha512-C9GCVAs4Eq7ZC/XFQHITLiHJxQngdtraXaM+LoUFoFp/lHNl2Zn8f3WQbe9HvTBBQ9YnKFB0/2Ajdqwo5D1EAw==", "dev": true, "dependencies": { - "confusing-browser-globals": "^1.0.10", - "object.assign": "^4.1.2", - "object.entries": "^1.1.2" + "prettier-linter-helpers": "^1.0.0", + "synckit": "^0.8.6" }, "engines": { - "node": ">= 6" + "node": "^14.18.0 || >=16.0.0" }, - "peerDependencies": { - "eslint": "^5.16.0 || ^6.8.0 || ^7.2.0", - "eslint-plugin-import": "^2.22.1" - } - }, - "node_modules/eslint-import-resolver-node": { - "version": "0.3.9", - "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.9.tgz", - "integrity": "sha512-WFj2isz22JahUv+B788TlO3N6zL3nNJGU8CcZbPZvVEkBPaJdCV4vy5wyghty5ROFbCRnm132v8BScu5/1BQ8g==", - "dev": true, - "dependencies": { - "debug": "^3.2.7", - "is-core-module": "^2.13.0", - "resolve": "^1.22.4" - } - }, - "node_modules/eslint-import-resolver-node/node_modules/debug": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", - "dev": true, - "dependencies": { - "ms": "^2.1.1" - } - }, - "node_modules/eslint-module-utils": { - "version": "2.8.0", - "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.8.0.tgz", - "integrity": "sha512-aWajIYfsqCKRDgUfjEXNN/JlrzauMuSEy5sbd7WXbtW3EH6A6MpwEh42c7qD+MqQo9QMJ6fWLAeIJynx0g6OAw==", - "dev": true, - "dependencies": { - "debug": "^3.2.7" + "funding": { + "url": "https://opencollective.com/eslint-plugin-prettier" }, - "engines": { - "node": ">=4" + "peerDependencies": { + "@types/eslint": ">=8.0.0", + "eslint": ">=8.0.0", + "eslint-config-prettier": "*", + "prettier": ">=3.0.0" }, "peerDependenciesMeta": { - "eslint": { + "@types/eslint": { + "optional": true + }, + "eslint-config-prettier": { "optional": true } } }, - "node_modules/eslint-module-utils/node_modules/debug": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", - "dev": true, - "dependencies": { - "ms": "^2.1.1" - } - }, - "node_modules/eslint-plugin-import": { - "version": "2.29.1", - "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.29.1.tgz", - "integrity": "sha512-BbPC0cuExzhiMo4Ff1BTVwHpjjv28C5R+btTOGaCRC7UEz801up0JadwkeSk5Ued6TG34uaczuVuH6qyy5YUxw==", - "dev": true, - "dependencies": { - "array-includes": "^3.1.7", - "array.prototype.findlastindex": "^1.2.3", - "array.prototype.flat": "^1.3.2", - "array.prototype.flatmap": "^1.3.2", - "debug": "^3.2.7", - "doctrine": "^2.1.0", - "eslint-import-resolver-node": "^0.3.9", - "eslint-module-utils": "^2.8.0", - "hasown": "^2.0.0", - "is-core-module": "^2.13.1", - "is-glob": "^4.0.3", - "minimatch": "^3.1.2", - "object.fromentries": "^2.0.7", - "object.groupby": "^1.0.1", - "object.values": "^1.1.7", - "semver": "^6.3.1", - "tsconfig-paths": "^3.15.0" - }, - "engines": { - "node": ">=4" - }, - "peerDependencies": { - "eslint": "^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8" - } - }, - "node_modules/eslint-plugin-import/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, - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/eslint-plugin-import/node_modules/debug": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", - "dev": true, - "dependencies": { - "ms": "^2.1.1" - } - }, - "node_modules/eslint-plugin-import/node_modules/doctrine": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", - "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", - "dev": true, - "dependencies": { - "esutils": "^2.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/eslint-plugin-import/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, - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/eslint-plugin-import/node_modules/semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "dev": true, - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/eslint-plugin-jsx-a11y": { - "version": "6.8.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-6.8.0.tgz", - "integrity": "sha512-Hdh937BS3KdwwbBaKd5+PLCOmYY6U4f2h9Z2ktwtNKvIdIEu137rjYbcb9ApSbVJfWxANNuiKTD/9tOKjK9qOA==", - "dev": true, - "dependencies": { - "@babel/runtime": "^7.23.2", - "aria-query": "^5.3.0", - "array-includes": "^3.1.7", - "array.prototype.flatmap": "^1.3.2", - "ast-types-flow": "^0.0.8", - "axe-core": "=4.7.0", - "axobject-query": "^3.2.1", - "damerau-levenshtein": "^1.0.8", - "emoji-regex": "^9.2.2", - "es-iterator-helpers": "^1.0.15", - "hasown": "^2.0.0", - "jsx-ast-utils": "^3.3.5", - "language-tags": "^1.0.9", - "minimatch": "^3.1.2", - "object.entries": "^1.1.7", - "object.fromentries": "^2.0.7" - }, - "engines": { - "node": ">=4.0" - }, - "peerDependencies": { - "eslint": "^3 || ^4 || ^5 || ^6 || ^7 || ^8" - } - }, - "node_modules/eslint-plugin-jsx-a11y/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, - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/eslint-plugin-jsx-a11y/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, - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/eslint-plugin-react": { - "version": "7.33.2", - "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.33.2.tgz", - "integrity": "sha512-73QQMKALArI8/7xGLNI/3LylrEYrlKZSb5C9+q3OtOewTnMQi5cT+aE9E41sLCmli3I9PGGmD1yiZydyo4FEPw==", - "dev": true, - "dependencies": { - "array-includes": "^3.1.6", - "array.prototype.flatmap": "^1.3.1", - "array.prototype.tosorted": "^1.1.1", - "doctrine": "^2.1.0", - "es-iterator-helpers": "^1.0.12", - "estraverse": "^5.3.0", - "jsx-ast-utils": "^2.4.1 || ^3.0.0", - "minimatch": "^3.1.2", - "object.entries": "^1.1.6", - "object.fromentries": "^2.0.6", - "object.hasown": "^1.1.2", - "object.values": "^1.1.6", - "prop-types": "^15.8.1", - "resolve": "^2.0.0-next.4", - "semver": "^6.3.1", - "string.prototype.matchall": "^4.0.8" - }, - "engines": { - "node": ">=4" - }, - "peerDependencies": { - "eslint": "^3 || ^4 || ^5 || ^6 || ^7 || ^8" - } - }, - "node_modules/eslint-plugin-react-hooks": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-4.6.0.tgz", - "integrity": "sha512-oFc7Itz9Qxh2x4gNHStv3BqJq54ExXmfC+a1NjAta66IAN87Wu0R/QArgIS9qKzX3dXKPI9H5crl9QchNMY9+g==", - "dev": true, - "peer": true, - "engines": { - "node": ">=10" - }, - "peerDependencies": { - "eslint": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0" - } - }, - "node_modules/eslint-plugin-react/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, - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/eslint-plugin-react/node_modules/doctrine": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", - "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", - "dev": true, - "dependencies": { - "esutils": "^2.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/eslint-plugin-react/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, - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/eslint-plugin-react/node_modules/resolve": { - "version": "2.0.0-next.5", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-2.0.0-next.5.tgz", - "integrity": "sha512-U7WjGVG9sH8tvjW5SmGbQuui75FiyjAX72HX15DwBBwF9dNiQZRQAg9nnPhYy+TUnE0+VcrttuvNI8oSxZcocA==", - "dev": true, - "dependencies": { - "is-core-module": "^2.13.0", - "path-parse": "^1.0.7", - "supports-preserve-symlinks-flag": "^1.0.0" - }, - "bin": { - "resolve": "bin/resolve" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/eslint-plugin-react/node_modules/semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "dev": true, - "bin": { - "semver": "bin/semver.js" - } - }, "node_modules/eslint-scope": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", - "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", + "version": "7.2.2", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz", + "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==", "dev": true, "dependencies": { "esrecurse": "^4.3.0", - "estraverse": "^4.1.1" - }, - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/eslint-scope/node_modules/estraverse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", - "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", - "dev": true, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/eslint-utils": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-2.1.0.tgz", - "integrity": "sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==", - "dev": true, - "dependencies": { - "eslint-visitor-keys": "^1.1.0" + "estraverse": "^5.2.0" }, "engines": { - "node": ">=6" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" }, "funding": { - "url": "https://github.com/sponsors/mysticatea" - } - }, - "node_modules/eslint-utils/node_modules/eslint-visitor-keys": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", - "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", - "dev": true, - "engines": { - "node": ">=4" + "url": "https://opencollective.com/eslint" } }, "node_modules/eslint-visitor-keys": { @@ -4440,6 +3745,15 @@ "url": "https://opencollective.com/eslint" } }, + "node_modules/eslint/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==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, "node_modules/eslint/node_modules/brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", @@ -4450,22 +3764,16 @@ "concat-map": "0.0.1" } }, - "node_modules/eslint/node_modules/eslint-visitor-keys": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", - "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", - "dev": true, - "engines": { - "node": ">=10" - } - }, - "node_modules/eslint/node_modules/ignore": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", - "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", + "node_modules/eslint/node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", "dev": true, + "dependencies": { + "is-glob": "^4.0.3" + }, "engines": { - "node": ">= 4" + "node": ">=10.13.0" } }, "node_modules/eslint/node_modules/minimatch": { @@ -4481,39 +3789,20 @@ } }, "node_modules/espree": { - "version": "7.3.1", - "resolved": "https://registry.npmjs.org/espree/-/espree-7.3.1.tgz", - "integrity": "sha512-v3JCNCE64umkFpmkFGqzVKsOT0tN1Zr+ueqLZfpV1Ob8e+CEgPWa+OxCoGH3tnhimMKIaBm4m/vaRpJ/krRz2g==", + "version": "9.6.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", + "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==", "dev": true, "dependencies": { - "acorn": "^7.4.0", - "acorn-jsx": "^5.3.1", - "eslint-visitor-keys": "^1.3.0" + "acorn": "^8.9.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^3.4.1" }, "engines": { - "node": "^10.12.0 || >=12.0.0" - } - }, - "node_modules/espree/node_modules/eslint-visitor-keys": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", - "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/esprima": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", - "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", - "dev": true, - "bin": { - "esparse": "bin/esparse.js", - "esvalidate": "bin/esvalidate.js" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" }, - "engines": { - "node": ">=4" + "funding": { + "url": "https://opencollective.com/eslint" } }, "node_modules/esquery": { @@ -4571,6 +3860,12 @@ "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" }, + "node_modules/fast-diff": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.3.0.tgz", + "integrity": "sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw==", + "dev": true + }, "node_modules/fast-glob": { "version": "3.3.2", "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz", @@ -4658,6 +3953,22 @@ "node": ">=8" } }, + "node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/flat-cache": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.2.0.tgz", @@ -4673,9 +3984,9 @@ } }, "node_modules/flatted": { - "version": "3.2.9", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.9.tgz", - "integrity": "sha512-36yxDn5H7OFZQla0/jFJmbIKTdZAQHngCedGxiMmpNfEZM0sdEeT+WczLQrjK6D7o2aiyLYDnkw0R3JK0Qv1RQ==", + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.1.tgz", + "integrity": "sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==", "dev": true }, "node_modules/fn.name": { @@ -4683,15 +3994,6 @@ "resolved": "https://registry.npmjs.org/fn.name/-/fn.name-1.1.0.tgz", "integrity": "sha512-GRnmB5gPyJpAhTQdSZTSp9uaPSvl09KoYcMQtsB9rQoOmzs9dH6ffeccH+Z+cv6P68Hu5bC6JjRh4Ah/mHSNRw==" }, - "node_modules/for-each": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", - "integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==", - "dev": true, - "dependencies": { - "is-callable": "^1.1.3" - } - }, "node_modules/form-data": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", @@ -4711,83 +4013,11 @@ "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", "dev": true }, - "node_modules/function-bind": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", - "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", - "dev": true, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/function.prototype.name": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.6.tgz", - "integrity": "sha512-Z5kx79swU5P27WEayXM1tBi5Ze/lbIyiNgU3qyXUOf9b2rgXYyF9Dy9Cx+IQv/Lc8WCG6L82zwUPpSS9hGehIg==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1", - "functions-have-names": "^1.2.3" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/functional-red-black-tree": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", - "integrity": "sha512-dsKNQNdj6xA3T+QlADDA7mOSlX0qiMINjn0cgr+eGHGsbSHzTabcIogz2+p/iqP1Xs6EP/sS2SbqH+brGTbq0g==", - "dev": true - }, - "node_modules/functions-have-names": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", - "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==", - "dev": true, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/get-intrinsic": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.2.tgz", - "integrity": "sha512-0gSo4ml/0j98Y3lngkFEot/zhiCeWsbYIlZ+uZOVgzLyLaUw7wxUL+nCTP0XJvJg1AXulJRI3UJi8GsbDuxdGA==", - "dev": true, - "dependencies": { - "function-bind": "^1.1.2", - "has-proto": "^1.0.1", - "has-symbols": "^1.0.3", - "hasown": "^2.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/get-symbol-description": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.0.tgz", - "integrity": "sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.1.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/glob": { "version": "7.2.3", "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Glob versions prior to v9 are no longer supported", "dev": true, "dependencies": { "fs.realpath": "^1.0.0", @@ -4853,21 +4083,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/globalthis": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.3.tgz", - "integrity": "sha512-sFdI5LyBiNTHjRd7cGPWapiHWMOXKyuBNX/cWJ3NfzrZQVa8GI/8cofCl74AOVqq9W5kNmguTIzJ/1s2gyI9wA==", - "dev": true, - "dependencies": { - "define-properties": "^1.1.3" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/globby": { "version": "11.1.0", "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", @@ -4888,33 +4103,12 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/gopd": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", - "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", - "dev": true, - "dependencies": { - "get-intrinsic": "^1.1.3" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/graphemer": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", "dev": true }, - "node_modules/has-bigints": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz", - "integrity": "sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==", - "dev": true, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", @@ -4924,69 +4118,6 @@ "node": ">=8" } }, - "node_modules/has-property-descriptors": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.1.tgz", - "integrity": "sha512-VsX8eaIewvas0xnvinAe9bw4WfIeODpGYikiWYLH+dma0Jw6KHYqWiWfhQlgOVK8D6PvjubK5Uc4P0iIhIcNVg==", - "dev": true, - "dependencies": { - "get-intrinsic": "^1.2.2" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-proto": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.1.tgz", - "integrity": "sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==", - "dev": true, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-symbols": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", - "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", - "dev": true, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-tostringtag": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz", - "integrity": "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==", - "dev": true, - "dependencies": { - "has-symbols": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/hasown": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.0.tgz", - "integrity": "sha512-vUptKVTpIJhcczKBbgnS+RtcuYMB8+oNzPK2/Hp3hanz8JmpATdmmgLgSaadVREkDm+e2giHwY3ZRkyjSIDDFA==", - "dev": true, - "dependencies": { - "function-bind": "^1.1.2" - }, - "engines": { - "node": ">= 0.4" - } - }, "node_modules/html-encoding-sniffer": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-4.0.0.tgz", @@ -5061,9 +4192,9 @@ ] }, "node_modules/ignore": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.0.tgz", - "integrity": "sha512-g7dmpshy+gD7mh88OC9NwSGTKoc3kyLAZQRU1mt53Aw/vnvfXnbC+F/7F7QoYVKbV+KNvJx8wArewKy1vXMtlg==", + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.1.tgz", + "integrity": "sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw==", "dev": true, "engines": { "node": ">= 4" @@ -5104,6 +4235,7 @@ "version": "1.0.6", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", "dev": true, "dependencies": { "once": "^1.3.0", @@ -5115,71 +4247,16 @@ "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" }, - "node_modules/internal-slot": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.6.tgz", - "integrity": "sha512-Xj6dv+PsbtwyPpEflsejS+oIZxmMlV44zAhG479uYu89MsjcYOhCFnNyKrkJrihbsiasQyY0afoCl/9BLR65bg==", - "dev": true, - "dependencies": { - "get-intrinsic": "^1.2.2", - "hasown": "^2.0.0", - "side-channel": "^1.0.4" - }, - "engines": { - "node": ">= 0.4" - } - }, "node_modules/ip": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ip/-/ip-2.0.0.tgz", "integrity": "sha512-WKa+XuLG1A1R0UWhl2+1XQSi+fZWMsYKffMZTTYsiZaUD8k2yDAj5atimTUD2TZkyCkNEeYE5NhFZmupOGtjYQ==" }, - "node_modules/is-array-buffer": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.2.tgz", - "integrity": "sha512-y+FyyR/w8vfIRq4eQcM1EYgSTnmHXPqaF+IgzgraytCFq5Xh8lllDVmAZolPJiZttZLeFSINPYMaEJ7/vWUa1w==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.2.0", - "is-typed-array": "^1.1.10" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/is-arrayish": { "version": "0.3.2", "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz", "integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==" }, - "node_modules/is-async-function": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-async-function/-/is-async-function-2.0.0.tgz", - "integrity": "sha512-Y1JXKrfykRJGdlDwdKlLpLyMIiWqWvuSd17TvZk68PLAOGOoF4Xyav1z0Xhoi+gCYjZVeC5SI+hYFOfvXmGRCA==", - "dev": true, - "dependencies": { - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-bigint": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz", - "integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==", - "dev": true, - "dependencies": { - "has-bigints": "^1.0.1" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/is-binary-path": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", @@ -5192,61 +4269,6 @@ "node": ">=8" } }, - "node_modules/is-boolean-object": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz", - "integrity": "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-callable": { - "version": "1.2.7", - "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", - "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", - "dev": true, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-core-module": { - "version": "2.13.1", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.1.tgz", - "integrity": "sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==", - "dev": true, - "dependencies": { - "hasown": "^2.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-date-object": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz", - "integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==", - "dev": true, - "dependencies": { - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/is-extglob": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", @@ -5256,42 +4278,6 @@ "node": ">=0.10.0" } }, - "node_modules/is-finalizationregistry": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-finalizationregistry/-/is-finalizationregistry-1.0.2.tgz", - "integrity": "sha512-0by5vtUJs8iFQb5TYUHHPudOR+qXYIMKtiUzvLIZITZUjknFmziyBJuLhVRc+Ds0dREFlskDNJKYIdIzu/9pfw==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/is-generator-function": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.0.10.tgz", - "integrity": "sha512-jsEjy9l3yiXEQ+PsXdmBwEPcOxaXWLspKdplFUVI9vq1iZgIekeC0L167qeu86czQaxed3q/Uzuw0swL0irL8A==", - "dev": true, - "dependencies": { - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/is-glob": { "version": "4.0.3", "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", @@ -5304,27 +4290,6 @@ "node": ">=0.10.0" } }, - "node_modules/is-map": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.2.tgz", - "integrity": "sha512-cOZFQQozTha1f4MxLFzlgKYPTyj26picdZTx82hbc/Xf4K/tZOOXSCkMvU4pKioRXGDLJRn0GM7Upe7kR721yg==", - "dev": true, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-negative-zero": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.2.tgz", - "integrity": "sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA==", - "dev": true, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/is-number": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", @@ -5334,192 +4299,44 @@ "node": ">=0.12.0" } }, - "node_modules/is-number-object": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.7.tgz", - "integrity": "sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==", - "dev": true, - "dependencies": { - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-potential-custom-element-name": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz", - "integrity": "sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==" - }, - "node_modules/is-regex": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", - "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-set": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/is-set/-/is-set-2.0.2.tgz", - "integrity": "sha512-+2cnTEZeY5z/iXGbLhPrOAaK/Mau5k5eXq9j14CpRTftq0pAJu2MwVRSZhyZWBzx3o6X795Lz6Bpb6R0GKf37g==", - "dev": true, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-shared-array-buffer": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.2.tgz", - "integrity": "sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-stream": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", - "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/is-string": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", - "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==", - "dev": true, - "dependencies": { - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-symbol": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz", - "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==", - "dev": true, - "dependencies": { - "has-symbols": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-typed-array": { - "version": "1.1.12", - "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.12.tgz", - "integrity": "sha512-Z14TF2JNG8Lss5/HMqt0//T9JeHXttXy5pH/DBU4vi98ozO2btxzq9MwYDZYnKwU8nRsz/+GVFVRDq3DkVuSPg==", - "dev": true, - "dependencies": { - "which-typed-array": "^1.1.11" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-weakmap": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-weakmap/-/is-weakmap-2.0.1.tgz", - "integrity": "sha512-NSBR4kH5oVj1Uwvv970ruUkCV7O1mzgVFO4/rev2cLRda9Tm9HrL70ZPut4rOHgY0FNrUu9BCbXA2sdQ+x0chA==", - "dev": true, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-weakref": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz", - "integrity": "sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-weakset": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/is-weakset/-/is-weakset-2.0.2.tgz", - "integrity": "sha512-t2yVvttHkQktwnNNmBQ98AhENLdPUTDTE21uPqAQ0ARwQfGeQKRVS0NNurH7bTf7RrvcVn1OOge45CnBeHCSmg==", + "node_modules/is-path-inside": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", + "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.1.1" + "engines": { + "node": ">=8" + } + }, + "node_modules/is-potential-custom-element-name": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz", + "integrity": "sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==" + }, + "node_modules/is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "engines": { + "node": ">=8" }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/isarray": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", - "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", - "dev": true - }, "node_modules/isexe": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", "dev": true }, - "node_modules/iterator.prototype": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/iterator.prototype/-/iterator.prototype-1.1.2.tgz", - "integrity": "sha512-DR33HMMr8EzwuRL8Y9D3u2BMj8+RqSE850jfGu59kS7tbmPLzGkZmVSfyCFSDxuZiEY6Rzt3T2NA/qU+NwVj1w==", - "dev": true, - "dependencies": { - "define-properties": "^1.2.1", - "get-intrinsic": "^1.2.1", - "has-symbols": "^1.0.3", - "reflect.getprototypeof": "^1.0.4", - "set-function-name": "^2.0.1" - } - }, - "node_modules/js-tokens": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", - "dev": true - }, "node_modules/js-yaml": { - "version": "3.14.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", - "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", "dev": true, "dependencies": { - "argparse": "^1.0.7", - "esprima": "^4.0.0" + "argparse": "^2.0.1" }, "bin": { "js-yaml": "bin/js-yaml.js" @@ -5636,21 +4453,6 @@ "node": ">=6" } }, - "node_modules/jsx-ast-utils": { - "version": "3.3.5", - "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.3.5.tgz", - "integrity": "sha512-ZZow9HBI5O6EPgSJLUb8n2NKgmVWTwCvHGwFuJlMjvLFqlGG6pjirPhtdsseaLZjSibD8eegzmYpUZwoIlj2cQ==", - "dev": true, - "dependencies": { - "array-includes": "^3.1.6", - "array.prototype.flat": "^1.3.1", - "object.assign": "^4.1.4", - "object.values": "^1.1.6" - }, - "engines": { - "node": ">=4.0" - } - }, "node_modules/kareem": { "version": "2.5.1", "resolved": "https://registry.npmjs.org/kareem/-/kareem-2.5.1.tgz", @@ -5673,24 +4475,6 @@ "resolved": "https://registry.npmjs.org/kuler/-/kuler-2.0.0.tgz", "integrity": "sha512-Xq9nH7KlWZmXAtodXDDRE7vs6DU1gTU8zYDHDiWLSip45Egwq3plLHzPn27NgvzL2r1LMPC1vdqh98sQxtqj4A==" }, - "node_modules/language-subtag-registry": { - "version": "0.3.22", - "resolved": "https://registry.npmjs.org/language-subtag-registry/-/language-subtag-registry-0.3.22.tgz", - "integrity": "sha512-tN0MCzyWnoz/4nHS6uxdlFWoUZT7ABptwKPQ52Ea7URk6vll88bWBVhodtnlfEuCcKWNGoc+uGbw1cwa9IKh/w==", - "dev": true - }, - "node_modules/language-tags": { - "version": "1.0.9", - "resolved": "https://registry.npmjs.org/language-tags/-/language-tags-1.0.9.tgz", - "integrity": "sha512-MbjN408fEndfiQXbFQ1vnd+1NoLDsnQW41410oQBXiyXDMYH5z505juWa4KUE1LqxRC7DgOgZDbKLxHIwm27hA==", - "dev": true, - "dependencies": { - "language-subtag-registry": "^0.3.20" - }, - "engines": { - "node": ">=0.10" - } - }, "node_modules/levn": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", @@ -5704,6 +4488,21 @@ "node": ">= 0.8.0" } }, + "node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/lodash": { "version": "4.17.21", "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", @@ -5720,12 +4519,6 @@ "resolved": "https://registry.npmjs.org/lodash.snakecase/-/lodash.snakecase-4.1.1.tgz", "integrity": "sha512-QZ1d4xoBHYUeuouhEq3lk3Uq7ldgyFXGBhg04+oRLnIz8o9T65Eh+8YdroUwn846zchkA9yDsDl5CVVaV2nqYw==" }, - "node_modules/lodash.truncate": { - "version": "4.4.2", - "resolved": "https://registry.npmjs.org/lodash.truncate/-/lodash.truncate-4.4.2.tgz", - "integrity": "sha512-jttmRe7bRse52OsWIMDLaXxWqRAmtIUccAQ3garviCqJjafXOfNMO0yMfNpdD6zbGaTU0P5Nz7e7gAT6cKmJRw==", - "dev": true - }, "node_modules/logform": { "version": "2.6.0", "resolved": "https://registry.npmjs.org/logform/-/logform-2.6.0.tgz", @@ -5742,30 +4535,6 @@ "node": ">= 12.0.0" } }, - "node_modules/loose-envify": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", - "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", - "dev": true, - "dependencies": { - "js-tokens": "^3.0.0 || ^4.0.0" - }, - "bin": { - "loose-envify": "cli.js" - } - }, - "node_modules/lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "dev": true, - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/luxon": { "version": "3.4.4", "resolved": "https://registry.npmjs.org/luxon/-/luxon-3.4.4.tgz", @@ -5851,15 +4620,6 @@ "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/minimist": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", - "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", - "dev": true, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/moment": { "version": "2.30.1", "resolved": "https://registry.npmjs.org/moment/-/moment-2.30.1.tgz", @@ -6141,124 +4901,6 @@ "resolved": "https://registry.npmjs.org/numbered/-/numbered-1.1.0.tgz", "integrity": "sha512-pv/ue2Odr7IfYOO0byC1KgBI10wo5YDauLhxY6/saNzAdAs0r1SotGCPzzCLNPL0xtrAwWRialLu23AAu9xO1g==" }, - "node_modules/object-assign": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/object-inspect": { - "version": "1.13.1", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.1.tgz", - "integrity": "sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==", - "dev": true, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/object-keys": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", - "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", - "dev": true, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/object.assign": { - "version": "4.1.5", - "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.5.tgz", - "integrity": "sha512-byy+U7gp+FVwmyzKPYhW2h5l3crpmGsxl7X2s8y43IgxvG4g3QZ6CffDtsNQy1WsmZpQbO+ybo0AlW7TY6DcBQ==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.5", - "define-properties": "^1.2.1", - "has-symbols": "^1.0.3", - "object-keys": "^1.1.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/object.entries": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.7.tgz", - "integrity": "sha512-jCBs/0plmPsOnrKAfFQXRG2NFjlhZgjjcBLSmTnEhU8U6vVTsVe8ANeQJCHTl3gSsI4J+0emOoCgoKlmQPMgmA==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/object.fromentries": { - "version": "2.0.7", - "resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.7.tgz", - "integrity": "sha512-UPbPHML6sL8PI/mOqPwsH4G6iyXcCGzLin8KvEPenOZN5lpCNBZZQ+V62vdjB1mQHrmqGQt5/OJzemUA+KJmEA==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/object.groupby": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/object.groupby/-/object.groupby-1.0.1.tgz", - "integrity": "sha512-HqaQtqLnp/8Bn4GL16cj+CUYbnpe1bh0TtEaWvybszDG4tgxCJuRpV8VGuvNaI1fAnI4lUJzDG55MXcOH4JZcQ==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1", - "get-intrinsic": "^1.2.1" - } - }, - "node_modules/object.hasown": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/object.hasown/-/object.hasown-1.1.3.tgz", - "integrity": "sha512-fFI4VcYpRHvSLXxP7yiZOMAd331cPfd2p7PFDVbgUsYOfCT3tICVqXWngbjr4m49OvsBwUBQ6O2uQoJvy3RexA==", - "dev": true, - "dependencies": { - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/object.values": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.7.tgz", - "integrity": "sha512-aU6xnDFYT3x17e/f0IiiwlGPTy2jzMySGfUB4fq6z7CV8l85CWHDk5ErhyhpfDHhrOMwGFhSQkhMGHaIotA6Ng==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/once": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", @@ -6292,6 +4934,36 @@ "node": ">= 0.8.0" } }, + "node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/parent-module": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", @@ -6315,6 +4987,15 @@ "url": "https://github.com/inikulin/parse5?sponsor=1" } }, + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "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", @@ -6333,12 +5014,6 @@ "node": ">=8" } }, - "node_modules/path-parse": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", - "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", - "dev": true - }, "node_modules/path-type": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", @@ -6369,24 +5044,31 @@ "node": ">= 0.8.0" } }, - "node_modules/progress": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", - "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", + "node_modules/prettier": { + "version": "3.2.5", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.2.5.tgz", + "integrity": "sha512-3/GWa9aOC0YeD7LUfvOG2NiDyhOWRvt1k+rcKhOuYnMY24iiCphgneUfJDyFXd6rZCAnuLBv6UeAULtrhT/F4A==", "dev": true, + "bin": { + "prettier": "bin/prettier.cjs" + }, "engines": { - "node": ">=0.4.0" + "node": ">=14" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" } }, - "node_modules/prop-types": { - "version": "15.8.1", - "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", - "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", + "node_modules/prettier-linter-helpers": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz", + "integrity": "sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==", "dev": true, "dependencies": { - "loose-envify": "^1.4.0", - "object-assign": "^4.1.1", - "react-is": "^16.13.1" + "fast-diff": "^1.1.2" + }, + "engines": { + "node": ">=6.0.0" } }, "node_modules/psl": { @@ -6433,12 +5115,6 @@ } ] }, - "node_modules/react-is": { - "version": "16.13.1", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", - "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", - "dev": true - }, "node_modules/readable-stream": { "version": "3.6.2", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", @@ -6464,61 +5140,6 @@ "node": ">=8.10.0" } }, - "node_modules/reflect.getprototypeof": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/reflect.getprototypeof/-/reflect.getprototypeof-1.0.4.tgz", - "integrity": "sha512-ECkTw8TmJwW60lOTR+ZkODISW6RQ8+2CL3COqtiJKLd6MmB45hN51HprHFziKLGkAuTGQhBb91V8cy+KHlaCjw==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1", - "get-intrinsic": "^1.2.1", - "globalthis": "^1.0.3", - "which-builtin-type": "^1.1.3" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/regenerator-runtime": { - "version": "0.14.1", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz", - "integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==", - "dev": true - }, - "node_modules/regexp.prototype.flags": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.1.tgz", - "integrity": "sha512-sy6TXMN+hnP/wMy+ISxg3krXx7BAtWVO4UouuCN/ziM9UEne0euamVNafDfvC83bRNr95y0V5iijeDQFUNpvrg==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "set-function-name": "^2.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/regexpp": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz", - "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==", - "dev": true, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/mysticatea" - } - }, "node_modules/require-from-string": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", @@ -6532,23 +5153,6 @@ "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==" }, - "node_modules/resolve": { - "version": "1.22.8", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", - "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==", - "dev": true, - "dependencies": { - "is-core-module": "^2.13.0", - "path-parse": "^1.0.7", - "supports-preserve-symlinks-flag": "^1.0.0" - }, - "bin": { - "resolve": "bin/resolve" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/resolve-from": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", @@ -6572,6 +5176,7 @@ "version": "3.0.2", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "deprecated": "Rimraf versions prior to v4 are no longer supported", "dev": true, "dependencies": { "glob": "^7.1.3" @@ -6611,24 +5216,6 @@ "queue-microtask": "^1.2.2" } }, - "node_modules/safe-array-concat": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.0.1.tgz", - "integrity": "sha512-6XbUAseYE2KtOuGueyeobCySj9L4+66Tn6KQMOPQJrAJEowYKW/YR/MGJZl7FdydUdaFu4LYyDZjxf4/Nmo23Q==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.2.1", - "has-symbols": "^1.0.3", - "isarray": "^2.0.5" - }, - "engines": { - "node": ">=0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/safe-buffer": { "version": "5.2.1", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", @@ -6648,23 +5235,6 @@ } ] }, - "node_modules/safe-regex-test": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.0.1.tgz", - "integrity": "sha512-Y5NejJTTliTyY4H7sipGqY+RX5P87i3F7c4Rcepy72nq+mNLhIsD0W4c7kEmduMDQCSqtPsXPlSTsFhh2LQv+g==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.5", - "get-intrinsic": "^1.2.2", - "is-regex": "^1.1.4" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/safe-stable-stringify": { "version": "2.4.3", "resolved": "https://registry.npmjs.org/safe-stable-stringify/-/safe-stable-stringify-2.4.3.tgz", @@ -6680,57 +5250,25 @@ }, "node_modules/saxes": { "version": "6.0.0", - "resolved": "https://registry.npmjs.org/saxes/-/saxes-6.0.0.tgz", - "integrity": "sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA==", - "dependencies": { - "xmlchars": "^2.2.0" - }, - "engines": { - "node": ">=v12.22.7" - } - }, - "node_modules/semver": { - "version": "7.5.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", - "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", - "dev": true, - "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/set-function-length": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.1.1.tgz", - "integrity": "sha512-VoaqjbBJKiWtg4yRcKBQ7g7wnGnLV3M8oLvVWwOk2PdYY6PEFegR1vezXR0tw6fZGF9csVakIRjrJiy2veSBFQ==", - "dev": true, + "resolved": "https://registry.npmjs.org/saxes/-/saxes-6.0.0.tgz", + "integrity": "sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA==", "dependencies": { - "define-data-property": "^1.1.1", - "get-intrinsic": "^1.2.1", - "gopd": "^1.0.1", - "has-property-descriptors": "^1.0.0" + "xmlchars": "^2.2.0" }, "engines": { - "node": ">= 0.4" + "node": ">=v12.22.7" } }, - "node_modules/set-function-name": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/set-function-name/-/set-function-name-2.0.1.tgz", - "integrity": "sha512-tMNCiqYVkXIZgc2Hnoy2IvC/f8ezc5koaRFkCjrpWzGpCd3qbZXPzVy9MAZzK1ch/X0jvSkojys3oqJN0qCmdA==", + "node_modules/semver": { + "version": "7.6.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.2.tgz", + "integrity": "sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w==", "dev": true, - "dependencies": { - "define-data-property": "^1.0.1", - "functions-have-names": "^1.2.3", - "has-property-descriptors": "^1.0.0" + "bin": { + "semver": "bin/semver.js" }, "engines": { - "node": ">= 0.4" + "node": ">=10" } }, "node_modules/shebang-command": { @@ -6754,20 +5292,6 @@ "node": ">=8" } }, - "node_modules/side-channel": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", - "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.0", - "get-intrinsic": "^1.0.2", - "object-inspect": "^1.9.0" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/sift": { "version": "16.0.1", "resolved": "https://registry.npmjs.org/sift/-/sift-16.0.1.tgz", @@ -6802,23 +5326,6 @@ "node": ">=8" } }, - "node_modules/slice-ansi": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz", - "integrity": "sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.0.0", - "astral-regex": "^2.0.0", - "is-fullwidth-code-point": "^3.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/slice-ansi?sponsor=1" - } - }, "node_modules/smart-buffer": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz", @@ -6857,12 +5364,6 @@ "memory-pager": "^1.0.2" } }, - "node_modules/sprintf-js": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", - "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", - "dev": true - }, "node_modules/stack-trace": { "version": "0.0.10", "resolved": "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.10.tgz", @@ -6888,91 +5389,6 @@ "safe-buffer": "~5.2.0" } }, - "node_modules/string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dev": true, - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/string-width/node_modules/emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true - }, - "node_modules/string.prototype.matchall": { - "version": "4.0.10", - "resolved": "https://registry.npmjs.org/string.prototype.matchall/-/string.prototype.matchall-4.0.10.tgz", - "integrity": "sha512-rGXbGmOEosIQi6Qva94HUjgPs9vKW+dkG7Y8Q5O2OYkWL6wFaTRZO8zM4mhP94uX55wgyrXzfS2aGtGzUL7EJQ==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1", - "get-intrinsic": "^1.2.1", - "has-symbols": "^1.0.3", - "internal-slot": "^1.0.5", - "regexp.prototype.flags": "^1.5.0", - "set-function-name": "^2.0.0", - "side-channel": "^1.0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/string.prototype.trim": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.8.tgz", - "integrity": "sha512-lfjY4HcixfQXOfaqCvcBuOIapyaroTXhbkfJN3gcB1OtyupngWK4sEET9Knd0cXd28kTUqu/kHoV4HKSJdnjiQ==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/string.prototype.trimend": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.7.tgz", - "integrity": "sha512-Ni79DqeB72ZFq1uH/L6zJ+DKZTkOtPIHovb3YZHQViE+HDouuU4mBrLOLDn5Dde3RF8qw5qVETEjhu9locMLvA==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/string.prototype.trimstart": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.7.tgz", - "integrity": "sha512-NGhtDFu3jCEm7B4Fy0DpLewdJQOZcQ0rGbwQ/+stjnrp2i+rlKeCvos9hOIeCmqwratM47OBxY7uFZzjxHXmrg==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/strip-ansi": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", @@ -6985,15 +5401,6 @@ "node": ">=8" } }, - "node_modules/strip-bom": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", - "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", - "dev": true, - "engines": { - "node": ">=4" - } - }, "node_modules/strip-json-comments": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", @@ -7023,61 +5430,27 @@ "node": ">=8" } }, - "node_modules/supports-preserve-symlinks-flag": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", - "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", - "dev": true, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/symbol-tree": { "version": "3.2.4", "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz", "integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==" }, - "node_modules/table": { - "version": "6.8.1", - "resolved": "https://registry.npmjs.org/table/-/table-6.8.1.tgz", - "integrity": "sha512-Y4X9zqrCftUhMeH2EptSSERdVKt/nEdijTOacGD/97EKjhQ/Qs8RTlEGABSJNNN8lac9kheH+af7yAkEWlgneA==", + "node_modules/synckit": { + "version": "0.8.8", + "resolved": "https://registry.npmjs.org/synckit/-/synckit-0.8.8.tgz", + "integrity": "sha512-HwOKAP7Wc5aRGYdKH+dw0PRRpbO841v2DENBtjnR5HFWoiNByAl7vrx3p0G/rCyYXQsrxqtX48TImFtPcIHSpQ==", "dev": true, "dependencies": { - "ajv": "^8.0.1", - "lodash.truncate": "^4.4.2", - "slice-ansi": "^4.0.0", - "string-width": "^4.2.3", - "strip-ansi": "^6.0.1" + "@pkgr/core": "^0.1.0", + "tslib": "^2.6.2" }, "engines": { - "node": ">=10.0.0" - } - }, - "node_modules/table/node_modules/ajv": { - "version": "8.12.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", - "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", - "dev": true, - "dependencies": { - "fast-deep-equal": "^3.1.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2", - "uri-js": "^4.2.2" + "node": "^14.18.0 || >=16.0.0" }, "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" + "url": "https://opencollective.com/unts" } }, - "node_modules/table/node_modules/json-schema-traverse": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", - "dev": true - }, "node_modules/text-hex": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/text-hex/-/text-hex-1.0.0.tgz", @@ -7147,12 +5520,12 @@ } }, "node_modules/ts-api-utils": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.0.3.tgz", - "integrity": "sha512-wNMeqtMz5NtwpT/UZGY5alT+VoKdSsOOP/kqHFcUW1P/VRhH2wJ48+DN2WwUliNbQ976ETwDL0Ifd2VVvgonvg==", + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.3.0.tgz", + "integrity": "sha512-UQMIo7pb8WRomKR1/+MFVLTroIvDVtMX3K6OUir8ynLyzB8Jeriont2bTAtmNPa1ekAgN7YPDyf6V+ygrdU+eQ==", "dev": true, "engines": { - "node": ">=16.13.0" + "node": ">=16" }, "peerDependencies": { "typescript": ">=4.2.0" @@ -7206,42 +5579,6 @@ } } }, - "node_modules/ts-node/node_modules/acorn": { - "version": "8.11.3", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.3.tgz", - "integrity": "sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==", - "dev": true, - "bin": { - "acorn": "bin/acorn" - }, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/tsconfig-paths": { - "version": "3.15.0", - "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.15.0.tgz", - "integrity": "sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg==", - "dev": true, - "dependencies": { - "@types/json5": "^0.0.29", - "json5": "^1.0.2", - "minimist": "^1.2.6", - "strip-bom": "^3.0.0" - } - }, - "node_modules/tsconfig-paths/node_modules/json5": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz", - "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==", - "dev": true, - "dependencies": { - "minimist": "^1.2.0" - }, - "bin": { - "json5": "lib/cli.js" - } - }, "node_modules/tslib": { "version": "2.6.2", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", @@ -7271,97 +5608,194 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/typed-array-buffer": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.0.tgz", - "integrity": "sha512-Y8KTSIglk9OZEr8zywiIHG/kmQ7KWyjseXs1CbSo8vC42w7hg2HgYTxSWwP0+is7bWDc1H+Fo026CpHFwm8tkw==", + "node_modules/typescript": { + "version": "5.4.5", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.4.5.tgz", + "integrity": "sha512-vcI4UpRgg81oIRUFwR0WSIHKt11nJ7SAVlYNIu+QpqeyXP+gpQJy/Z4+F0aGxSE4MqwjyXvW/TzgkLAx2AGHwQ==", + "dev": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/typescript-eslint": { + "version": "7.11.0", + "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-7.11.0.tgz", + "integrity": "sha512-ZKe3yHF/IS/kCUE4CGE3UgtK+Q7yRk1e9kwEI0rqm9XxMTd9P1eHe0LVVtrZ3oFuIQ2unJ9Xn0vTsLApzJ3aPw==", "dev": true, "dependencies": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.2.1", - "is-typed-array": "^1.1.10" + "@typescript-eslint/eslint-plugin": "7.11.0", + "@typescript-eslint/parser": "7.11.0", + "@typescript-eslint/utils": "7.11.0" }, "engines": { - "node": ">= 0.4" + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.56.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } } }, - "node_modules/typed-array-byte-length": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/typed-array-byte-length/-/typed-array-byte-length-1.0.0.tgz", - "integrity": "sha512-Or/+kvLxNpeQ9DtSydonMxCx+9ZXOswtwJn17SNLvhptaXYDJvkFFP5zbfU/uLmvnBJlI4yrnXRxpdWH/M5tNA==", + "node_modules/typescript-eslint/node_modules/@typescript-eslint/eslint-plugin": { + "version": "7.11.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.11.0.tgz", + "integrity": "sha512-P+qEahbgeHW4JQ/87FuItjBj8O3MYv5gELDzr8QaQ7fsll1gSMTYb6j87MYyxwf3DtD7uGFB9ShwgmCJB5KmaQ==", "dev": true, "dependencies": { - "call-bind": "^1.0.2", - "for-each": "^0.3.3", - "has-proto": "^1.0.1", - "is-typed-array": "^1.1.10" + "@eslint-community/regexpp": "^4.10.0", + "@typescript-eslint/scope-manager": "7.11.0", + "@typescript-eslint/type-utils": "7.11.0", + "@typescript-eslint/utils": "7.11.0", + "@typescript-eslint/visitor-keys": "7.11.0", + "graphemer": "^1.4.0", + "ignore": "^5.3.1", + "natural-compare": "^1.4.0", + "ts-api-utils": "^1.3.0" }, "engines": { - "node": ">= 0.4" + "node": "^18.18.0 || >=20.0.0" }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "@typescript-eslint/parser": "^7.0.0", + "eslint": "^8.56.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } } }, - "node_modules/typed-array-byte-offset": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/typed-array-byte-offset/-/typed-array-byte-offset-1.0.0.tgz", - "integrity": "sha512-RD97prjEt9EL8YgAgpOkf3O4IF9lhJFr9g0htQkm0rchFp/Vx7LW5Q8fSXXub7BXAODyUQohRMyOc3faCPd0hg==", + "node_modules/typescript-eslint/node_modules/@typescript-eslint/parser": { + "version": "7.11.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.11.0.tgz", + "integrity": "sha512-yimw99teuaXVWsBcPO1Ais02kwJ1jmNA1KxE7ng0aT7ndr1pT1wqj0OJnsYVGKKlc4QJai86l/025L6z8CljOg==", "dev": true, "dependencies": { - "available-typed-arrays": "^1.0.5", - "call-bind": "^1.0.2", - "for-each": "^0.3.3", - "has-proto": "^1.0.1", - "is-typed-array": "^1.1.10" + "@typescript-eslint/scope-manager": "7.11.0", + "@typescript-eslint/types": "7.11.0", + "@typescript-eslint/typescript-estree": "7.11.0", + "@typescript-eslint/visitor-keys": "7.11.0", + "debug": "^4.3.4" }, "engines": { - "node": ">= 0.4" + "node": "^18.18.0 || >=20.0.0" }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.56.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } } }, - "node_modules/typed-array-length": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.4.tgz", - "integrity": "sha512-KjZypGq+I/H7HI5HlOoGHkWUUGq+Q0TPhQurLbyrVrvnKTBgzLhIJ7j6J/XTQOi0d1RjyZ0wdas8bKs2p0x3Ng==", + "node_modules/typescript-eslint/node_modules/@typescript-eslint/scope-manager": { + "version": "7.11.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.11.0.tgz", + "integrity": "sha512-27tGdVEiutD4POirLZX4YzT180vevUURJl4wJGmm6TrQoiYwuxTIY98PBp6L2oN+JQxzE0URvYlzJaBHIekXAw==", "dev": true, "dependencies": { - "call-bind": "^1.0.2", - "for-each": "^0.3.3", - "is-typed-array": "^1.1.9" + "@typescript-eslint/types": "7.11.0", + "@typescript-eslint/visitor-keys": "7.11.0" + }, + "engines": { + "node": "^18.18.0 || >=20.0.0" }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" } }, - "node_modules/typescript": { - "version": "5.3.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.3.3.tgz", - "integrity": "sha512-pXWcraxM0uxAS+tN0AG/BF2TyqmHO014Z070UsJ+pFvYuRSq8KH8DmWpnbXe0pEPDHXZV3FcAbJkijJ5oNEnWw==", + "node_modules/typescript-eslint/node_modules/@typescript-eslint/types": { + "version": "7.11.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.11.0.tgz", + "integrity": "sha512-MPEsDRZTyCiXkD4vd3zywDCifi7tatc4K37KqTprCvaXptP7Xlpdw0NR2hRJTetG5TxbWDB79Ys4kLmHliEo/w==", "dev": true, - "bin": { - "tsc": "bin/tsc", - "tsserver": "bin/tsserver" + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/typescript-eslint/node_modules/@typescript-eslint/typescript-estree": { + "version": "7.11.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.11.0.tgz", + "integrity": "sha512-cxkhZ2C/iyi3/6U9EPc5y+a6csqHItndvN/CzbNXTNrsC3/ASoYQZEt9uMaEp+xFNjasqQyszp5TumAVKKvJeQ==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "7.11.0", + "@typescript-eslint/visitor-keys": "7.11.0", + "debug": "^4.3.4", + "globby": "^11.1.0", + "is-glob": "^4.0.3", + "minimatch": "^9.0.4", + "semver": "^7.6.0", + "ts-api-utils": "^1.3.0" }, "engines": { - "node": ">=14.17" + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } } }, - "node_modules/unbox-primitive": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz", - "integrity": "sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==", + "node_modules/typescript-eslint/node_modules/@typescript-eslint/visitor-keys": { + "version": "7.11.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.11.0.tgz", + "integrity": "sha512-7syYk4MzjxTEk0g/w3iqtgxnFQspDJfn6QKD36xMuuhTzjcxY7F8EmBLnALjVyaOF1/bVocu3bS/2/F7rXrveQ==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "7.11.0", + "eslint-visitor-keys": "^3.4.3" + }, + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/typescript-eslint/node_modules/minimatch": { + "version": "9.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.4.tgz", + "integrity": "sha512-KqWh+VchfxcMNRAJjj2tnsSJdNbHsVgnkBhTNrW7AjVo6OvLtxw8zfT9oLw1JSohlFzJ8jCoTgaoXvJ+kHt6fw==", "dev": true, "dependencies": { - "call-bind": "^1.0.2", - "has-bigints": "^1.0.2", - "has-symbols": "^1.0.3", - "which-boxed-primitive": "^1.0.2" + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "url": "https://github.com/sponsors/isaacs" } }, "node_modules/undefsafe": { @@ -7430,12 +5864,6 @@ "uuid": "dist/bin/uuid" } }, - "node_modules/v8-compile-cache": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.4.0.tgz", - "integrity": "sha512-ocyWc3bAHBB/guyqJQVI5o4BZkPhznPYUG2ea80Gond/BgNWpap8TOmLSeeQG7bnh2KMISxskdADG59j7zruhw==", - "dev": true - }, "node_modules/v8-compile-cache-lib": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", @@ -7507,82 +5935,6 @@ "node": ">= 8" } }, - "node_modules/which-boxed-primitive": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz", - "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==", - "dev": true, - "dependencies": { - "is-bigint": "^1.0.1", - "is-boolean-object": "^1.1.0", - "is-number-object": "^1.0.4", - "is-string": "^1.0.5", - "is-symbol": "^1.0.3" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/which-builtin-type": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/which-builtin-type/-/which-builtin-type-1.1.3.tgz", - "integrity": "sha512-YmjsSMDBYsM1CaFiayOVT06+KJeXf0o5M/CAd4o1lTadFAtacTUM49zoYxr/oroopFDfhvN6iEcBxUyc3gvKmw==", - "dev": true, - "dependencies": { - "function.prototype.name": "^1.1.5", - "has-tostringtag": "^1.0.0", - "is-async-function": "^2.0.0", - "is-date-object": "^1.0.5", - "is-finalizationregistry": "^1.0.2", - "is-generator-function": "^1.0.10", - "is-regex": "^1.1.4", - "is-weakref": "^1.0.2", - "isarray": "^2.0.5", - "which-boxed-primitive": "^1.0.2", - "which-collection": "^1.0.1", - "which-typed-array": "^1.1.9" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/which-collection": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/which-collection/-/which-collection-1.0.1.tgz", - "integrity": "sha512-W8xeTUwaln8i3K/cY1nGXzdnVZlidBcagyNFtBdD5kxnb4TvGKR7FfSIS3mYpwWS1QUCutfKz8IY8RjftB0+1A==", - "dev": true, - "dependencies": { - "is-map": "^2.0.1", - "is-set": "^2.0.1", - "is-weakmap": "^2.0.1", - "is-weakset": "^2.0.1" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/which-typed-array": { - "version": "1.1.13", - "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.13.tgz", - "integrity": "sha512-P5Nra0qjSncduVPEAr7xhoF5guty49ArDTwzJ/yNuPIbZppyRxFQsRCWrocxIY+CnMVG+qfbU2FmDKyvSGClow==", - "dev": true, - "dependencies": { - "available-typed-arrays": "^1.0.5", - "call-bind": "^1.0.4", - "for-each": "^0.3.3", - "gopd": "^1.0.1", - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/winston": { "version": "3.11.0", "resolved": "https://registry.npmjs.org/winston/-/winston-3.11.0.tgz", @@ -7655,12 +6007,6 @@ "resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz", "integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==" }, - "node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true - }, "node_modules/yn": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", @@ -7669,6 +6015,18 @@ "engines": { "node": ">=6" } + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } } } } diff --git a/package.json b/package.json index 3b722c24..6a384cec 100644 --- a/package.json +++ b/package.json @@ -29,19 +29,19 @@ "winston": "^3.3.4" }, "devDependencies": { - "@flybywiresim/eslint-config": "^0.1.0", + "@eslint/js": "^9.3.0", "@types/bad-words": "^3.0.3", "@types/config": "^3.3.1", "@types/jsdom": "^21.1.6", "@types/node": "^18.0.0", "@types/node-fetch": "^2.6.10", - "@typescript-eslint/eslint-plugin": "^6.18.0", "@typescript-eslint/parser": "^6.18.0", "dotenv": "^16.0.0", - "eslint": "^7.29.0", + "eslint": "^8.57.0", "nodemon": "^3.0.2", "ts-node": "^10.4.0", - "typescript": "^5.0.3" + "typescript": "^5.4.5", + "typescript-eslint": "^7.11.0" }, "engines": { "node": "18.x" From 0cf5021bc52a0146eda2fdf9842a16be1c0b06c1 Mon Sep 17 00:00:00 2001 From: ExampleWasTaken <58574351+ExampleWasTaken@users.noreply.github.com> Date: Thu, 13 Jun 2024 17:52:22 +0200 Subject: [PATCH 02/82] update eslint and ts-eslint and add prettier support --- eslint.config.mjs | 2 +- package-lock.json | 672 +++++++++++++++++----------------------------- package.json | 6 +- 3 files changed, 244 insertions(+), 436 deletions(-) diff --git a/eslint.config.mjs b/eslint.config.mjs index 11c0371d..fadca2ac 100644 --- a/eslint.config.mjs +++ b/eslint.config.mjs @@ -5,7 +5,7 @@ import prettierConfig from 'eslint-config-prettier'; export default tseslint.config( eslint.configs.recommended, - ...tseslint.configs.strictTypeChecked, + ...tseslint.configs.recommendedTypeChecked, prettierConfig, { plugins: { diff --git a/package-lock.json b/package-lock.json index d0ded7e3..af2c8b80 100644 --- a/package-lock.json +++ b/package-lock.json @@ -16,6 +16,8 @@ "bad-words": "^3.0.4", "config": "^3.3.9", "discord.js": "^14.11.0", + "eslint-config-prettier": "^9.1.0", + "eslint-plugin-prettier": "^5.1.3", "jsdom": "^23.2.0", "moment": "^2.29.4", "mongoose": "^8.0.3", @@ -31,14 +33,11 @@ "@types/node-fetch": "^2.6.10", "@typescript-eslint/parser": "^6.18.0", "dotenv": "^16.0.0", - "eslint": "^8.57.0", - "eslint-config-prettier": "^9.1.0", - "eslint-plugin-prettier": "^5.1.3", + "eslint": "^9.4.0", "nodemon": "^3.0.2", - "prettier": "^3.2.5", "ts-node": "^10.4.0", "typescript": "^5.4.5", - "typescript-eslint": "^7.11.0" + "typescript-eslint": "^8.0.0-alpha.30" }, "engines": { "node": "18.x" @@ -48,7 +47,6 @@ "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" } @@ -1602,7 +1600,6 @@ "version": "4.4.0", "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", "integrity": "sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==", - "dev": true, "dependencies": { "eslint-visitor-keys": "^3.3.0" }, @@ -1617,21 +1614,52 @@ "version": "4.10.0", "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.10.0.tgz", "integrity": "sha512-Cu96Sd2By9mCNTx2iyKOmq10v22jUVQv0lQnlGNy16oE9589yE+QADPbrMGCkA51cKZSg3Pu/aTJVTGfL/qjUA==", - "dev": true, "engines": { "node": "^12.0.0 || ^14.0.0 || >=16.0.0" } }, + "node_modules/@eslint/config-array": { + "version": "0.15.1", + "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.15.1.tgz", + "integrity": "sha512-K4gzNq+yymn/EVsXYmf+SBcBro8MTf+aXJZUphM96CdzUEr+ClGDvAbpmaEK+cGVigVXIgs9gNmvHAlrzzY5JQ==", + "dependencies": { + "@eslint/object-schema": "^2.1.3", + "debug": "^4.3.1", + "minimatch": "^3.0.5" + }, + "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==", + "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==", + "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==", - "dev": true, + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.1.0.tgz", + "integrity": "sha512-4Bfj15dVJdoy3RfZmmo86RK1Fwzn6SstsvK9JS+BaVKqC6QQQQyXekNaC+g+LKNgkQ+2VhGAzm6hO40AhMR3zQ==", "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", @@ -1639,7 +1667,7 @@ "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" @@ -1649,7 +1677,6 @@ "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -1659,7 +1686,6 @@ "version": "3.1.2", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, "dependencies": { "brace-expansion": "^1.1.7" }, @@ -1668,10 +1694,17 @@ } }, "node_modules/@eslint/js": { - "version": "9.3.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.3.0.tgz", - "integrity": "sha512-niBqk8iwv96+yuTwjM6bWg8ovzAPF9qkICsGtcoa5/dmqcEMfdwNAX7+/OHcJHc7wj7XqPxH98oAHytFYlw6Sw==", - "dev": true, + "version": "9.4.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.4.0.tgz", + "integrity": "sha512-fdI7VJjP3Rvc70lC4xkFXHB0fiPeojiL1PxVG6t1ZvXQrarj893PweuBTujxDUFk0Fxj4R7PIIAZ/aiiyZPZcg==", + "engines": { + "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==", "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } @@ -1700,47 +1733,10 @@ "node": ">=14.0.0" } }, - "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/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, - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/@humanwhocodes/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, - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, "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, "engines": { "node": ">=12.22" }, @@ -1749,11 +1745,17 @@ "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==", + "engines": { + "node": ">=18.18" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } }, "node_modules/@jridgewell/resolve-uri": { "version": "3.1.1", @@ -1792,7 +1794,6 @@ "version": "2.1.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", - "dev": true, "dependencies": { "@nodelib/fs.stat": "2.0.5", "run-parallel": "^1.1.9" @@ -1805,7 +1806,6 @@ "version": "2.0.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", - "dev": true, "engines": { "node": ">= 8" } @@ -1814,7 +1814,6 @@ "version": "1.2.8", "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", - "dev": true, "dependencies": { "@nodelib/fs.scandir": "2.1.5", "fastq": "^1.6.0" @@ -1879,7 +1878,6 @@ "version": "0.1.1", "resolved": "https://registry.npmjs.org/@pkgr/core/-/core-0.1.1.tgz", "integrity": "sha512-cq8o4cWH0ibXh9VGi5P20Tu9XF/0fFXl9EUinr9QfTM7a7p0oTA4iJRCQWppXR1Pg8dSM0UCItCkPwsk9qWWYA==", - "dev": true, "engines": { "node": "^12.20.0 || ^14.18.0 || >=16.0.0" }, @@ -2698,26 +2696,23 @@ } }, "node_modules/@typescript-eslint/type-utils": { - "version": "7.11.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-7.11.0.tgz", - "integrity": "sha512-WmppUEgYy+y1NTseNMJ6mCFxt03/7jTOy08bcg7bxJJdsM4nuhnchyBbE8vryveaJUf62noH7LodPSo5Z0WUCg==", + "version": "8.0.0-alpha.30", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.0.0-alpha.30.tgz", + "integrity": "sha512-FrnhlCKEKZKRbpDviHkIU9tayIUGTOfa+SjvrRv6p/AJIUv6QT8oRboRjLH/cCuwUEbM0k5UtRWYug4albHUqQ==", "dev": true, "dependencies": { - "@typescript-eslint/typescript-estree": "7.11.0", - "@typescript-eslint/utils": "7.11.0", + "@typescript-eslint/typescript-estree": "8.0.0-alpha.30", + "@typescript-eslint/utils": "8.0.0-alpha.30", "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 @@ -2725,12 +2720,12 @@ } }, "node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/types": { - "version": "7.11.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.11.0.tgz", - "integrity": "sha512-MPEsDRZTyCiXkD4vd3zywDCifi7tatc4K37KqTprCvaXptP7Xlpdw0NR2hRJTetG5TxbWDB79Ys4kLmHliEo/w==", + "version": "8.0.0-alpha.30", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.0.0-alpha.30.tgz", + "integrity": "sha512-4WzLlw27SO9pK9UFj/Hu7WGo8WveT0SEiIpFVsV2WwtQmLps6kouwtVCB8GJPZKJyurhZhcqCoQVQFmpv441Vg==", "dev": true, "engines": { - "node": "^18.18.0 || >=20.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "type": "opencollective", @@ -2738,13 +2733,13 @@ } }, "node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/typescript-estree": { - "version": "7.11.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.11.0.tgz", - "integrity": "sha512-cxkhZ2C/iyi3/6U9EPc5y+a6csqHItndvN/CzbNXTNrsC3/ASoYQZEt9uMaEp+xFNjasqQyszp5TumAVKKvJeQ==", + "version": "8.0.0-alpha.30", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.0.0-alpha.30.tgz", + "integrity": "sha512-WSXbc9ZcXI+7yC+6q95u77i8FXz6HOLsw3ST+vMUlFy1lFbXyFL/3e6HDKQCm2Clt0krnoCPiTGvIn+GkYPn4Q==", "dev": true, "dependencies": { - "@typescript-eslint/types": "7.11.0", - "@typescript-eslint/visitor-keys": "7.11.0", + "@typescript-eslint/types": "8.0.0-alpha.30", + "@typescript-eslint/visitor-keys": "8.0.0-alpha.30", "debug": "^4.3.4", "globby": "^11.1.0", "is-glob": "^4.0.3", @@ -2753,7 +2748,7 @@ "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", @@ -2766,16 +2761,16 @@ } }, "node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/visitor-keys": { - "version": "7.11.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.11.0.tgz", - "integrity": "sha512-7syYk4MzjxTEk0g/w3iqtgxnFQspDJfn6QKD36xMuuhTzjcxY7F8EmBLnALjVyaOF1/bVocu3bS/2/F7rXrveQ==", + "version": "8.0.0-alpha.30", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.0.0-alpha.30.tgz", + "integrity": "sha512-XZuNurZxBqmr6ZIRIwWFq7j5RZd6ZlkId/HZEWyfciK+CWoyOxSF9Pv2VXH9Rlu2ZG2PfbhLz2Veszl4Pfn7yA==", "dev": true, "dependencies": { - "@typescript-eslint/types": "7.11.0", + "@typescript-eslint/types": "8.0.0-alpha.30", "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", @@ -2839,38 +2834,38 @@ } }, "node_modules/@typescript-eslint/utils": { - "version": "7.11.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.11.0.tgz", - "integrity": "sha512-xlAWwPleNRHwF37AhrZurOxA1wyXowW4PqVXZVUNCLjB48CqdPJoJWkrpH2nij9Q3Lb7rtWindtoXwxjxlKKCA==", + "version": "8.0.0-alpha.30", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.0.0-alpha.30.tgz", + "integrity": "sha512-rfhqfLqFyXhHNDwMnHiVGxl/Z2q/3guQ1jLlGQ0hi9Rb7inmwz42crM+NnLPR+2vEnwyw1P/g7fnQgQ3qvFx4g==", "dev": true, "dependencies": { "@eslint-community/eslint-utils": "^4.4.0", - "@typescript-eslint/scope-manager": "7.11.0", - "@typescript-eslint/types": "7.11.0", - "@typescript-eslint/typescript-estree": "7.11.0" + "@typescript-eslint/scope-manager": "8.0.0-alpha.30", + "@typescript-eslint/types": "8.0.0-alpha.30", + "@typescript-eslint/typescript-estree": "8.0.0-alpha.30" }, "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/utils/node_modules/@typescript-eslint/scope-manager": { - "version": "7.11.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.11.0.tgz", - "integrity": "sha512-27tGdVEiutD4POirLZX4YzT180vevUURJl4wJGmm6TrQoiYwuxTIY98PBp6L2oN+JQxzE0URvYlzJaBHIekXAw==", + "version": "8.0.0-alpha.30", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.0.0-alpha.30.tgz", + "integrity": "sha512-FGW/iPWGyPFamAVZ60oCAthMqQrqafUGebF8UKuq/ha+e9SVG6YhJoRzurlQXOVf8dHfOhJ0ADMXyFnMc53clg==", "dev": true, "dependencies": { - "@typescript-eslint/types": "7.11.0", - "@typescript-eslint/visitor-keys": "7.11.0" + "@typescript-eslint/types": "8.0.0-alpha.30", + "@typescript-eslint/visitor-keys": "8.0.0-alpha.30" }, "engines": { - "node": "^18.18.0 || >=20.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "type": "opencollective", @@ -2878,12 +2873,12 @@ } }, "node_modules/@typescript-eslint/utils/node_modules/@typescript-eslint/types": { - "version": "7.11.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.11.0.tgz", - "integrity": "sha512-MPEsDRZTyCiXkD4vd3zywDCifi7tatc4K37KqTprCvaXptP7Xlpdw0NR2hRJTetG5TxbWDB79Ys4kLmHliEo/w==", + "version": "8.0.0-alpha.30", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.0.0-alpha.30.tgz", + "integrity": "sha512-4WzLlw27SO9pK9UFj/Hu7WGo8WveT0SEiIpFVsV2WwtQmLps6kouwtVCB8GJPZKJyurhZhcqCoQVQFmpv441Vg==", "dev": true, "engines": { - "node": "^18.18.0 || >=20.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "type": "opencollective", @@ -2891,13 +2886,13 @@ } }, "node_modules/@typescript-eslint/utils/node_modules/@typescript-eslint/typescript-estree": { - "version": "7.11.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.11.0.tgz", - "integrity": "sha512-cxkhZ2C/iyi3/6U9EPc5y+a6csqHItndvN/CzbNXTNrsC3/ASoYQZEt9uMaEp+xFNjasqQyszp5TumAVKKvJeQ==", + "version": "8.0.0-alpha.30", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.0.0-alpha.30.tgz", + "integrity": "sha512-WSXbc9ZcXI+7yC+6q95u77i8FXz6HOLsw3ST+vMUlFy1lFbXyFL/3e6HDKQCm2Clt0krnoCPiTGvIn+GkYPn4Q==", "dev": true, "dependencies": { - "@typescript-eslint/types": "7.11.0", - "@typescript-eslint/visitor-keys": "7.11.0", + "@typescript-eslint/types": "8.0.0-alpha.30", + "@typescript-eslint/visitor-keys": "8.0.0-alpha.30", "debug": "^4.3.4", "globby": "^11.1.0", "is-glob": "^4.0.3", @@ -2906,7 +2901,7 @@ "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", @@ -2919,16 +2914,16 @@ } }, "node_modules/@typescript-eslint/utils/node_modules/@typescript-eslint/visitor-keys": { - "version": "7.11.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.11.0.tgz", - "integrity": "sha512-7syYk4MzjxTEk0g/w3iqtgxnFQspDJfn6QKD36xMuuhTzjcxY7F8EmBLnALjVyaOF1/bVocu3bS/2/F7rXrveQ==", + "version": "8.0.0-alpha.30", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.0.0-alpha.30.tgz", + "integrity": "sha512-XZuNurZxBqmr6ZIRIwWFq7j5RZd6ZlkId/HZEWyfciK+CWoyOxSF9Pv2VXH9Rlu2ZG2PfbhLz2Veszl4Pfn7yA==", "dev": true, "dependencies": { - "@typescript-eslint/types": "7.11.0", + "@typescript-eslint/types": "8.0.0-alpha.30", "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", @@ -2967,12 +2962,6 @@ "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.2.4", "resolved": "https://registry.npmjs.org/@vladfrangu/async_event_emitter/-/async_event_emitter-2.2.4.tgz", @@ -2992,7 +2981,6 @@ "version": "8.11.3", "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.3.tgz", "integrity": "sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==", - "dev": true, "bin": { "acorn": "bin/acorn" }, @@ -3004,7 +2992,6 @@ "version": "5.3.2", "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", - "dev": true, "peerDependencies": { "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" } @@ -3033,7 +3020,6 @@ "version": "6.12.6", "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", - "dev": true, "dependencies": { "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", @@ -3049,7 +3035,6 @@ "version": "5.0.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true, "engines": { "node": ">=8" } @@ -3058,7 +3043,6 @@ "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, "dependencies": { "color-convert": "^2.0.1" }, @@ -3091,8 +3075,7 @@ "node_modules/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 + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==" }, "node_modules/array-union": { "version": "2.1.0", @@ -3132,8 +3115,7 @@ "node_modules/balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "dev": true + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" }, "node_modules/base64-js": { "version": "1.5.1", @@ -3235,7 +3217,6 @@ "version": "3.1.0", "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", - "dev": true, "engines": { "node": ">=6" } @@ -3244,7 +3225,6 @@ "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" @@ -3296,7 +3276,6 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, "dependencies": { "color-name": "~1.1.4" }, @@ -3354,8 +3333,7 @@ "node_modules/concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", - "dev": true + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==" }, "node_modules/config": { "version": "3.3.10", @@ -3389,7 +3367,6 @@ "version": "7.0.3", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", - "dev": true, "dependencies": { "path-key": "^3.1.0", "shebang-command": "^2.0.0", @@ -3502,8 +3479,7 @@ "node_modules/deep-is": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", - "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", - "dev": true + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==" }, "node_modules/delayed-stream": { "version": "1.0.0", @@ -3568,18 +3544,6 @@ "node": ">=16.11.0" } }, - "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/dotenv": { "version": "16.3.1", "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.3.1.tgz", @@ -3612,7 +3576,6 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", - "dev": true, "engines": { "node": ">=10" }, @@ -3621,41 +3584,36 @@ } }, "node_modules/eslint": { - "version": "8.57.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.57.0.tgz", - "integrity": "sha512-dZ6+mexnaTIbSBZWgou51U6OmzIhYM2VcNdtiTtI7qPNZm35Akpr0f6vtw3w1Kmn5PYo+tZVfh13WrhpS6oLqQ==", - "dev": true, + "version": "9.4.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.4.0.tgz", + "integrity": "sha512-sjc7Y8cUD1IlwYcTS9qPSvGjAC8Ne9LctpxKKu3x/1IC9bnOg98Zy6GxEJUfr1NojMgVPlyANXYns8oE2c1TAA==", "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/config-array": "^0.15.1", + "@eslint/eslintrc": "^3.1.0", + "@eslint/js": "9.4.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", + "eslint-scope": "^8.0.1", + "eslint-visitor-keys": "^4.0.0", + "espree": "^10.0.1", "esquery": "^1.4.2", "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", @@ -3669,7 +3627,7 @@ "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" @@ -3679,7 +3637,6 @@ "version": "9.1.0", "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-9.1.0.tgz", "integrity": "sha512-NSWl5BFQWEPi1j4TjVNItzYV7dZXZ+wP6I6ZhrBGpChQhZRUaElihE9uRRkcbRnNb76UMKDF3r+WTmNcGPKsqw==", - "dev": true, "bin": { "eslint-config-prettier": "bin/cli.js" }, @@ -3691,7 +3648,6 @@ "version": "5.1.3", "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-5.1.3.tgz", "integrity": "sha512-C9GCVAs4Eq7ZC/XFQHITLiHJxQngdtraXaM+LoUFoFp/lHNl2Zn8f3WQbe9HvTBBQ9YnKFB0/2Ajdqwo5D1EAw==", - "dev": true, "dependencies": { "prettier-linter-helpers": "^1.0.0", "synckit": "^0.8.6" @@ -3718,16 +3674,15 @@ } }, "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==", - "dev": true, + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.0.1.tgz", + "integrity": "sha512-pL8XjgP4ZOmmwfFE8mEhSxA7ZY4C+LWyqjQ3o4yWkkmD0qcMT9kkW3zWHOczhWcjTSgqycYAgwSlXvZltv65og==", "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" @@ -3737,7 +3692,6 @@ "version": "3.4.3", "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", - "dev": true, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" }, @@ -3745,30 +3699,30 @@ "url": "https://opencollective.com/eslint" } }, - "node_modules/eslint/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==", - "dev": true, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - } - }, "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, "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==", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, "node_modules/eslint/node_modules/glob-parent": { "version": "6.0.2", "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", - "dev": true, "dependencies": { "is-glob": "^4.0.3" }, @@ -3780,7 +3734,6 @@ "version": "3.1.2", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, "dependencies": { "brace-expansion": "^1.1.7" }, @@ -3789,17 +3742,27 @@ } }, "node_modules/espree": { - "version": "9.6.1", - "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", - "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==", - "dev": true, + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-10.0.1.tgz", + "integrity": "sha512-MWkrWZbJsL2UwnjxTX3gG8FneachS/Mwg7tdGXce011sJd5b0JG54vat5KHnfSBODZ3Wvzd2WnjxyzsRoVv+ww==", "dependencies": { - "acorn": "^8.9.0", + "acorn": "^8.11.3", "acorn-jsx": "^5.3.2", - "eslint-visitor-keys": "^3.4.1" + "eslint-visitor-keys": "^4.0.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" + } + }, + "node_modules/espree/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==", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "url": "https://opencollective.com/eslint" @@ -3809,7 +3772,6 @@ "version": "1.5.0", "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.5.0.tgz", "integrity": "sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==", - "dev": true, "dependencies": { "estraverse": "^5.1.0" }, @@ -3821,7 +3783,6 @@ "version": "4.3.0", "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", - "dev": true, "dependencies": { "estraverse": "^5.2.0" }, @@ -3833,7 +3794,6 @@ "version": "5.3.0", "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true, "engines": { "node": ">=4.0" } @@ -3842,7 +3802,6 @@ "version": "2.0.3", "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", - "dev": true, "engines": { "node": ">=0.10.0" } @@ -3863,8 +3822,7 @@ "node_modules/fast-diff": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.3.0.tgz", - "integrity": "sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw==", - "dev": true + "integrity": "sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw==" }, "node_modules/fast-glob": { "version": "3.3.2", @@ -3885,14 +3843,12 @@ "node_modules/fast-json-stable-stringify": { "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 + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==" }, "node_modules/fast-levenshtein": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", - "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", - "dev": true + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==" }, "node_modules/fast-xml-parser": { "version": "4.2.5", @@ -3919,7 +3875,6 @@ "version": "1.16.0", "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.16.0.tgz", "integrity": "sha512-ifCoaXsDrsdkWTtiNJX5uzHDsrck5TzfKKDcuFFTIrrc/BS076qgEIfoIy1VeZqViznfKiysPYTh/QeHtnIsYA==", - "dev": true, "dependencies": { "reusify": "^1.0.4" } @@ -3930,15 +3885,14 @@ "integrity": "sha512-OP2IUU6HeYKJi3i0z4A19kHMQoLVs4Hc+DPqqxI2h/DPZHTm/vjsfC6P0b4jCMy14XizLBqvndQ+UilD7707Jw==" }, "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==", - "dev": true, + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz", + "integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==", "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-range": { @@ -3957,7 +3911,6 @@ "version": "5.0.0", "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", - "dev": true, "dependencies": { "locate-path": "^6.0.0", "path-exists": "^4.0.0" @@ -3970,24 +3923,21 @@ } }, "node_modules/flat-cache": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.2.0.tgz", - "integrity": "sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==", - "dev": true, + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz", + "integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==", "dependencies": { "flatted": "^3.2.9", - "keyv": "^4.5.3", - "rimraf": "^3.0.2" + "keyv": "^4.5.4" }, "engines": { - "node": "^10.12.0 || >=12.0.0" + "node": ">=16" } }, "node_modules/flatted": { "version": "3.3.1", "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.1.tgz", - "integrity": "sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==", - "dev": true + "integrity": "sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==" }, "node_modules/fn.name": { "version": "1.1.0", @@ -4007,33 +3957,6 @@ "node": ">= 6" } }, - "node_modules/fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", - "dev": true - }, - "node_modules/glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "deprecated": "Glob versions prior to v9 are no longer supported", - "dev": true, - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, "node_modules/glob-parent": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", @@ -4046,38 +3969,12 @@ "node": ">= 6" } }, - "node_modules/glob/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, - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/glob/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, - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, "node_modules/globals": { - "version": "13.24.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", - "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", - "dev": true, - "dependencies": { - "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==", "engines": { - "node": ">=8" + "node": ">=18" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" @@ -4113,7 +4010,6 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, "engines": { "node": ">=8" } @@ -4195,7 +4091,6 @@ "version": "5.3.1", "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.1.tgz", "integrity": "sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw==", - "dev": true, "engines": { "node": ">= 4" } @@ -4210,7 +4105,6 @@ "version": "3.3.0", "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", - "dev": true, "dependencies": { "parent-module": "^1.0.0", "resolve-from": "^4.0.0" @@ -4226,22 +4120,10 @@ "version": "0.1.4", "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", - "dev": true, "engines": { "node": ">=0.8.19" } }, - "node_modules/inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", - "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", - "dev": true, - "dependencies": { - "once": "^1.3.0", - "wrappy": "1" - } - }, "node_modules/inherits": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", @@ -4273,7 +4155,6 @@ "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", - "dev": true, "engines": { "node": ">=0.10.0" } @@ -4282,7 +4163,6 @@ "version": "4.0.3", "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", - "dev": true, "dependencies": { "is-extglob": "^2.1.1" }, @@ -4303,7 +4183,6 @@ "version": "3.0.3", "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", - "dev": true, "engines": { "node": ">=8" } @@ -4327,14 +4206,12 @@ "node_modules/isexe": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", - "dev": true + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==" }, "node_modules/js-yaml": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", - "dev": true, "dependencies": { "argparse": "^2.0.1" }, @@ -4427,20 +4304,17 @@ "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 + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==" }, "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 + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" }, "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 + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==" }, "node_modules/json5": { "version": "2.2.3", @@ -4465,7 +4339,6 @@ "version": "4.5.4", "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", - "dev": true, "dependencies": { "json-buffer": "3.0.1" } @@ -4479,7 +4352,6 @@ "version": "0.4.1", "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", - "dev": true, "dependencies": { "prelude-ls": "^1.2.1", "type-check": "~0.4.0" @@ -4492,7 +4364,6 @@ "version": "6.0.0", "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", - "dev": true, "dependencies": { "p-locate": "^5.0.0" }, @@ -4511,8 +4382,7 @@ "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 + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==" }, "node_modules/lodash.snakecase": { "version": "4.1.1", @@ -4760,8 +4630,7 @@ "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 + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==" }, "node_modules/node-fetch": { "version": "2.7.0", @@ -4921,7 +4790,6 @@ "version": "0.9.3", "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.3.tgz", "integrity": "sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg==", - "dev": true, "dependencies": { "@aashutoshrathi/word-wrap": "^1.2.3", "deep-is": "^0.1.3", @@ -4938,7 +4806,6 @@ "version": "3.1.0", "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", - "dev": true, "dependencies": { "yocto-queue": "^0.1.0" }, @@ -4953,7 +4820,6 @@ "version": "5.0.0", "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", - "dev": true, "dependencies": { "p-limit": "^3.0.2" }, @@ -4968,7 +4834,6 @@ "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, "dependencies": { "callsites": "^3.0.0" }, @@ -4991,25 +4856,14 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", - "dev": true, "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", "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", - "dev": true, "engines": { "node": ">=8" } @@ -5039,16 +4893,15 @@ "version": "1.2.1", "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", - "dev": true, "engines": { "node": ">= 0.8.0" } }, "node_modules/prettier": { - "version": "3.2.5", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.2.5.tgz", - "integrity": "sha512-3/GWa9aOC0YeD7LUfvOG2NiDyhOWRvt1k+rcKhOuYnMY24iiCphgneUfJDyFXd6rZCAnuLBv6UeAULtrhT/F4A==", - "dev": true, + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.3.2.tgz", + "integrity": "sha512-rAVeHYMcv8ATV5d508CFdn+8/pHPpXeIid1DdrPwXnaAdH7cqjVbpJaT5eq4yRAFU/lsbwYwSF/n5iNrdJHPQA==", + "peer": true, "bin": { "prettier": "bin/prettier.cjs" }, @@ -5063,7 +4916,6 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz", "integrity": "sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==", - "dev": true, "dependencies": { "fast-diff": "^1.1.2" }, @@ -5099,7 +4951,6 @@ "version": "1.2.3", "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", - "dev": true, "funding": [ { "type": "github", @@ -5157,7 +5008,6 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", - "dev": true, "engines": { "node": ">=4" } @@ -5166,28 +5016,11 @@ "version": "1.0.4", "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", - "dev": true, "engines": { "iojs": ">=1.0.0", "node": ">=0.10.0" } }, - "node_modules/rimraf": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", - "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", - "deprecated": "Rimraf versions prior to v4 are no longer supported", - "dev": true, - "dependencies": { - "glob": "^7.1.3" - }, - "bin": { - "rimraf": "bin.js" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, "node_modules/rrweb-cssom": { "version": "0.6.0", "resolved": "https://registry.npmjs.org/rrweb-cssom/-/rrweb-cssom-0.6.0.tgz", @@ -5197,7 +5030,6 @@ "version": "1.2.0", "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", - "dev": true, "funding": [ { "type": "github", @@ -5275,7 +5107,6 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", - "dev": true, "dependencies": { "shebang-regex": "^3.0.0" }, @@ -5287,7 +5118,6 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", - "dev": true, "engines": { "node": ">=8" } @@ -5393,7 +5223,6 @@ "version": "6.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, "dependencies": { "ansi-regex": "^5.0.1" }, @@ -5405,7 +5234,6 @@ "version": "3.1.1", "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", - "dev": true, "engines": { "node": ">=8" }, @@ -5422,7 +5250,6 @@ "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, "dependencies": { "has-flag": "^4.0.0" }, @@ -5439,7 +5266,6 @@ "version": "0.8.8", "resolved": "https://registry.npmjs.org/synckit/-/synckit-0.8.8.tgz", "integrity": "sha512-HwOKAP7Wc5aRGYdKH+dw0PRRpbO841v2DENBtjnR5HFWoiNByAl7vrx3p0G/rCyYXQsrxqtX48TImFtPcIHSpQ==", - "dev": true, "dependencies": { "@pkgr/core": "^0.1.0", "tslib": "^2.6.2" @@ -5459,8 +5285,7 @@ "node_modules/text-table": { "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 + "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==" }, "node_modules/to-regex-range": { "version": "5.0.1", @@ -5588,7 +5413,6 @@ "version": "0.4.0", "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", - "dev": true, "dependencies": { "prelude-ls": "^1.2.1" }, @@ -5596,18 +5420,6 @@ "node": ">= 0.8.0" } }, - "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.4.5", "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.4.5.tgz", @@ -5622,25 +5434,22 @@ } }, "node_modules/typescript-eslint": { - "version": "7.11.0", - "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-7.11.0.tgz", - "integrity": "sha512-ZKe3yHF/IS/kCUE4CGE3UgtK+Q7yRk1e9kwEI0rqm9XxMTd9P1eHe0LVVtrZ3oFuIQ2unJ9Xn0vTsLApzJ3aPw==", + "version": "8.0.0-alpha.30", + "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.0.0-alpha.30.tgz", + "integrity": "sha512-/vGhBMsK1TpadQh1eQ02c5pyiPGmKR9cVzX5C9plZ+LC0HPLpWoJbbTVfQN7BkIK7tUxDt2BFr3pFL5hDDrx7g==", "dev": true, "dependencies": { - "@typescript-eslint/eslint-plugin": "7.11.0", - "@typescript-eslint/parser": "7.11.0", - "@typescript-eslint/utils": "7.11.0" + "@typescript-eslint/eslint-plugin": "8.0.0-alpha.30", + "@typescript-eslint/parser": "8.0.0-alpha.30", + "@typescript-eslint/utils": "8.0.0-alpha.30" }, "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 @@ -5648,31 +5457,31 @@ } }, "node_modules/typescript-eslint/node_modules/@typescript-eslint/eslint-plugin": { - "version": "7.11.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.11.0.tgz", - "integrity": "sha512-P+qEahbgeHW4JQ/87FuItjBj8O3MYv5gELDzr8QaQ7fsll1gSMTYb6j87MYyxwf3DtD7uGFB9ShwgmCJB5KmaQ==", + "version": "8.0.0-alpha.30", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.0.0-alpha.30.tgz", + "integrity": "sha512-2CBUupdkfbE3eATph4QeZejvT+M+1bVur+zXlVx09WN31phap51ps/qemeclnCbGEz6kTgBDmScrr9XmmF8/Pg==", "dev": true, "dependencies": { "@eslint-community/regexpp": "^4.10.0", - "@typescript-eslint/scope-manager": "7.11.0", - "@typescript-eslint/type-utils": "7.11.0", - "@typescript-eslint/utils": "7.11.0", - "@typescript-eslint/visitor-keys": "7.11.0", + "@typescript-eslint/scope-manager": "8.0.0-alpha.30", + "@typescript-eslint/type-utils": "8.0.0-alpha.30", + "@typescript-eslint/utils": "8.0.0-alpha.30", + "@typescript-eslint/visitor-keys": "8.0.0-alpha.30", "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": { @@ -5681,26 +5490,26 @@ } }, "node_modules/typescript-eslint/node_modules/@typescript-eslint/parser": { - "version": "7.11.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.11.0.tgz", - "integrity": "sha512-yimw99teuaXVWsBcPO1Ais02kwJ1jmNA1KxE7ng0aT7ndr1pT1wqj0OJnsYVGKKlc4QJai86l/025L6z8CljOg==", + "version": "8.0.0-alpha.30", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.0.0-alpha.30.tgz", + "integrity": "sha512-tAYgFmgXU1MlCK3nbblUvJlDSibBvxtAQXGrF3IG0KmnRza9FXILZifHWL0rrwacDn40K53K607Fk2QkMjiGgw==", "dev": true, "dependencies": { - "@typescript-eslint/scope-manager": "7.11.0", - "@typescript-eslint/types": "7.11.0", - "@typescript-eslint/typescript-estree": "7.11.0", - "@typescript-eslint/visitor-keys": "7.11.0", + "@typescript-eslint/scope-manager": "8.0.0-alpha.30", + "@typescript-eslint/types": "8.0.0-alpha.30", + "@typescript-eslint/typescript-estree": "8.0.0-alpha.30", + "@typescript-eslint/visitor-keys": "8.0.0-alpha.30", "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": { @@ -5709,16 +5518,16 @@ } }, "node_modules/typescript-eslint/node_modules/@typescript-eslint/scope-manager": { - "version": "7.11.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.11.0.tgz", - "integrity": "sha512-27tGdVEiutD4POirLZX4YzT180vevUURJl4wJGmm6TrQoiYwuxTIY98PBp6L2oN+JQxzE0URvYlzJaBHIekXAw==", + "version": "8.0.0-alpha.30", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.0.0-alpha.30.tgz", + "integrity": "sha512-FGW/iPWGyPFamAVZ60oCAthMqQrqafUGebF8UKuq/ha+e9SVG6YhJoRzurlQXOVf8dHfOhJ0ADMXyFnMc53clg==", "dev": true, "dependencies": { - "@typescript-eslint/types": "7.11.0", - "@typescript-eslint/visitor-keys": "7.11.0" + "@typescript-eslint/types": "8.0.0-alpha.30", + "@typescript-eslint/visitor-keys": "8.0.0-alpha.30" }, "engines": { - "node": "^18.18.0 || >=20.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "type": "opencollective", @@ -5726,12 +5535,12 @@ } }, "node_modules/typescript-eslint/node_modules/@typescript-eslint/types": { - "version": "7.11.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.11.0.tgz", - "integrity": "sha512-MPEsDRZTyCiXkD4vd3zywDCifi7tatc4K37KqTprCvaXptP7Xlpdw0NR2hRJTetG5TxbWDB79Ys4kLmHliEo/w==", + "version": "8.0.0-alpha.30", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.0.0-alpha.30.tgz", + "integrity": "sha512-4WzLlw27SO9pK9UFj/Hu7WGo8WveT0SEiIpFVsV2WwtQmLps6kouwtVCB8GJPZKJyurhZhcqCoQVQFmpv441Vg==", "dev": true, "engines": { - "node": "^18.18.0 || >=20.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "type": "opencollective", @@ -5739,13 +5548,13 @@ } }, "node_modules/typescript-eslint/node_modules/@typescript-eslint/typescript-estree": { - "version": "7.11.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.11.0.tgz", - "integrity": "sha512-cxkhZ2C/iyi3/6U9EPc5y+a6csqHItndvN/CzbNXTNrsC3/ASoYQZEt9uMaEp+xFNjasqQyszp5TumAVKKvJeQ==", + "version": "8.0.0-alpha.30", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.0.0-alpha.30.tgz", + "integrity": "sha512-WSXbc9ZcXI+7yC+6q95u77i8FXz6HOLsw3ST+vMUlFy1lFbXyFL/3e6HDKQCm2Clt0krnoCPiTGvIn+GkYPn4Q==", "dev": true, "dependencies": { - "@typescript-eslint/types": "7.11.0", - "@typescript-eslint/visitor-keys": "7.11.0", + "@typescript-eslint/types": "8.0.0-alpha.30", + "@typescript-eslint/visitor-keys": "8.0.0-alpha.30", "debug": "^4.3.4", "globby": "^11.1.0", "is-glob": "^4.0.3", @@ -5754,7 +5563,7 @@ "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", @@ -5767,16 +5576,16 @@ } }, "node_modules/typescript-eslint/node_modules/@typescript-eslint/visitor-keys": { - "version": "7.11.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.11.0.tgz", - "integrity": "sha512-7syYk4MzjxTEk0g/w3iqtgxnFQspDJfn6QKD36xMuuhTzjcxY7F8EmBLnALjVyaOF1/bVocu3bS/2/F7rXrveQ==", + "version": "8.0.0-alpha.30", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.0.0-alpha.30.tgz", + "integrity": "sha512-XZuNurZxBqmr6ZIRIwWFq7j5RZd6ZlkId/HZEWyfciK+CWoyOxSF9Pv2VXH9Rlu2ZG2PfbhLz2Veszl4Pfn7yA==", "dev": true, "dependencies": { - "@typescript-eslint/types": "7.11.0", + "@typescript-eslint/types": "8.0.0-alpha.30", "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", @@ -5837,7 +5646,6 @@ "version": "4.4.1", "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", - "dev": true, "dependencies": { "punycode": "^2.1.0" } @@ -5924,7 +5732,6 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "dev": true, "dependencies": { "isexe": "^2.0.0" }, @@ -6020,7 +5827,6 @@ "version": "0.1.0", "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", - "dev": true, "engines": { "node": ">=10" }, diff --git a/package.json b/package.json index 6a384cec..802fa5a6 100644 --- a/package.json +++ b/package.json @@ -22,6 +22,8 @@ "bad-words": "^3.0.4", "config": "^3.3.9", "discord.js": "^14.11.0", + "eslint-config-prettier": "^9.1.0", + "eslint-plugin-prettier": "^5.1.3", "jsdom": "^23.2.0", "moment": "^2.29.4", "mongoose": "^8.0.3", @@ -37,11 +39,11 @@ "@types/node-fetch": "^2.6.10", "@typescript-eslint/parser": "^6.18.0", "dotenv": "^16.0.0", - "eslint": "^8.57.0", + "eslint": "^9.4.0", "nodemon": "^3.0.2", "ts-node": "^10.4.0", "typescript": "^5.4.5", - "typescript-eslint": "^7.11.0" + "typescript-eslint": "^8.0.0-alpha.30" }, "engines": { "node": "18.x" From f082f9a47eae0ffe1757d73239658e16bf91ada0 Mon Sep 17 00:00:00 2001 From: ExampleWasTaken <58574351+ExampleWasTaken@users.noreply.github.com> Date: Fri, 14 Jun 2024 15:12:33 +0200 Subject: [PATCH 03/82] add prettier and improve eslint config --- .prettierrc | 15 +++ eslint.config.mjs | 35 +++++-- old.eslintrc.json | 38 ------- package-lock.json | 251 +++++++++++++++++++++------------------------- package.json | 10 +- 5 files changed, 160 insertions(+), 189 deletions(-) create mode 100644 .prettierrc delete mode 100644 old.eslintrc.json diff --git a/.prettierrc b/.prettierrc new file mode 100644 index 00000000..0e2a0078 --- /dev/null +++ b/.prettierrc @@ -0,0 +1,15 @@ +{ + "singleQuote": true, + "printWidth": 120, + "parser": "typescript", + "endOfLine": "auto", + "overrides": [ + { + "See https://github.com/prettier/prettier/issues/2276": "", + "files": "*.json", + "options": { + "parser": "jsonc" + } + } + ] +} \ No newline at end of file diff --git a/eslint.config.mjs b/eslint.config.mjs index fadca2ac..c11b0d4d 100644 --- a/eslint.config.mjs +++ b/eslint.config.mjs @@ -1,21 +1,38 @@ import eslint from '@eslint/js'; import tseslint from 'typescript-eslint'; -import prettierPlugin from 'eslint-plugin-prettier'; -import prettierConfig from 'eslint-config-prettier'; +import recommendedConfig from 'eslint-plugin-prettier/recommended'; export default tseslint.config( eslint.configs.recommended, ...tseslint.configs.recommendedTypeChecked, - prettierConfig, + recommendedConfig, { - plugins: { - prettierPlugin, - }, + name: 'Main Config', languageOptions: { parserOptions: { project: true, tsconfigRootDir: import.meta.dirname, - } + }, + }, + rules: { + 'prettier/prettier': ['error', {}, { usePrettierrc: true }], + + 'no-unused-vars': 'off', // Ensure eslint doesn't care about unused variables. + '@typescript-eslint/no-unused-vars': [ + 'error', + { + varsIgnorePattern: '^_', + argsIgnorePattern: '^_', + }, + ], }, - } -); \ No newline at end of file + }, + { + files: ['**/*.mjs', '**/*.cjs', '**/*.js'], + extends: [tseslint.configs.disableTypeChecked], + }, + { + // DO NOT ADD ANY PROPERTIES TO THIS OBJECT + ignores: ['node_modules', 'build', 'assets'], + }, +); diff --git a/old.eslintrc.json b/old.eslintrc.json deleted file mode 100644 index f86e4cb5..00000000 --- a/old.eslintrc.json +++ /dev/null @@ -1,38 +0,0 @@ -{ - "root": true, - "env": { "browser": true }, - "extends": "@flybywiresim/eslint-config", - "plugins": ["@typescript-eslint"], - "parser": "@typescript-eslint/parser", - "parserOptions": { - "ecmaVersion": 2021, - "sourceType": "script", - "requireConfigFile": false - }, - "settings": { - "import/resolver": { - "node": { - "extensions": [".js", ".jsx", ".ts", ".tsx"] - } - } - }, - "overrides": [ - { - "files": ["*.mjs", "*.ts", "*.d.ts"], - "parserOptions": { "sourceType": "module" } - }, - { - "files": ["*.ts", "*.tsx"], - "rules": { - "no-undef": "off" - } - } - ], - // overrides airbnb, use sparingly - "rules": { - "linebreak-style": "off", - "object-curly-newline": ["error", { "multiline": true }], - "max-len": "off", - "spaced-comment": "off" - } -} diff --git a/package-lock.json b/package-lock.json index af2c8b80..7ace498c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -16,8 +16,6 @@ "bad-words": "^3.0.4", "config": "^3.3.9", "discord.js": "^14.11.0", - "eslint-config-prettier": "^9.1.0", - "eslint-plugin-prettier": "^5.1.3", "jsdom": "^23.2.0", "moment": "^2.29.4", "mongoose": "^8.0.3", @@ -31,10 +29,12 @@ "@types/jsdom": "^21.1.6", "@types/node": "^18.0.0", "@types/node-fetch": "^2.6.10", - "@typescript-eslint/parser": "^6.18.0", "dotenv": "^16.0.0", "eslint": "^9.4.0", + "eslint-config-prettier": "^9.1.0", + "eslint-plugin-prettier": "^5.1.3", "nodemon": "^3.0.2", + "prettier": "^3.3.2", "ts-node": "^10.4.0", "typescript": "^5.4.5", "typescript-eslint": "^8.0.0-alpha.30" @@ -47,6 +47,7 @@ "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" } @@ -1600,6 +1601,7 @@ "version": "4.4.0", "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", "integrity": "sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==", + "dev": true, "dependencies": { "eslint-visitor-keys": "^3.3.0" }, @@ -1614,6 +1616,7 @@ "version": "4.10.0", "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.10.0.tgz", "integrity": "sha512-Cu96Sd2By9mCNTx2iyKOmq10v22jUVQv0lQnlGNy16oE9589yE+QADPbrMGCkA51cKZSg3Pu/aTJVTGfL/qjUA==", + "dev": true, "engines": { "node": "^12.0.0 || ^14.0.0 || >=16.0.0" } @@ -1622,6 +1625,7 @@ "version": "0.15.1", "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.15.1.tgz", "integrity": "sha512-K4gzNq+yymn/EVsXYmf+SBcBro8MTf+aXJZUphM96CdzUEr+ClGDvAbpmaEK+cGVigVXIgs9gNmvHAlrzzY5JQ==", + "dev": true, "dependencies": { "@eslint/object-schema": "^2.1.3", "debug": "^4.3.1", @@ -1635,6 +1639,7 @@ "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -1644,6 +1649,7 @@ "version": "3.1.2", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, "dependencies": { "brace-expansion": "^1.1.7" }, @@ -1655,6 +1661,7 @@ "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, "dependencies": { "ajv": "^6.12.4", "debug": "^4.3.2", @@ -1677,6 +1684,7 @@ "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -1686,6 +1694,7 @@ "version": "3.1.2", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, "dependencies": { "brace-expansion": "^1.1.7" }, @@ -1697,6 +1706,7 @@ "version": "9.4.0", "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.4.0.tgz", "integrity": "sha512-fdI7VJjP3Rvc70lC4xkFXHB0fiPeojiL1PxVG6t1ZvXQrarj893PweuBTujxDUFk0Fxj4R7PIIAZ/aiiyZPZcg==", + "dev": true, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } @@ -1705,6 +1715,7 @@ "version": "2.1.4", "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-2.1.4.tgz", "integrity": "sha512-BsWiH1yFGjXXS2yvrf5LyuoSIIbPrGUWob917o+BTKuZ7qJdxX8aJLRxs1fS9n6r7vESrq1OUqb68dANcFXuQQ==", + "dev": true, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } @@ -1737,6 +1748,7 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", + "dev": true, "engines": { "node": ">=12.22" }, @@ -1749,6 +1761,7 @@ "version": "0.3.0", "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.3.0.tgz", "integrity": "sha512-d2CGZR2o7fS6sWB7DG/3a95bGKQyHMACZ5aW8qGkkqQpUoZV6C0X7Pc7l4ZNMZkfNBf4VWNe9E1jRsf0G146Ew==", + "dev": true, "engines": { "node": ">=18.18" }, @@ -1794,6 +1807,7 @@ "version": "2.1.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dev": true, "dependencies": { "@nodelib/fs.stat": "2.0.5", "run-parallel": "^1.1.9" @@ -1806,6 +1820,7 @@ "version": "2.0.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "dev": true, "engines": { "node": ">= 8" } @@ -1814,6 +1829,7 @@ "version": "1.2.8", "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dev": true, "dependencies": { "@nodelib/fs.scandir": "2.1.5", "fastq": "^1.6.0" @@ -1878,6 +1894,7 @@ "version": "0.1.1", "resolved": "https://registry.npmjs.org/@pkgr/core/-/core-0.1.1.tgz", "integrity": "sha512-cq8o4cWH0ibXh9VGi5P20Tu9XF/0fFXl9EUinr9QfTM7a7p0oTA4iJRCQWppXR1Pg8dSM0UCItCkPwsk9qWWYA==", + "dev": true, "engines": { "node": "^12.20.0 || ^14.18.0 || >=16.0.0" }, @@ -2650,51 +2667,6 @@ "@types/node": "*" } }, - "node_modules/@typescript-eslint/parser": { - "version": "6.18.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-6.18.1.tgz", - "integrity": "sha512-zct/MdJnVaRRNy9e84XnVtRv9Vf91/qqe+hZJtKanjojud4wAVy/7lXxJmMyX6X6J+xc6c//YEWvpeif8cAhWA==", - "dev": true, - "dependencies": { - "@typescript-eslint/scope-manager": "6.18.1", - "@typescript-eslint/types": "6.18.1", - "@typescript-eslint/typescript-estree": "6.18.1", - "@typescript-eslint/visitor-keys": "6.18.1", - "debug": "^4.3.4" - }, - "engines": { - "node": "^16.0.0 || >=18.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^7.0.0 || ^8.0.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@typescript-eslint/scope-manager": { - "version": "6.18.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.18.1.tgz", - "integrity": "sha512-BgdBwXPFmZzaZUuw6wKiHKIovms97a7eTImjkXCZE04TGHysG+0hDQPmygyvgtkoB/aOQwSM/nWv3LzrOIQOBw==", - "dev": true, - "dependencies": { - "@typescript-eslint/types": "6.18.1", - "@typescript-eslint/visitor-keys": "6.18.1" - }, - "engines": { - "node": "^16.0.0 || >=18.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, "node_modules/@typescript-eslint/type-utils": { "version": "8.0.0-alpha.30", "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.0.0-alpha.30.tgz", @@ -2792,47 +2764,6 @@ "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/@typescript-eslint/types": { - "version": "6.18.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.18.1.tgz", - "integrity": "sha512-4TuMAe+tc5oA7wwfqMtB0Y5OrREPF1GeJBAjqwgZh1lEMH5PJQgWgHGfYufVB51LtjD+peZylmeyxUXPfENLCw==", - "dev": true, - "engines": { - "node": "^16.0.0 || >=18.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@typescript-eslint/typescript-estree": { - "version": "6.18.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.18.1.tgz", - "integrity": "sha512-fv9B94UAhywPRhUeeV/v+3SBDvcPiLxRZJw/xZeeGgRLQZ6rLMG+8krrJUyIf6s1ecWTzlsbp0rlw7n9sjufHA==", - "dev": true, - "dependencies": { - "@typescript-eslint/types": "6.18.1", - "@typescript-eslint/visitor-keys": "6.18.1", - "debug": "^4.3.4", - "globby": "^11.1.0", - "is-glob": "^4.0.3", - "minimatch": "9.0.3", - "semver": "^7.5.4", - "ts-api-utils": "^1.0.1" - }, - "engines": { - "node": "^16.0.0 || >=18.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, "node_modules/@typescript-eslint/utils": { "version": "8.0.0-alpha.30", "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.0.0-alpha.30.tgz", @@ -2945,23 +2876,6 @@ "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/@typescript-eslint/visitor-keys": { - "version": "6.18.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.18.1.tgz", - "integrity": "sha512-/kvt0C5lRqGoCfsbmm7/CwMqoSkY3zzHLIjdhHZQW3VFrnz7ATecOHR7nb7V+xn4286MBxfnQfQhAmCI0u+bJA==", - "dev": true, - "dependencies": { - "@typescript-eslint/types": "6.18.1", - "eslint-visitor-keys": "^3.4.1" - }, - "engines": { - "node": "^16.0.0 || >=18.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, "node_modules/@vladfrangu/async_event_emitter": { "version": "2.2.4", "resolved": "https://registry.npmjs.org/@vladfrangu/async_event_emitter/-/async_event_emitter-2.2.4.tgz", @@ -2981,6 +2895,7 @@ "version": "8.11.3", "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.3.tgz", "integrity": "sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==", + "dev": true, "bin": { "acorn": "bin/acorn" }, @@ -2992,6 +2907,7 @@ "version": "5.3.2", "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true, "peerDependencies": { "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" } @@ -3020,6 +2936,7 @@ "version": "6.12.6", "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, "dependencies": { "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", @@ -3035,6 +2952,7 @@ "version": "5.0.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, "engines": { "node": ">=8" } @@ -3043,6 +2961,7 @@ "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, "dependencies": { "color-convert": "^2.0.1" }, @@ -3075,7 +2994,8 @@ "node_modules/argparse": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==" + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true }, "node_modules/array-union": { "version": "2.1.0", @@ -3115,7 +3035,8 @@ "node_modules/balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true }, "node_modules/base64-js": { "version": "1.5.1", @@ -3217,6 +3138,7 @@ "version": "3.1.0", "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true, "engines": { "node": ">=6" } @@ -3225,6 +3147,7 @@ "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" @@ -3276,6 +3199,7 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, "dependencies": { "color-name": "~1.1.4" }, @@ -3333,7 +3257,8 @@ "node_modules/concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==" + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true }, "node_modules/config": { "version": "3.3.10", @@ -3367,6 +3292,7 @@ "version": "7.0.3", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dev": true, "dependencies": { "path-key": "^3.1.0", "shebang-command": "^2.0.0", @@ -3479,7 +3405,8 @@ "node_modules/deep-is": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", - "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==" + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true }, "node_modules/delayed-stream": { "version": "1.0.0", @@ -3576,6 +3503,7 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true, "engines": { "node": ">=10" }, @@ -3587,6 +3515,7 @@ "version": "9.4.0", "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.4.0.tgz", "integrity": "sha512-sjc7Y8cUD1IlwYcTS9qPSvGjAC8Ne9LctpxKKu3x/1IC9bnOg98Zy6GxEJUfr1NojMgVPlyANXYns8oE2c1TAA==", + "dev": true, "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/regexpp": "^4.6.1", @@ -3637,6 +3566,7 @@ "version": "9.1.0", "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-9.1.0.tgz", "integrity": "sha512-NSWl5BFQWEPi1j4TjVNItzYV7dZXZ+wP6I6ZhrBGpChQhZRUaElihE9uRRkcbRnNb76UMKDF3r+WTmNcGPKsqw==", + "dev": true, "bin": { "eslint-config-prettier": "bin/cli.js" }, @@ -3648,6 +3578,7 @@ "version": "5.1.3", "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-5.1.3.tgz", "integrity": "sha512-C9GCVAs4Eq7ZC/XFQHITLiHJxQngdtraXaM+LoUFoFp/lHNl2Zn8f3WQbe9HvTBBQ9YnKFB0/2Ajdqwo5D1EAw==", + "dev": true, "dependencies": { "prettier-linter-helpers": "^1.0.0", "synckit": "^0.8.6" @@ -3677,6 +3608,7 @@ "version": "8.0.1", "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.0.1.tgz", "integrity": "sha512-pL8XjgP4ZOmmwfFE8mEhSxA7ZY4C+LWyqjQ3o4yWkkmD0qcMT9kkW3zWHOczhWcjTSgqycYAgwSlXvZltv65og==", + "dev": true, "dependencies": { "esrecurse": "^4.3.0", "estraverse": "^5.2.0" @@ -3692,6 +3624,7 @@ "version": "3.4.3", "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "dev": true, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" }, @@ -3703,6 +3636,7 @@ "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -3712,6 +3646,7 @@ "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, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, @@ -3723,6 +3658,7 @@ "version": "6.0.2", "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, "dependencies": { "is-glob": "^4.0.3" }, @@ -3734,6 +3670,7 @@ "version": "3.1.2", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, "dependencies": { "brace-expansion": "^1.1.7" }, @@ -3745,6 +3682,7 @@ "version": "10.0.1", "resolved": "https://registry.npmjs.org/espree/-/espree-10.0.1.tgz", "integrity": "sha512-MWkrWZbJsL2UwnjxTX3gG8FneachS/Mwg7tdGXce011sJd5b0JG54vat5KHnfSBODZ3Wvzd2WnjxyzsRoVv+ww==", + "dev": true, "dependencies": { "acorn": "^8.11.3", "acorn-jsx": "^5.3.2", @@ -3761,6 +3699,7 @@ "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, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, @@ -3772,6 +3711,7 @@ "version": "1.5.0", "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.5.0.tgz", "integrity": "sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==", + "dev": true, "dependencies": { "estraverse": "^5.1.0" }, @@ -3783,6 +3723,7 @@ "version": "4.3.0", "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, "dependencies": { "estraverse": "^5.2.0" }, @@ -3794,6 +3735,7 @@ "version": "5.3.0", "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, "engines": { "node": ">=4.0" } @@ -3802,6 +3744,7 @@ "version": "2.0.3", "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true, "engines": { "node": ">=0.10.0" } @@ -3822,7 +3765,8 @@ "node_modules/fast-diff": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.3.0.tgz", - "integrity": "sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw==" + "integrity": "sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw==", + "dev": true }, "node_modules/fast-glob": { "version": "3.3.2", @@ -3843,12 +3787,14 @@ "node_modules/fast-json-stable-stringify": { "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==" + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true }, "node_modules/fast-levenshtein": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", - "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==" + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", + "dev": true }, "node_modules/fast-xml-parser": { "version": "4.2.5", @@ -3875,6 +3821,7 @@ "version": "1.16.0", "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.16.0.tgz", "integrity": "sha512-ifCoaXsDrsdkWTtiNJX5uzHDsrck5TzfKKDcuFFTIrrc/BS076qgEIfoIy1VeZqViznfKiysPYTh/QeHtnIsYA==", + "dev": true, "dependencies": { "reusify": "^1.0.4" } @@ -3888,6 +3835,7 @@ "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, "dependencies": { "flat-cache": "^4.0.0" }, @@ -3911,6 +3859,7 @@ "version": "5.0.0", "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, "dependencies": { "locate-path": "^6.0.0", "path-exists": "^4.0.0" @@ -3926,6 +3875,7 @@ "version": "4.0.1", "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz", "integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==", + "dev": true, "dependencies": { "flatted": "^3.2.9", "keyv": "^4.5.4" @@ -3937,7 +3887,8 @@ "node_modules/flatted": { "version": "3.3.1", "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.1.tgz", - "integrity": "sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==" + "integrity": "sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==", + "dev": true }, "node_modules/fn.name": { "version": "1.1.0", @@ -3973,6 +3924,7 @@ "version": "14.0.0", "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz", "integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==", + "dev": true, "engines": { "node": ">=18" }, @@ -4010,6 +3962,7 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, "engines": { "node": ">=8" } @@ -4091,6 +4044,7 @@ "version": "5.3.1", "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.1.tgz", "integrity": "sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw==", + "dev": true, "engines": { "node": ">= 4" } @@ -4105,6 +4059,7 @@ "version": "3.3.0", "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "dev": true, "dependencies": { "parent-module": "^1.0.0", "resolve-from": "^4.0.0" @@ -4120,6 +4075,7 @@ "version": "0.1.4", "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "dev": true, "engines": { "node": ">=0.8.19" } @@ -4155,6 +4111,7 @@ "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, "engines": { "node": ">=0.10.0" } @@ -4163,6 +4120,7 @@ "version": "4.0.3", "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, "dependencies": { "is-extglob": "^2.1.1" }, @@ -4183,6 +4141,7 @@ "version": "3.0.3", "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", + "dev": true, "engines": { "node": ">=8" } @@ -4206,12 +4165,14 @@ "node_modules/isexe": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==" + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true }, "node_modules/js-yaml": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, "dependencies": { "argparse": "^2.0.1" }, @@ -4304,17 +4265,20 @@ "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==" + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", + "dev": true }, "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==" + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true }, "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==" + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", + "dev": true }, "node_modules/json5": { "version": "2.2.3", @@ -4339,6 +4303,7 @@ "version": "4.5.4", "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", + "dev": true, "dependencies": { "json-buffer": "3.0.1" } @@ -4352,6 +4317,7 @@ "version": "0.4.1", "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, "dependencies": { "prelude-ls": "^1.2.1", "type-check": "~0.4.0" @@ -4364,6 +4330,7 @@ "version": "6.0.0", "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, "dependencies": { "p-locate": "^5.0.0" }, @@ -4382,7 +4349,8 @@ "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==" + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "dev": true }, "node_modules/lodash.snakecase": { "version": "4.1.1", @@ -4475,21 +4443,6 @@ "node": ">= 0.6" } }, - "node_modules/minimatch": { - "version": "9.0.3", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz", - "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==", - "dev": true, - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, "node_modules/moment": { "version": "2.30.1", "resolved": "https://registry.npmjs.org/moment/-/moment-2.30.1.tgz", @@ -4630,7 +4583,8 @@ "node_modules/natural-compare": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", - "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==" + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "dev": true }, "node_modules/node-fetch": { "version": "2.7.0", @@ -4790,6 +4744,7 @@ "version": "0.9.3", "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.3.tgz", "integrity": "sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg==", + "dev": true, "dependencies": { "@aashutoshrathi/word-wrap": "^1.2.3", "deep-is": "^0.1.3", @@ -4806,6 +4761,7 @@ "version": "3.1.0", "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, "dependencies": { "yocto-queue": "^0.1.0" }, @@ -4820,6 +4776,7 @@ "version": "5.0.0", "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, "dependencies": { "p-limit": "^3.0.2" }, @@ -4834,6 +4791,7 @@ "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, "dependencies": { "callsites": "^3.0.0" }, @@ -4856,6 +4814,7 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, "engines": { "node": ">=8" } @@ -4864,6 +4823,7 @@ "version": "3.1.1", "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, "engines": { "node": ">=8" } @@ -4893,6 +4853,7 @@ "version": "1.2.1", "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true, "engines": { "node": ">= 0.8.0" } @@ -4901,7 +4862,7 @@ "version": "3.3.2", "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.3.2.tgz", "integrity": "sha512-rAVeHYMcv8ATV5d508CFdn+8/pHPpXeIid1DdrPwXnaAdH7cqjVbpJaT5eq4yRAFU/lsbwYwSF/n5iNrdJHPQA==", - "peer": true, + "dev": true, "bin": { "prettier": "bin/prettier.cjs" }, @@ -4916,6 +4877,7 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz", "integrity": "sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==", + "dev": true, "dependencies": { "fast-diff": "^1.1.2" }, @@ -4951,6 +4913,7 @@ "version": "1.2.3", "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "dev": true, "funding": [ { "type": "github", @@ -5008,6 +4971,7 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true, "engines": { "node": ">=4" } @@ -5016,6 +4980,7 @@ "version": "1.0.4", "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "dev": true, "engines": { "iojs": ">=1.0.0", "node": ">=0.10.0" @@ -5030,6 +4995,7 @@ "version": "1.2.0", "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, "funding": [ { "type": "github", @@ -5107,6 +5073,7 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, "dependencies": { "shebang-regex": "^3.0.0" }, @@ -5118,6 +5085,7 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, "engines": { "node": ">=8" } @@ -5223,6 +5191,7 @@ "version": "6.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, "dependencies": { "ansi-regex": "^5.0.1" }, @@ -5234,6 +5203,7 @@ "version": "3.1.1", "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true, "engines": { "node": ">=8" }, @@ -5250,6 +5220,7 @@ "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, "dependencies": { "has-flag": "^4.0.0" }, @@ -5266,6 +5237,7 @@ "version": "0.8.8", "resolved": "https://registry.npmjs.org/synckit/-/synckit-0.8.8.tgz", "integrity": "sha512-HwOKAP7Wc5aRGYdKH+dw0PRRpbO841v2DENBtjnR5HFWoiNByAl7vrx3p0G/rCyYXQsrxqtX48TImFtPcIHSpQ==", + "dev": true, "dependencies": { "@pkgr/core": "^0.1.0", "tslib": "^2.6.2" @@ -5285,7 +5257,8 @@ "node_modules/text-table": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", - "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==" + "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", + "dev": true }, "node_modules/to-regex-range": { "version": "5.0.1", @@ -5413,6 +5386,7 @@ "version": "0.4.0", "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, "dependencies": { "prelude-ls": "^1.2.1" }, @@ -5646,6 +5620,7 @@ "version": "4.4.1", "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, "dependencies": { "punycode": "^2.1.0" } @@ -5732,6 +5707,7 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, "dependencies": { "isexe": "^2.0.0" }, @@ -5827,6 +5803,7 @@ "version": "0.1.0", "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true, "engines": { "node": ">=10" }, diff --git a/package.json b/package.json index 802fa5a6..da54ab9b 100644 --- a/package.json +++ b/package.json @@ -9,8 +9,8 @@ "dev": "nodemon --config nodemon.json src/index.ts", "build": "tsc", "build:digitalocean": "npm ci --include=dev && npm run build", - "lint": "eslint \"src/**/**/*.ts\"", - "lint-fix": "eslint \"src/**/**/*.ts\" --fix" + "lint": "eslint", + "lint-fix": "eslint --fix" }, "author": "FlyByWire Simulations", "license": "AGPL-3.0", @@ -22,8 +22,6 @@ "bad-words": "^3.0.4", "config": "^3.3.9", "discord.js": "^14.11.0", - "eslint-config-prettier": "^9.1.0", - "eslint-plugin-prettier": "^5.1.3", "jsdom": "^23.2.0", "moment": "^2.29.4", "mongoose": "^8.0.3", @@ -37,10 +35,12 @@ "@types/jsdom": "^21.1.6", "@types/node": "^18.0.0", "@types/node-fetch": "^2.6.10", - "@typescript-eslint/parser": "^6.18.0", "dotenv": "^16.0.0", "eslint": "^9.4.0", + "eslint-config-prettier": "^9.1.0", + "eslint-plugin-prettier": "^5.1.3", "nodemon": "^3.0.2", + "prettier": "^3.3.2", "ts-node": "^10.4.0", "typescript": "^5.4.5", "typescript-eslint": "^8.0.0-alpha.30" From 0adefb7b263386e122d4def3c11fb6affd886e00 Mon Sep 17 00:00:00 2001 From: ExampleWasTaken <58574351+ExampleWasTaken@users.noreply.github.com> Date: Fri, 14 Jun 2024 15:16:11 +0200 Subject: [PATCH 04/82] eslint --fix including prettier write --- src/client.ts | 9 +- src/commands/context/index.ts | 6 +- src/commands/context/message/reportMessage.ts | 119 ++++++----- src/commands/context/user/userInfo.ts | 6 +- src/commands/moderation/cacheUpdate.ts | 61 +++--- src/commands/moderation/clearMessages.ts | 37 +++- src/commands/moderation/commandTable.ts | 14 +- src/commands/moderation/deployCommands.ts | 43 ++-- src/commands/moderation/faq/faq.ts | 28 +-- .../moderation/faq/functions/addFaq.ts | 101 +++++----- .../moderation/faq/functions/faqPrintAll.ts | 4 +- .../moderation/faq/functions/listFaq.ts | 43 ++-- .../moderation/faq/functions/removeFaq.ts | 54 +++-- .../moderation/infractions/functions/ban.ts | 160 ++++++++------- .../functions/deleteInfractions.ts | 61 +++--- .../infractions/functions/listInfractions.ts | 123 ++++++------ .../infractions/functions/removeTimeout.ts | 80 ++++---- .../infractions/functions/timeout.ts | 189 +++++++++-------- .../infractions/functions/unbanInfractions.ts | 78 +++---- .../infractions/functions/userNote.ts | 70 +++---- .../moderation/infractions/functions/warn.ts | 139 +++++++------ .../moderation/infractions/infractions.ts | 54 ++--- src/commands/moderation/listRoleUsers.ts | 29 ++- src/commands/moderation/roleAssignment.ts | 14 +- src/commands/moderation/rules.ts | 6 +- .../moderation/slowmode/functions/disable.ts | 32 ++- .../moderation/slowmode/functions/set.ts | 39 +++- src/commands/moderation/slowmode/slowmode.ts | 98 ++++++--- src/commands/moderation/welcome.ts | 5 +- src/commands/moderation/whois.ts | 20 +- src/commands/utils/avatar.ts | 16 +- src/commands/utils/birthday/birthday.ts | 22 +- .../utils/birthday/functions/listBirthday.ts | 19 +- .../birthday/functions/removeBirthday.ts | 20 +- .../utils/birthday/functions/setBirthday.ts | 9 +- src/commands/utils/count.ts | 4 +- src/commands/utils/docSearch.ts | 20 +- .../github/functions/githubPullRequest.ts | 4 +- .../github/functions/handleGithubIssue.ts | 4 +- src/commands/utils/github/github.ts | 66 +++--- src/commands/utils/help.ts | 93 ++++----- .../locate/functions/filterSearchResults.ts | 4 +- .../utils/locate/functions/handleCommand.ts | 23 ++- src/commands/utils/locate/locate.ts | 40 ++-- .../utils/locate/panels/a32nx/a32nx-panels.ts | 70 ++++++- .../utils/locate/panels/a32nx/flyPad.ts | 6 +- .../utils/locate/panels/a32nx/front-panel.ts | 39 +--- .../utils/locate/panels/a32nx/glareshield.ts | 6 +- .../utils/locate/panels/a32nx/overhead.ts | 137 ++----------- .../utils/locate/panels/a32nx/pedestal.ts | 79 ++------ .../locate/panels/a32nx/rear-cb-panel.ts | 5 +- src/commands/utils/metar.ts | 25 ++- src/commands/utils/ping.ts | 16 +- src/commands/utils/reportedIssues.ts | 50 +++-- src/commands/utils/roleInfo.ts | 16 +- src/commands/utils/searchFaq.ts | 29 +-- src/commands/utils/simbriefData.ts | 68 ++++--- src/commands/utils/station.ts | 27 ++- src/commands/utils/taf.ts | 22 +- .../vatsim/functions/vatsimControllers.ts | 72 ++++--- .../utils/vatsim/functions/vatsimEvents.ts | 102 +++++----- .../utils/vatsim/functions/vatsimObservers.ts | 69 ++++--- .../utils/vatsim/functions/vatsimPilots.ts | 46 +++-- .../utils/vatsim/functions/vatsimStats.ts | 99 +++++---- src/commands/utils/vatsim/vatsim.ts | 51 ++--- src/commands/utils/wolframAlpha.ts | 25 +-- src/commands/utils/zulu.ts | 27 ++- src/events/buttonHandlers/buttonHandler.ts | 28 +-- .../functions/handleRoleAssignment.ts | 7 +- src/events/contextInteractionHandler.ts | 8 +- src/events/logging/detectBan.ts | 190 +++++++++--------- src/events/logging/messageDelete.ts | 17 +- src/events/logging/messageUpdate.ts | 22 +- src/events/logging/scamLogs.ts | 18 +- src/events/ready.ts | 43 ++-- src/events/slashCommandHandler.ts | 8 +- src/lib/config.ts | 94 ++++----- src/lib/contextMenuCommand.ts | 12 +- src/lib/durationInEnglish.ts | 6 +- src/lib/embed.ts | 12 +- src/lib/events.ts | 6 +- src/lib/genericEmbedPagination.ts | 33 ++- src/lib/infractionEmbedPagination.ts | 47 ++++- src/lib/logger.ts | 4 +- src/lib/replies.ts | 12 +- src/lib/schedulerJobs/autoDisableSlowMode.ts | 87 ++++---- src/lib/schedulerJobs/postBirthdays.ts | 12 +- src/lib/schedulerJobs/sendHeartbeat.ts | 2 +- src/lib/slashCommand.ts | 37 ++-- src/scripts/deployCommands.ts | 14 +- 90 files changed, 2099 insertions(+), 1772 deletions(-) diff --git a/src/client.ts b/src/client.ts index 3801d69a..b1177f80 100644 --- a/src/client.ts +++ b/src/client.ts @@ -26,11 +26,10 @@ export const client = new Client({ registerEvents(client, Events); -client.login(process.env.BOT_SECRET) - .catch((e) => { - Logger.error(e); - process.exit(1); - }); +client.login(process.env.BOT_SECRET).catch((e) => { + Logger.error(e); + process.exit(1); +}); const handleTermination = async () => { Logger.info('Terminating bot...'); diff --git a/src/commands/context/index.ts b/src/commands/context/index.ts index 1346d3e3..d3e875a0 100644 --- a/src/commands/context/index.ts +++ b/src/commands/context/index.ts @@ -3,10 +3,6 @@ import userInfo from './user/userInfo'; import reportMessage from './message/reportMessage'; import listInfractions from './user/listInfractions'; -const contextArray: ContextMenuCommand[] = [ - userInfo, - reportMessage, - listInfractions, -]; +const contextArray: ContextMenuCommand[] = [userInfo, reportMessage, listInfractions]; export default contextArray; diff --git a/src/commands/context/message/reportMessage.ts b/src/commands/context/message/reportMessage.ts index ef85cd0b..d0edead0 100644 --- a/src/commands/context/message/reportMessage.ts +++ b/src/commands/context/message/reportMessage.ts @@ -2,7 +2,8 @@ import { ActionRowBuilder, ApplicationCommandType, ContextMenuCommandInteraction, - ModalBuilder, TextChannel, + ModalBuilder, + TextChannel, TextInputBuilder, TextInputStyle, Colors, @@ -15,52 +16,57 @@ const data = contextMenuCommandStructure({ type: ApplicationCommandType.Message, }); -const reportedMessageEmbed = (targetMessage: any, interaction: ContextMenuCommandInteraction<'cached'>, messageContent: string, commentContent: string, formattedDate: string) => makeEmbed({ - author: { - name: `[REPORTED MESSAGE] ${targetMessage.author.tag}`, - iconURL: targetMessage.author.displayAvatarURL(), - }, - fields: [ - { - name: 'Reported by', - value: interaction.user.toString(), - inline: true, +const reportedMessageEmbed = ( + targetMessage: any, + interaction: ContextMenuCommandInteraction<'cached'>, + messageContent: string, + commentContent: string, + formattedDate: string, +) => + makeEmbed({ + author: { + name: `[REPORTED MESSAGE] ${targetMessage.author.tag}`, + iconURL: targetMessage.author.displayAvatarURL(), }, - { - name: 'Message Author', - value: targetMessage.author.toString(), - inline: true, - }, - { - name: 'Message Content', - value: messageContent, - inline: false, - }, - { - name: 'Link to Message', - value: targetMessage.url, - inline: false, - }, - { - name: 'Additional Comments', - value: commentContent, - inline: false, - }, - { - name: 'Reported at', - value: formattedDate, - inline: false, - }, - ], - color: Colors.Red, - footer: { text: `Reported Users ID: ${targetMessage.author.id}` }, -}); + fields: [ + { + name: 'Reported by', + value: interaction.user.toString(), + inline: true, + }, + { + name: 'Message Author', + value: targetMessage.author.toString(), + inline: true, + }, + { + name: 'Message Content', + value: messageContent, + inline: false, + }, + { + name: 'Link to Message', + value: targetMessage.url, + inline: false, + }, + { + name: 'Additional Comments', + value: commentContent, + inline: false, + }, + { + name: 'Reported at', + value: formattedDate, + inline: false, + }, + ], + color: Colors.Red, + footer: { text: `Reported Users ID: ${targetMessage.author.id}` }, + }); export default contextMenuCommand(data, async ({ interaction }) => { const currentDate = new Date(); - const formattedDate: string = moment(currentDate) - .utcOffset(0) - .format(); + const formattedDate: string = moment(currentDate).utcOffset(0).format(); const scamReportLogs = interaction.guild.channels.resolve(constantsConfig.channels.SCAM_REPORT_LOGS) as TextChannel; const modRoleId = constantsConfig.roles.MODERATION_TEAM; @@ -126,10 +132,8 @@ export default contextMenuCommand(data, async ({ interaction }) => { //Modal sent - const filter = (interaction: { - customId: string; - user: { id: any; }; - }) => interaction.customId === 'reportMessageModal' && interaction.user.id; + const filter = (interaction: { customId: string; user: { id: any } }) => + interaction.customId === 'reportMessageModal' && interaction.user.id; let commentContent = 'No additional comments provided.'; @@ -160,7 +164,10 @@ export default contextMenuCommand(data, async ({ interaction }) => { //Send a follow-up message to the user if they are part of the staff role group - if (constantsConfig.roleGroups.SUPPORT && constantsConfig.roleGroups.SUPPORT.some((role) => interaction.member.roles.cache.has(role))) { + if ( + constantsConfig.roleGroups.SUPPORT && + constantsConfig.roleGroups.SUPPORT.some((role) => interaction.member.roles.cache.has(role)) + ) { await interaction.followUp({ content: `Is your report urgent and requires immediate attention from the <@&${modRoleId}>? If so please click yes and I will ping the <@&${modRoleId}>. If not, click no.`, components: [ @@ -186,7 +193,7 @@ export default contextMenuCommand(data, async ({ interaction }) => { }); try { - // Handle the button interactions + // Handle the button interactions const modPingButtonInteraction = await interaction.channel.awaitMessageComponent({ filter: (i) => i.customId === 'pingModerationTeamYes' || i.customId === 'pingModerationTeamNo', time: 60000, @@ -231,7 +238,11 @@ export default contextMenuCommand(data, async ({ interaction }) => { content: 'Unable to find the mod alerts channel. Please contact a Moderator.', ephemeral: true, }); - await scamReportLogs.send({ embeds: [reportedMessageEmbed(targetMessage, interaction, messageContent, commentContent, formattedDate)] }); + await scamReportLogs.send({ + embeds: [ + reportedMessageEmbed(targetMessage, interaction, messageContent, commentContent, formattedDate), + ], + }); return; } @@ -286,7 +297,9 @@ export default contextMenuCommand(data, async ({ interaction }) => { content: `Your report has been submitted and shared in ${modAlertsChannel}.`, ephemeral: true, }); - await scamReportLogs.send({ content: `Reported message from ${interaction.user.toString()} has been shared in ${modAlertsChannel}.` }); + await scamReportLogs.send({ + content: `Reported message from ${interaction.user.toString()} has been shared in ${modAlertsChannel}.`, + }); } if (shareReportButtonInteraction.customId === 'shareReportNo') { @@ -303,5 +316,7 @@ export default contextMenuCommand(data, async ({ interaction }) => { }); } } - await scamReportLogs.send({ embeds: [reportedMessageEmbed(targetMessage, interaction, messageContent, commentContent, formattedDate)] }); + await scamReportLogs.send({ + embeds: [reportedMessageEmbed(targetMessage, interaction, messageContent, commentContent, formattedDate)], + }); }); diff --git a/src/commands/context/user/userInfo.ts b/src/commands/context/user/userInfo.ts index 0d25a548..d4e6c654 100644 --- a/src/commands/context/user/userInfo.ts +++ b/src/commands/context/user/userInfo.ts @@ -65,7 +65,11 @@ export default contextMenuCommand(data, async ({ interaction }) => { }, { name: 'Permissions', - value: targetMember.permissions.toArray().join(', ').toLowerCase().replace(/_/g, ' ') + value: targetMember.permissions + .toArray() + .join(', ') + .toLowerCase() + .replace(/_/g, ' ') .replace(/(^\w)|(\s+\w)/g, (char) => char.toUpperCase()), }, ], diff --git a/src/commands/moderation/cacheUpdate.ts b/src/commands/moderation/cacheUpdate.ts index f16c3d72..caab4f9b 100644 --- a/src/commands/moderation/cacheUpdate.ts +++ b/src/commands/moderation/cacheUpdate.ts @@ -31,19 +31,26 @@ const data = slashCommandStructure({ ], }); -const cacheUpdateEmbed = (action: string, fields: any, color: number) => makeEmbed({ - title: `Cache Update - ${action}`, - fields, - color, -}); +const cacheUpdateEmbed = (action: string, fields: any, color: number) => + makeEmbed({ + title: `Cache Update - ${action}`, + fields, + color, + }); -const noChannelEmbed = (action:string, channelName: string) => makeEmbed({ - title: `Sticky Message - ${action} - No ${channelName} channel`, - description: `The command was successful, but no message to ${channelName} was sent. Please check the channel still exists.`, - color: Colors.Yellow, -}); +const noChannelEmbed = (action: string, channelName: string) => + makeEmbed({ + title: `Sticky Message - ${action} - No ${channelName} channel`, + description: `The command was successful, but no message to ${channelName} was sent. Please check the channel still exists.`, + color: Colors.Yellow, + }); -const cacheUpdateEmbedField = (moderator: string, cacheType: string, cacheSize: string, duration: string): EmbedField[] => [ +const cacheUpdateEmbedField = ( + moderator: string, + cacheType: string, + cacheSize: string, + duration: string, +): EmbedField[] => [ { name: 'Type', value: cacheType, @@ -95,26 +102,34 @@ export default slashCommand(data, async ({ interaction }) => { if (cacheSize !== undefined) { await interaction.editReply({ - embeds: [cacheUpdateEmbed(interaction.options.getSubcommand(), - cacheUpdateEmbedField( - interaction.user.tag, + embeds: [ + cacheUpdateEmbed( interaction.options.getSubcommand(), - cacheSize.toString(), - duration, + cacheUpdateEmbedField( + interaction.user.tag, + interaction.options.getSubcommand(), + cacheSize.toString(), + duration, + ), + Colors.Green, ), - Colors.Green)], + ], }); try { await modLogsChannel.send({ - embeds: [cacheUpdateEmbed(interaction.options.getSubcommand(), - cacheUpdateEmbedField( - interaction.user.tag, + embeds: [ + cacheUpdateEmbed( interaction.options.getSubcommand(), - cacheSize.toString(), - duration, + cacheUpdateEmbedField( + interaction.user.tag, + interaction.options.getSubcommand(), + cacheSize.toString(), + duration, + ), + Colors.Green, ), - Colors.Green)], + ], }); } catch (error) { await interaction.followUp({ embeds: [noChannelEmbed(interaction.options.getSubcommand(), 'mod-log')] }); diff --git a/src/commands/moderation/clearMessages.ts b/src/commands/moderation/clearMessages.ts index f5b34eca..9b6c5e05 100644 --- a/src/commands/moderation/clearMessages.ts +++ b/src/commands/moderation/clearMessages.ts @@ -1,4 +1,13 @@ -import { ApplicationCommandOptionType, ApplicationCommandType, TextChannel, Colors, ActionRowBuilder, ButtonBuilder, ButtonStyle, Interaction } from 'discord.js'; +import { + ApplicationCommandOptionType, + ApplicationCommandType, + TextChannel, + Colors, + ActionRowBuilder, + ButtonBuilder, + ButtonStyle, + Interaction, +} from 'discord.js'; import { slashCommand, slashCommandStructure, makeEmbed, constantsConfig, Logger } from '../../lib'; const data = slashCommandStructure({ @@ -7,14 +16,16 @@ const data = slashCommandStructure({ type: ApplicationCommandType.ChatInput, default_member_permissions: constantsConfig.commandPermission.MANAGE_SERVER, //Overrides need to be added for admin and moderator roles dm_permission: false, - options: [{ - name: 'amount', - description: 'Number of messages to clear (1-100).', - type: ApplicationCommandOptionType.Integer, - required: true, - min_value: 1, - max_value: 100, - }], + options: [ + { + name: 'amount', + description: 'Number of messages to clear (1-100).', + type: ApplicationCommandOptionType.Integer, + required: true, + min_value: 1, + max_value: 100, + }, + ], }); export default slashCommand(data, async ({ interaction }) => { @@ -68,7 +79,9 @@ export default slashCommand(data, async ({ interaction }) => { timestamp: new Date(), }); - const modLogsChannel = interaction.guild.channels.resolve(constantsConfig.channels.MOD_LOGS) as TextChannel; + const modLogsChannel = interaction.guild.channels.resolve( + constantsConfig.channels.MOD_LOGS, + ) as TextChannel; const modLogEmbed = makeEmbed({ title: '🧹 Messages Cleared', description: 'Messages have been cleared.', @@ -98,7 +111,9 @@ export default slashCommand(data, async ({ interaction }) => { return interaction.editReply({ content: '', embeds: [replyEmbed], components: [] }); } catch (error) { Logger.error('Error clearing messages:', error); - return interaction.editReply({ content: 'There was an error trying to clear messages in this channel. The error has been logged.' }); + return interaction.editReply({ + content: 'There was an error trying to clear messages in this channel. The error has been logged.', + }); } } else { const canceledEmbed = makeEmbed({ diff --git a/src/commands/moderation/commandTable.ts b/src/commands/moderation/commandTable.ts index 8c98eb4c..66ee5f0f 100644 --- a/src/commands/moderation/commandTable.ts +++ b/src/commands/moderation/commandTable.ts @@ -42,7 +42,11 @@ export default slashCommand(data, async ({ interaction }: { interaction: Command // eslint-disable-next-line prefer-const let { name, description, type } = command; - const subcommandList = command.options?.filter((option) => option.type === ApplicationCommandOptionType.Subcommand || option.type === ApplicationCommandOptionType.SubcommandGroup); + const subcommandList = command.options?.filter( + (option) => + option.type === ApplicationCommandOptionType.Subcommand || + option.type === ApplicationCommandOptionType.SubcommandGroup, + ); let subcommandDescription = ''; @@ -53,11 +57,11 @@ export default slashCommand(data, async ({ interaction }: { interaction: Command return subcommand.name; } if (subcommand.type === ApplicationCommandOptionType.SubcommandGroup) { - const groupSubcommands = subcommand.options?.filter((sub) => sub.type === ApplicationCommandOptionType.Subcommand); + const groupSubcommands = subcommand.options?.filter( + (sub) => sub.type === ApplicationCommandOptionType.Subcommand, + ); if (groupSubcommands && groupSubcommands.length > 0) { - return `${subcommand.name} [${groupSubcommands - .map((sub) => sub.name) - .join(', ')}]`; + return `${subcommand.name} [${groupSubcommands.map((sub) => sub.name).join(', ')}]`; } return `${subcommand.name} [None]`; } diff --git a/src/commands/moderation/deployCommands.ts b/src/commands/moderation/deployCommands.ts index 45da2ba4..f7b59a8b 100644 --- a/src/commands/moderation/deployCommands.ts +++ b/src/commands/moderation/deployCommands.ts @@ -16,36 +16,37 @@ const data = slashCommandStructure({ export default slashCommand(data, async ({ interaction }) => { if (interaction.guild) { try { - await deployCommands(commandArray, contextArray) - .then(async (user) => { - const bot = `<@${user.id}>`; + await deployCommands(commandArray, contextArray).then(async (user) => { + const bot = `<@${user.id}>`; - const guildID = constantsConfig.guildId; - if (!guildID) { - await interaction.reply('guildId configuration constant is not defined.'); - return; - } + const guildID = constantsConfig.guildId; + if (!guildID) { + await interaction.reply('guildId configuration constant is not defined.'); + return; + } - const guildName = client.guilds.cache.get(guildID); + const guildName = client.guilds.cache.get(guildID); - let response; - //If the bot is deployed to a guild and can resolve the name, use the guild name in the response - if (guildName) { - response = process.env.NODE_ENV === 'production' + let response; + //If the bot is deployed to a guild and can resolve the name, use the guild name in the response + if (guildName) { + response = + process.env.NODE_ENV === 'production' ? `Deployed ${commandArray.length} commands and ${contextArray.length} contexts globally as ${bot}!` : `Deployed ${commandArray.length} commands and ${contextArray.length} contexts to \`${guildName}\` as ${bot}!`; - } else { + } else { //If the bot can't gather the guild name, use the ID in the response - response = process.env.NODE_ENV === 'production' + response = + process.env.NODE_ENV === 'production' ? `Deployed ${commandArray.length} commands and ${contextArray.length} contexts globally as ${bot}!` : `Deployed ${commandArray.length} commands and ${contextArray.length} contexts to \`<@${guildID}>\` as ${bot}!`; - } - Logger.info(response); - await interaction.reply({ - content: response, - ephemeral: true, - }); + } + Logger.info(response); + await interaction.reply({ + content: response, + ephemeral: true, }); + }); } catch (error) { await interaction.reply({ content: 'Failed to deploy commands!', diff --git a/src/commands/moderation/faq/faq.ts b/src/commands/moderation/faq/faq.ts index cccc208f..f003ddb1 100644 --- a/src/commands/moderation/faq/faq.ts +++ b/src/commands/moderation/faq/faq.ts @@ -63,20 +63,20 @@ export default slashCommand(data, async ({ interaction }) => { const modLogsChannel = interaction.guild.channels.resolve(constantsConfig.channels.MOD_LOGS) as TextChannel; switch (subcommandName) { - case 'add': - await handleAddFaq(interaction, modLogsChannel); - break; - case 'remove': - await handleRemoveFaq(interaction, faqID, modLogsChannel); - break; - case 'list': - await handleListFaq(interaction); - break; - case 'print-all': - await handlePrintAllFAQ(interaction); - break; + case 'add': + await handleAddFaq(interaction, modLogsChannel); + break; + case 'remove': + await handleRemoveFaq(interaction, faqID, modLogsChannel); + break; + case 'list': + await handleListFaq(interaction); + break; + case 'print-all': + await handlePrintAllFAQ(interaction); + break; - default: - await interaction.reply({ content: 'Unknown subcommand', ephemeral: true }); + default: + await interaction.reply({ content: 'Unknown subcommand', ephemeral: true }); } }); diff --git a/src/commands/moderation/faq/functions/addFaq.ts b/src/commands/moderation/faq/functions/addFaq.ts index 72fa12ec..bd6d3274 100644 --- a/src/commands/moderation/faq/functions/addFaq.ts +++ b/src/commands/moderation/faq/functions/addFaq.ts @@ -10,25 +10,26 @@ import { } from 'discord.js'; import { Logger, makeEmbed, FAQ } from '../../../../lib'; -const faqAddedEmbed = (discordUser: User, question: string, answer: string) => makeEmbed({ - author: { - name: `[FAQ Added] ${discordUser.tag}`, - iconURL: discordUser.displayAvatarURL(), - }, - fields: [ - { - inline: false, - name: 'Question', - value: question, +const faqAddedEmbed = (discordUser: User, question: string, answer: string) => + makeEmbed({ + author: { + name: `[FAQ Added] ${discordUser.tag}`, + iconURL: discordUser.displayAvatarURL(), }, - { - inline: false, - name: 'Answer', - value: answer, - }, - ], - color: Colors.Green, -}); + fields: [ + { + inline: false, + name: 'Question', + value: question, + }, + { + inline: false, + name: 'Answer', + value: answer, + }, + ], + color: Colors.Green, + }); export async function handleAddFaq(interaction: ChatInputCommandInteraction<'cached'>, modLogsChannel: TextChannel) { const modal = new ModalBuilder({ @@ -36,27 +37,23 @@ export async function handleAddFaq(interaction: ChatInputCommandInteraction<'cac title: 'Add an FAQ entry', }); - const faqTitleInput = new TextInputBuilder( - { - customId: 'faqTitleInput', - label: 'Title', - placeholder: 'Please enter the title of the FAQ.', - style: TextInputStyle.Short, - maxLength: 500, - required: true, - }, - ); - - const faqAnswerInput = new TextInputBuilder( - { - customId: 'faqAnswerInput', - label: 'Answer', - placeholder: 'If you wish to mention a role or channel use <@&*ID*> or <#*ID*> respectively.', - style: TextInputStyle.Paragraph, - maxLength: 1000, - required: true, - }, - ); + const faqTitleInput = new TextInputBuilder({ + customId: 'faqTitleInput', + label: 'Title', + placeholder: 'Please enter the title of the FAQ.', + style: TextInputStyle.Short, + maxLength: 500, + required: true, + }); + + const faqAnswerInput = new TextInputBuilder({ + customId: 'faqAnswerInput', + label: 'Answer', + placeholder: 'If you wish to mention a role or channel use <@&*ID*> or <#*ID*> respectively.', + style: TextInputStyle.Paragraph, + maxLength: 1000, + required: true, + }); const titleActionRow = new ActionRowBuilder().addComponents(faqTitleInput); const answerActionRow = new ActionRowBuilder().addComponents(faqAnswerInput); @@ -67,10 +64,8 @@ export async function handleAddFaq(interaction: ChatInputCommandInteraction<'cac //Modal sent - const filter = (interaction: { - customId: string; - user: { id: any; }; - }) => interaction.customId === 'faqAddModal' && interaction.user.id; + const filter = (interaction: { customId: string; user: { id: any } }) => + interaction.customId === 'faqAddModal' && interaction.user.id; try { //Await a modal response @@ -95,13 +90,16 @@ export async function handleAddFaq(interaction: ChatInputCommandInteraction<'cac if (!faqData) { faqData = new FAQ({ - faqTitle: faqTitle!, - faqAnswer: faqAnswer!, + faqTitle: faqTitle, + faqAnswer: faqAnswer, moderatorID: discordUser.id, dateSet: currentDate, }); } else { - await interaction.followUp({ content: 'FAQ with this title already exists. Please choose another title', ephemeral: true }); + await interaction.followUp({ + content: 'FAQ with this title already exists. Please choose another title', + ephemeral: true, + }); return; } @@ -109,7 +107,10 @@ export async function handleAddFaq(interaction: ChatInputCommandInteraction<'cac await faqData.save(); } catch (error) { Logger.error(error); - await interaction.followUp({ content: 'Could not add FAQ, error has been logged, please notify the bot team.', ephemeral: true }); + await interaction.followUp({ + content: 'Could not add FAQ, error has been logged, please notify the bot team.', + ephemeral: true, + }); return; } @@ -117,7 +118,11 @@ export async function handleAddFaq(interaction: ChatInputCommandInteraction<'cac await modLogsChannel.send({ embeds: [faqAddedEmbed(discordUser, faqTitle, faqAnswer)] }); } catch (error) { Logger.error(error); - await interaction.followUp({ content: 'FAQ added successfully, but could not send mod log, error has been logged, please notify the bot team.', ephemeral: true }); + await interaction.followUp({ + content: + 'FAQ added successfully, but could not send mod log, error has been logged, please notify the bot team.', + ephemeral: true, + }); return; } diff --git a/src/commands/moderation/faq/functions/faqPrintAll.ts b/src/commands/moderation/faq/functions/faqPrintAll.ts index e9f573ea..72394937 100644 --- a/src/commands/moderation/faq/functions/faqPrintAll.ts +++ b/src/commands/moderation/faq/functions/faqPrintAll.ts @@ -34,7 +34,8 @@ export async function handlePrintAllFAQ(interaction: ChatInputCommandInteraction if (faqs.length === 0) { return interaction.followUp('No FAQs found.'); - } if (interaction.channel) { + } + if (interaction.channel) { await interaction.channel.send({ files: [FLIGHT_DECK_IMAGE_URL] }); // Divide the FAQs into sets of 5 @@ -55,7 +56,6 @@ export async function handlePrintAllFAQ(interaction: ChatInputCommandInteraction })), }); - // eslint-disable-next-line no-await-in-loop await interaction.channel.send({ embeds: [faqEmbed] }); } diff --git a/src/commands/moderation/faq/functions/listFaq.ts b/src/commands/moderation/faq/functions/listFaq.ts index 965d87dd..b4098862 100644 --- a/src/commands/moderation/faq/functions/listFaq.ts +++ b/src/commands/moderation/faq/functions/listFaq.ts @@ -2,10 +2,11 @@ import { ChatInputCommandInteraction } from 'discord.js'; import moment from 'moment/moment'; import { Logger, makeEmbed, FAQ, createPaginatedEmbedHandler } from '../../../../lib'; -const faqListEmbed = (faqFields: { name: string; value: string; }[], currentPage: number, totalPages: number) => makeEmbed({ - title: `FAQ List (Page ${currentPage} of ${totalPages})`, - fields: faqFields, -}); +const faqListEmbed = (faqFields: { name: string; value: string }[], currentPage: number, totalPages: number) => + makeEmbed({ + title: `FAQ List (Page ${currentPage} of ${totalPages})`, + fields: faqFields, + }); export async function handleListFaq(interaction: ChatInputCommandInteraction<'cached'>) { try { @@ -20,16 +21,19 @@ export async function handleListFaq(interaction: ChatInputCommandInteraction<'ca const embeds = []; let currentPage = 1; let faqsAddedToPage = 0; - const faqFields: { name: string; value: string; }[] = []; + const faqFields: { name: string; value: string }[] = []; - const moderatorPromises = faqs.map((currentFaq) => interaction.client.users.fetch(currentFaq.moderatorID!) - // Added for better readability - // eslint-disable-next-line arrow-body-style - .catch(() => { - return new Promise((resolve) => { - resolve(`I can't find the moderator, here is the stored ID: ${currentFaq.moderatorID}`); - }); - })); + const moderatorPromises = faqs.map((currentFaq) => + interaction.client.users + .fetch(currentFaq.moderatorID) + // Added for better readability + + .catch(() => { + return new Promise((resolve) => { + resolve(`I can't find the moderator, here is the stored ID: ${currentFaq.moderatorID}`); + }); + }), + ); const moderatorUsers = await Promise.all(moderatorPromises); for (let i = 0; i < faqs.length; i++) { @@ -39,10 +43,10 @@ export async function handleListFaq(interaction: ChatInputCommandInteraction<'ca { name: `**Title:** ${faqs[i].faqTitle}`, value: - `**Answer:** ${faqs[i].faqAnswer}\n` - + `**Moderator:** ${moderatorUsers[i]}\n` - + `**Date Set:** ${formattedDate}\n` - + `**FAQ ID:** ${faqs[i].id}\n`, + `**Answer:** ${faqs[i].faqAnswer}\n` + + `**Moderator:** ${moderatorUsers[i]}\n` + + `**Date Set:** ${formattedDate}\n` + + `**FAQ ID:** ${faqs[i].id}\n`, }, { name: '', @@ -71,6 +75,9 @@ export async function handleListFaq(interaction: ChatInputCommandInteraction<'ca await createPaginatedEmbedHandler(interaction, embeds); } catch (error) { Logger.error(error); - await interaction.reply({ content: 'Could not list FAQs, error has been logged, please notify the bot team.', ephemeral: true }); + await interaction.reply({ + content: 'Could not list FAQs, error has been logged, please notify the bot team.', + ephemeral: true, + }); } } diff --git a/src/commands/moderation/faq/functions/removeFaq.ts b/src/commands/moderation/faq/functions/removeFaq.ts index 80fb2937..30b508fc 100644 --- a/src/commands/moderation/faq/functions/removeFaq.ts +++ b/src/commands/moderation/faq/functions/removeFaq.ts @@ -1,27 +1,32 @@ import { ChatInputCommandInteraction, Colors, TextChannel, User } from 'discord.js'; import { Logger, makeEmbed, FAQ } from '../../../../lib'; -const faqRemovedEmbed = (discordUser: User, faqQuestion: string, faqAnswer: string) => makeEmbed({ - author: { - name: `[FAQ Removed] ${discordUser.tag}`, - iconURL: discordUser.displayAvatarURL(), - }, - fields: [ - { - inline: false, - name: 'Question', - value: faqQuestion, +const faqRemovedEmbed = (discordUser: User, faqQuestion: string, faqAnswer: string) => + makeEmbed({ + author: { + name: `[FAQ Removed] ${discordUser.tag}`, + iconURL: discordUser.displayAvatarURL(), }, - { - inline: false, - name: 'Answer', - value: faqAnswer, - }, - ], - color: Colors.Red, -}); + fields: [ + { + inline: false, + name: 'Question', + value: faqQuestion, + }, + { + inline: false, + name: 'Answer', + value: faqAnswer, + }, + ], + color: Colors.Red, + }); -export async function handleRemoveFaq(interaction: ChatInputCommandInteraction<'cached'>, faqID: string, modLogsChannel: TextChannel) { +export async function handleRemoveFaq( + interaction: ChatInputCommandInteraction<'cached'>, + faqID: string, + modLogsChannel: TextChannel, +) { const discordUser = interaction.user; const faqEntry = await FAQ.findOne({ _id: faqID }); @@ -38,7 +43,10 @@ export async function handleRemoveFaq(interaction: ChatInputCommandInteraction<' await faqEntry.deleteOne(); } catch (error) { Logger.error(error); - await interaction.reply({ content: 'Could not remove FAQ, error has been logged, please notify the bot team.', ephemeral: true }); + await interaction.reply({ + content: 'Could not remove FAQ, error has been logged, please notify the bot team.', + ephemeral: true, + }); return; } @@ -46,7 +54,11 @@ export async function handleRemoveFaq(interaction: ChatInputCommandInteraction<' await modLogsChannel.send({ embeds: [faqRemovedEmbed(discordUser, faqTitle, faqAnswer)] }); } catch (error) { Logger.error(error); - await interaction.reply({ content: 'FAQ removed successfully, but could not send mod log, error has been logged, please notify the bot team.', ephemeral: true }); + await interaction.reply({ + content: + 'FAQ removed successfully, but could not send mod log, error has been logged, please notify the bot team.', + ephemeral: true, + }); return; } diff --git a/src/commands/moderation/infractions/functions/ban.ts b/src/commands/moderation/infractions/functions/ban.ts index e141df53..40c2eed6 100644 --- a/src/commands/moderation/infractions/functions/ban.ts +++ b/src/commands/moderation/infractions/functions/ban.ts @@ -11,82 +11,94 @@ const noConnEmbed = makeEmbed({ const moderatableFailEmbed = makeEmbed({ color: Colors.Red, - description: 'You can\'t ban a moderator!', + description: "You can't ban a moderator!", }); -const failedBanEmbed = (discordUser: User) => makeEmbed({ - title: 'Ban - Failed', - description: `Failed to Ban ${discordUser.toString()}`, - color: Colors.Red, -}); - -const DMEmbed = (moderator: User, banReason: string, guild: Guild) => makeEmbed({ - title: `You have been banned from ${guild.name}`, - description: 'This ban is also logged against your record.', - fields: [ - { - inline: true, - name: 'Moderator', - value: moderator.toString(), - }, - { - inline: false, - name: 'Reason', - value: banReason, - }, - { - inline: false, - name: 'Appeal', - value: `If you would like to appeal your ban, please fill out [this form.](${process.env.BAN_APPEAL_URL})`, +const failedBanEmbed = (discordUser: User) => + makeEmbed({ + title: 'Ban - Failed', + description: `Failed to Ban ${discordUser.toString()}`, + color: Colors.Red, + }); + +const DMEmbed = (moderator: User, banReason: string, guild: Guild) => + makeEmbed({ + title: `You have been banned from ${guild.name}`, + description: 'This ban is also logged against your record.', + fields: [ + { + inline: true, + name: 'Moderator', + value: moderator.toString(), + }, + { + inline: false, + name: 'Reason', + value: banReason, + }, + { + inline: false, + name: 'Appeal', + value: `If you would like to appeal your ban, please fill out [this form.](${process.env.BAN_APPEAL_URL})`, + }, + ], + }); + +const banEmbed = (discordUser: User) => + makeEmbed({ + title: `${discordUser.tag} was banned successfully`, + color: Colors.Green, + }); + +const DMFailed = (discordUser: User) => + makeEmbed({ + title: 'Ban - DM not sent', + description: `DM was not sent to ${discordUser.toString()}, they either have DMs closed or share no mutual servers with the bot.`, + color: Colors.Red, + }); + +const modLogEmbed = ( + moderator: User, + discordUser: User, + banReason: string, + daysDeletedNumber: number, + formattedDate: string, +) => + makeEmbed({ + author: { + name: `[BANNED] ${discordUser.tag}`, + iconURL: discordUser.displayAvatarURL(), }, - ], -}); - -const banEmbed = (discordUser: User) => makeEmbed({ - title: `${discordUser.tag} was banned successfully`, - color: Colors.Green, -}); - -const DMFailed = (discordUser: User) => makeEmbed({ - title: 'Ban - DM not sent', - description: `DM was not sent to ${discordUser.toString()}, they either have DMs closed or share no mutual servers with the bot.`, - color: Colors.Red, -}); - -const modLogEmbed = (moderator: User, discordUser: User, banReason: string, daysDeletedNumber: number, formattedDate: string) => makeEmbed({ - author: { - name: `[BANNED] ${discordUser.tag}`, - iconURL: discordUser.displayAvatarURL(), - }, - fields: [ - { - name: 'User', - value: discordUser.toString(), - }, - { - name: 'Moderator', - value: `${moderator}`, - }, - { - name: 'Reason', - value: `\u200B${banReason}`, - }, - { - name: 'Days of messages deleted', - value: daysDeletedNumber.toString(), - }, - { - name: 'Date', - value: formattedDate, - }, - ], - footer: { text: `User ID: ${discordUser.id}` }, - color: Colors.Red, -}); + fields: [ + { + name: 'User', + value: discordUser.toString(), + }, + { + name: 'Moderator', + value: `${moderator}`, + }, + { + name: 'Reason', + value: `\u200B${banReason}`, + }, + { + name: 'Days of messages deleted', + value: daysDeletedNumber.toString(), + }, + { + name: 'Date', + value: formattedDate, + }, + ], + footer: { text: `User ID: ${discordUser.id}` }, + color: Colors.Red, + }); const noModLogs = makeEmbed({ title: 'Ban - No Mod Log', - description: 'I can\'t find the mod logs channel. I will still try to ban the user. Please check the channel still exists.', + description: + "I can't find the mod logs channel. I will still try to ban the user. Please check the channel still exists.", color: Colors.Red, }); @@ -112,9 +124,7 @@ export async function handleBanInfraction(interaction: ChatInputCommandInteracti const discordUser = await interaction.guild.members.fetch(userID); const moderator = interaction.user; const currentDate = new Date(); - const formattedDate: string = moment(currentDate) - .utcOffset(0) - .format(); + const formattedDate: string = moment(currentDate).utcOffset(0).format(); const modLogsChannel = interaction.guild.channels.resolve(constantsConfig.channels.MOD_LOGS) as TextChannel; //Check if the user is a moderator @@ -145,7 +155,9 @@ export async function handleBanInfraction(interaction: ChatInputCommandInteracti try { await interaction.guild.members.ban(discordUser, { deleteMessageDays: daysDeletedNumber, reason: banReason }); if (modLogsChannel) { - await modLogsChannel.send({ embeds: [modLogEmbed(moderator, discordUser.user, banReason, daysDeletedNumber, formattedDate)] }); + await modLogsChannel.send({ + embeds: [modLogEmbed(moderator, discordUser.user, banReason, daysDeletedNumber, formattedDate)], + }); } await interaction.followUp({ embeds: [banEmbed(discordUser.user)], ephemeral: true }); } catch (error) { diff --git a/src/commands/moderation/infractions/functions/deleteInfractions.ts b/src/commands/moderation/infractions/functions/deleteInfractions.ts index d2bd7539..388d237b 100644 --- a/src/commands/moderation/infractions/functions/deleteInfractions.ts +++ b/src/commands/moderation/infractions/functions/deleteInfractions.ts @@ -31,35 +31,36 @@ const errorEmbed = makeEmbed({ color: Colors.Red, }); -const modLogEmbed = (moderator: string, discordUser: User, infractionType: string, infractionReason: string) => makeEmbed({ - author: { - name: `[INFRACTION DELETE] ${discordUser.tag}`, - iconURL: discordUser.displayAvatarURL(), - }, - fields: [ - { - inline: false, - name: 'Deleted by:', - value: moderator, +const modLogEmbed = (moderator: string, discordUser: User, infractionType: string, infractionReason: string) => + makeEmbed({ + author: { + name: `[INFRACTION DELETE] ${discordUser.tag}`, + iconURL: discordUser.displayAvatarURL(), }, - { - inline: false, - name: 'Infraction user:', - value: discordUser.toString(), - }, - { - inline: false, - name: 'Infraction type:', - value: infractionType, - }, - { - inline: false, - name: 'Reason', - value: infractionReason, - }, - ], - color: Colors.Green, -}); + fields: [ + { + inline: false, + name: 'Deleted by:', + value: moderator, + }, + { + inline: false, + name: 'Infraction user:', + value: discordUser.toString(), + }, + { + inline: false, + name: 'Infraction type:', + value: infractionType, + }, + { + inline: false, + name: 'Reason', + value: infractionReason, + }, + ], + color: Colors.Green, + }); export async function handleDeleteInfraction(interaction: ChatInputCommandInteraction<'cached'>) { const conn = getConn(); @@ -105,7 +106,9 @@ export async function handleDeleteInfraction(interaction: ChatInputCommandIntera const modLogsChannel = interaction.guild.channels.resolve(constantsConfig.channels.MOD_LOGS) as TextChannel; if (modLogsChannel) { - await modLogsChannel.send({ embeds: [modLogEmbed(interaction.user.toString(), discordUser, infractionType, infractionReason)] }); + await modLogsChannel.send({ + embeds: [modLogEmbed(interaction.user.toString(), discordUser, infractionType, infractionReason)], + }); } } catch (error) { await interaction.reply({ embeds: [errorEmbed], ephemeral: true }); diff --git a/src/commands/moderation/infractions/functions/listInfractions.ts b/src/commands/moderation/infractions/functions/listInfractions.ts index 52820386..794c6fc8 100644 --- a/src/commands/moderation/infractions/functions/listInfractions.ts +++ b/src/commands/moderation/infractions/functions/listInfractions.ts @@ -8,7 +8,11 @@ const noConnEmbed = makeEmbed({ color: Colors.Red, }); -export async function handleListInfraction(interaction: CommandInteraction, userID: string | undefined, ephemeral = false) { +export async function handleListInfraction( + interaction: CommandInteraction, + userID: string | undefined, + ephemeral = false, +) { const conn = getConn(); if (!conn) { @@ -63,22 +67,20 @@ export async function handleListInfraction(interaction: CommandInteraction, user notesLength: userNotes.length.toString(), }; - type InfractionArray = typeof warnInfractions - | typeof timeoutInfractions - | typeof scamLogInfractions - | typeof banInfractions - | typeof unbanInfractions - | typeof userNotes; + type InfractionArray = typeof warnInfractions; const fetchModerators = (infractions: InfractionArray) => { - const moderatorPromises = infractions.map((infraction) => interaction.client.users.fetch(infraction.moderatorID!) - // Disabled for readability - // eslint-disable-next-line arrow-body-style - .catch(() => { - return new Promise((resolve) => { - resolve(`I can't find the moderator, here is the stored ID: ${infraction.moderatorID}`); - }); - })); + const moderatorPromises = infractions.map((infraction) => + interaction.client.users + .fetch(infraction.moderatorID) + // Disabled for readability + + .catch(() => { + return new Promise((resolve) => { + resolve(`I can't find the moderator, here is the stored ID: ${infraction.moderatorID}`); + }); + }), + ); return Promise.all(moderatorPromises); }; @@ -88,19 +90,17 @@ export async function handleListInfraction(interaction: CommandInteraction, user const warnModeratorUsers = await fetchModerators(warnInfractions); for (let i = 0; i < warnInfractions.length; i++) { - const formattedDate: string = moment(warnInfractions[i].date) - .utcOffset(0) - .format(); + const formattedDate: string = moment(warnInfractions[i].date).utcOffset(0).format(); warnFields.push( { name: `Warn #${i + 1}`, value: - `**Type:** ${warnInfractions[i].infractionType}\n` - + `**Moderator:** ${warnModeratorUsers[i]}\n` - + `**Reason:** ${warnInfractions[i].reason}\n` - + `**Date:** ${formattedDate}\n` - + `**Infraction ID:** ${warnInfractions[i].infractionID}`, + `**Type:** ${warnInfractions[i].infractionType}\n` + + `**Moderator:** ${warnModeratorUsers[i]}\n` + + `**Reason:** ${warnInfractions[i].reason}\n` + + `**Date:** ${formattedDate}\n` + + `**Infraction ID:** ${warnInfractions[i].infractionID}`, }, { name: '', @@ -124,20 +124,18 @@ export async function handleListInfraction(interaction: CommandInteraction, user const timeoutModeratorUsers = await fetchModerators(timeoutInfractions); for (let i = 0; i < timeoutInfractions.length; i++) { - const formattedDate: string = moment(timeoutInfractions[i].date) - .utcOffset(0) - .format(); + const formattedDate: string = moment(timeoutInfractions[i].date).utcOffset(0).format(); timeoutFields.push( { name: `Timeout #${i + 1}`, value: - `**Type:** ${timeoutInfractions[i].infractionType}\n` - + `**Moderator:** ${timeoutModeratorUsers[i]}\n` - + `**Reason:** ${timeoutInfractions[i].reason}\n` - + `**Duration:** ${timeoutInfractions[i].duration !== undefined ? timeoutInfractions[i].duration : 'No duration specified, this user was timed out before the bot upgrade!'}\n` - + `**Date:** ${formattedDate}\n` - + `**Infraction ID:** ${timeoutInfractions[i].infractionID}`, + `**Type:** ${timeoutInfractions[i].infractionType}\n` + + `**Moderator:** ${timeoutModeratorUsers[i]}\n` + + `**Reason:** ${timeoutInfractions[i].reason}\n` + + `**Duration:** ${timeoutInfractions[i].duration !== undefined ? timeoutInfractions[i].duration : 'No duration specified, this user was timed out before the bot upgrade!'}\n` + + `**Date:** ${formattedDate}\n` + + `**Infraction ID:** ${timeoutInfractions[i].infractionID}`, }, { name: '', @@ -161,19 +159,17 @@ export async function handleListInfraction(interaction: CommandInteraction, user const scamLogModerators = await fetchModerators(scamLogInfractions); for (let i = 0; i < scamLogInfractions.length; i++) { - const formattedDate: string = moment(scamLogInfractions[i].date) - .utcOffset(0) - .format(); + const formattedDate: string = moment(scamLogInfractions[i].date).utcOffset(0).format(); scamLogFields.push( { name: `Scam Log #${i + 1}`, value: - `**Type:** ${scamLogInfractions[i].infractionType}\n` - + `**Moderator:** ${scamLogModerators[i]}\n` - + `**Message Content:** ${scamLogInfractions[i].reason}\n` - + `**Date:** ${formattedDate}\n` - + `**Infraction ID:** ${scamLogInfractions[i].infractionID}`, + `**Type:** ${scamLogInfractions[i].infractionType}\n` + + `**Moderator:** ${scamLogModerators[i]}\n` + + `**Message Content:** ${scamLogInfractions[i].reason}\n` + + `**Date:** ${formattedDate}\n` + + `**Infraction ID:** ${scamLogInfractions[i].infractionID}`, }, { name: '', @@ -197,19 +193,17 @@ export async function handleListInfraction(interaction: CommandInteraction, user const banModerators = await fetchModerators(banInfractions); for (let i = 0; i < banInfractions.length; i++) { - const formattedDate: string = moment(banInfractions[i].date) - .utcOffset(0) - .format(); + const formattedDate: string = moment(banInfractions[i].date).utcOffset(0).format(); banFields.push( { name: `Ban #${i + 1}`, value: - `**Type:** ${banInfractions[i].infractionType}\n` - + `**Moderator:** ${banModerators[i]}\n` - + `**Reason:** ${banInfractions[i].reason}\n` - + `**Date:** ${formattedDate}\n` - + `**Infraction ID:** ${banInfractions[i].infractionID}`, + `**Type:** ${banInfractions[i].infractionType}\n` + + `**Moderator:** ${banModerators[i]}\n` + + `**Reason:** ${banInfractions[i].reason}\n` + + `**Date:** ${formattedDate}\n` + + `**Infraction ID:** ${banInfractions[i].infractionID}`, }, { name: '', @@ -232,19 +226,17 @@ export async function handleListInfraction(interaction: CommandInteraction, user const unbanFields: { name: string; value: string }[] = []; const unbanModerators = await fetchModerators(unbanInfractions); for (let i = 0; i < unbanInfractions.length; i++) { - const formattedDate: string = moment(unbanInfractions[i].date) - .utcOffset(0) - .format(); + const formattedDate: string = moment(unbanInfractions[i].date).utcOffset(0).format(); unbanFields.push( { name: `Unban #${i + 1}`, value: - `**Type:** ${unbanInfractions[i].infractionType}\n` - + `**Moderator:** ${unbanModerators[i]}\n` - + `**Reason:** ${unbanInfractions[i].reason}\n` - + `**Date:** ${formattedDate}\n` - + `**Infraction ID:** ${unbanInfractions[i].infractionID}`, + `**Type:** ${unbanInfractions[i].infractionType}\n` + + `**Moderator:** ${unbanModerators[i]}\n` + + `**Reason:** ${unbanInfractions[i].reason}\n` + + `**Date:** ${formattedDate}\n` + + `**Infraction ID:** ${unbanInfractions[i].infractionID}`, }, { name: '', @@ -268,19 +260,17 @@ export async function handleListInfraction(interaction: CommandInteraction, user const userNodeModerators = await fetchModerators(userNotes); for (let i = 0; i < userNotes.length; i++) { - const formattedDate: string = moment(userNotes[i].date) - .utcOffset(0) - .format(); + const formattedDate: string = moment(userNotes[i].date).utcOffset(0).format(); noteFields.push( { name: `Note #${i + 1}`, value: - `**Type:** ${userNotes[i].infractionType}\n` - + `**Moderator:** ${userNodeModerators[i]}\n` - + `**Note:** ${userNotes[i].reason}\n` - + `**Date:** ${formattedDate}\n` - + `**Infraction ID:** ${userNotes[i].infractionID}`, + `**Type:** ${userNotes[i].infractionType}\n` + + `**Moderator:** ${userNodeModerators[i]}\n` + + `**Note:** ${userNotes[i].reason}\n` + + `**Date:** ${formattedDate}\n` + + `**Infraction ID:** ${userNotes[i].infractionID}`, }, { name: '', @@ -305,7 +295,7 @@ export async function handleListInfraction(interaction: CommandInteraction, user name: `${discordUser.tag}'s Infractions`, iconURL: avatarURL || undefined, }, - description: 'Click the buttons below to view the user\'s infractions in detail.', + description: "Click the buttons below to view the user's infractions in detail.", fields: [ { name: 'UserID', @@ -362,7 +352,8 @@ export async function handleListInfraction(interaction: CommandInteraction, user const userNotFound = makeEmbed({ color: Colors.Red, title: 'User not found', - description: 'An error occurred while fetching user information, please check the userID. If the ID is correct, this user may not exist on Discord anymore - If you need to view their infractions anyway one of the bot team can search the DB manually.', + description: + 'An error occurred while fetching user information, please check the userID. If the ID is correct, this user may not exist on Discord anymore - If you need to view their infractions anyway one of the bot team can search the DB manually.', }); await interaction.followUp({ embeds: [userNotFound], ephemeral }); diff --git a/src/commands/moderation/infractions/functions/removeTimeout.ts b/src/commands/moderation/infractions/functions/removeTimeout.ts index 211778a9..9c1e7c0f 100644 --- a/src/commands/moderation/infractions/functions/removeTimeout.ts +++ b/src/commands/moderation/infractions/functions/removeTimeout.ts @@ -2,48 +2,52 @@ import { ChatInputCommandInteraction, Colors, TextChannel, User } from 'discord. import moment from 'moment'; import { constantsConfig, Logger, makeEmbed } from '../../../../lib'; -const notTimedOutEmbed = (discordUser: User) => makeEmbed({ - title: 'Remove Timeout - Failed', - description: `${discordUser.toString()} is not currently timed out.`, - color: Colors.Red, -}); +const notTimedOutEmbed = (discordUser: User) => + makeEmbed({ + title: 'Remove Timeout - Failed', + description: `${discordUser.toString()} is not currently timed out.`, + color: Colors.Red, + }); -const failedRemoveTimeoutEmbed = (discordUser: User) => makeEmbed({ - title: 'Remove Timeout - Failed', - description: `Failed to remove timeout for ${discordUser.toString()}`, - color: Colors.Red, -}); +const failedRemoveTimeoutEmbed = (discordUser: User) => + makeEmbed({ + title: 'Remove Timeout - Failed', + description: `Failed to remove timeout for ${discordUser.toString()}`, + color: Colors.Red, + }); -const modLogEmbed = (moderator: User, discordUser: User, date: string) => makeEmbed({ - author: { - name: `[TIMEOUT REMOVED] ${discordUser.tag}`, - iconURL: discordUser.displayAvatarURL(), - }, - fields: [ - { - inline: true, - name: 'Moderator', - value: moderator.toString(), +const modLogEmbed = (moderator: User, discordUser: User, date: string) => + makeEmbed({ + author: { + name: `[TIMEOUT REMOVED] ${discordUser.tag}`, + iconURL: discordUser.displayAvatarURL(), }, - { - inline: true, - name: 'User', - value: discordUser.toString(), - }, - { - inline: false, - name: 'Date', - value: date, - }, - ], - footer: { text: `User ID: ${discordUser.id}` }, - color: Colors.Green, -}); + fields: [ + { + inline: true, + name: 'Moderator', + value: moderator.toString(), + }, + { + inline: true, + name: 'User', + value: discordUser.toString(), + }, + { + inline: false, + name: 'Date', + value: date, + }, + ], + footer: { text: `User ID: ${discordUser.id}` }, + color: Colors.Green, + }); -const timeoutRemovedEmbed = (discordUser: User) => makeEmbed({ - title: `${discordUser.tag} was successfully removed from timeout`, - color: Colors.Green, -}); +const timeoutRemovedEmbed = (discordUser: User) => + makeEmbed({ + title: `${discordUser.tag} was successfully removed from timeout`, + color: Colors.Green, + }); const noModLogs = makeEmbed({ title: 'Remove Timeout - No Mod Log', diff --git a/src/commands/moderation/infractions/functions/timeout.ts b/src/commands/moderation/infractions/functions/timeout.ts index 54af02b6..264647a0 100644 --- a/src/commands/moderation/infractions/functions/timeout.ts +++ b/src/commands/moderation/infractions/functions/timeout.ts @@ -9,80 +9,87 @@ const noConnEmbed = makeEmbed({ color: Colors.Red, }); -const failedTimeoutEmbed = (discordUser: User, error: any) => makeEmbed({ - title: 'Timeout - Failed', - description: makeLines([ - `Failed to timeout ${discordUser.toString()}`, - '', - error, - ]), - color: Colors.Red, -}); - -const DMEmbed = (moderator: User, timeoutDuration: string, reason: string, guild: Guild, timedOutUntil: Date) => makeEmbed({ - title: `You have been timed out in ${guild.name}`, - description: 'This timeout is also logged against your record.', - fields: [ - { - inline: true, - name: 'Duration', - value: durationInEnglish(timeoutDuration), +const failedTimeoutEmbed = (discordUser: User, error: any) => + makeEmbed({ + title: 'Timeout - Failed', + description: makeLines([`Failed to timeout ${discordUser.toString()}`, '', error]), + color: Colors.Red, + }); + +const DMEmbed = (moderator: User, timeoutDuration: string, reason: string, guild: Guild, timedOutUntil: Date) => + makeEmbed({ + title: `You have been timed out in ${guild.name}`, + description: 'This timeout is also logged against your record.', + fields: [ + { + inline: true, + name: 'Duration', + value: durationInEnglish(timeoutDuration), + }, + { + inline: true, + name: 'Moderator', + value: moderator.toString(), + }, + { + inline: false, + name: 'Reason', + value: reason, + }, + ], + footer: { text: `Your timeout will be lifted on ${timedOutUntil.toUTCString()}` }, + }); + +const timeoutEmbed = (discordUser: User) => + makeEmbed({ + title: `${discordUser.tag} was timed out successfully`, + color: Colors.Green, + }); + +const DMFailed = (discordUser: User) => + makeEmbed({ + title: 'Timeout - DM not sent', + description: `DM was not sent to ${discordUser.toString()}, they either have DMs closed or share no mutual servers with the bot.`, + color: Colors.Red, + }); + +const modLogEmbed = ( + moderator: User, + discordUser: User, + timeoutReason: string, + timeoutDuration: string, + formattedDate: string, +) => + makeEmbed({ + author: { + name: `[TIMED OUT] ${discordUser.tag}`, + iconURL: discordUser.displayAvatarURL(), }, - { - inline: true, - name: 'Moderator', - value: moderator.toString(), - }, - { - inline: false, - name: 'Reason', - value: reason, - }, - ], - footer: { text: `Your timeout will be lifted on ${timedOutUntil.toUTCString()}` }, -}); - -const timeoutEmbed = (discordUser: User) => makeEmbed({ - title: `${discordUser.tag} was timed out successfully`, - color: Colors.Green, -}); - -const DMFailed = (discordUser: User) => makeEmbed({ - title: 'Timeout - DM not sent', - description: `DM was not sent to ${discordUser.toString()}, they either have DMs closed or share no mutual servers with the bot.`, - color: Colors.Red, -}); - -const modLogEmbed = (moderator: User, discordUser: User, timeoutReason: string, timeoutDuration: string, formattedDate: string) => makeEmbed({ - author: { - name: `[TIMED OUT] ${discordUser.tag}`, - iconURL: discordUser.displayAvatarURL(), - }, - fields: [ - { - name: 'User', - value: discordUser.toString(), - }, - { - name: 'Moderator', - value: `${moderator}`, - }, - { - name: 'Reason', - value: `\u200B${timeoutReason}`, - }, - { - name: 'Duration', - value: durationInEnglish(timeoutDuration), - }, - { - name: 'Date', - value: formattedDate, - }, - ], - footer: { text: `User ID: ${discordUser.id}` }, - color: Colors.Red, -}); + fields: [ + { + name: 'User', + value: discordUser.toString(), + }, + { + name: 'Moderator', + value: `${moderator}`, + }, + { + name: 'Reason', + value: `\u200B${timeoutReason}`, + }, + { + name: 'Duration', + value: durationInEnglish(timeoutDuration), + }, + { + name: 'Date', + value: formattedDate, + }, + ], + footer: { text: `User ID: ${discordUser.id}` }, + color: Colors.Red, + }); const noModLogs = makeEmbed({ title: 'Timeout - No Mod Log', @@ -96,11 +103,12 @@ const logFailed = makeEmbed({ color: Colors.Red, }); -const communicationNotDisabledEmbed = (discordUser: User) => makeEmbed({ - title: 'Timeout - Communication not disabled', - description: `Bot has not detected that ${discordUser.toString()} was successfully timed out. Timeout may have failed.`, - color: Colors.Red, -}); +const communicationNotDisabledEmbed = (discordUser: User) => + makeEmbed({ + title: 'Timeout - Communication not disabled', + description: `Bot has not detected that ${discordUser.toString()} was successfully timed out. Timeout may have failed.`, + color: Colors.Red, + }); export async function handleTimeoutInfraction(interaction: ChatInputCommandInteraction<'cached'>) { await interaction.deferReply({ ephemeral: true }); @@ -119,9 +127,7 @@ export async function handleTimeoutInfraction(interaction: ChatInputCommandInter const discordUser = await interaction.guild.members.fetch(userID); const moderator = interaction.user; const currentDate = new Date(); - const formattedDate: string = moment(currentDate) - .utcOffset(0) - .format(); + const formattedDate: string = moment(currentDate).utcOffset(0).format(); const modLogsChannel = interaction.guild.channels.resolve(constantsConfig.channels.MOD_LOGS) as TextChannel; //Try to timeout the user @@ -134,11 +140,22 @@ export async function handleTimeoutInfraction(interaction: ChatInputCommandInter return; } - if (discordUser.isCommunicationDisabled()) { //Timeout was successful + if (discordUser.isCommunicationDisabled()) { + //Timeout was successful await interaction.editReply({ embeds: [timeoutEmbed(discordUser.user)] }); //Try and send a Dm to the user try { - await discordUser.send({ embeds: [DMEmbed(moderator, timeoutDuration.toString(), timeoutReason, interaction.guild, discordUser.communicationDisabledUntil)] }); + await discordUser.send({ + embeds: [ + DMEmbed( + moderator, + timeoutDuration.toString(), + timeoutReason, + interaction.guild, + discordUser.communicationDisabledUntil, + ), + ], + }); } catch { if (modLogsChannel) { await interaction.followUp({ embeds: [DMFailed(discordUser.user)], ephemeral: true }); @@ -146,7 +163,11 @@ export async function handleTimeoutInfraction(interaction: ChatInputCommandInter } //Send a mod log to the mod logs channel try { - await modLogsChannel.send({ embeds: [modLogEmbed(moderator, discordUser.user, timeoutReason, timeoutDuration.toString(), formattedDate)] }); + await modLogsChannel.send({ + embeds: [ + modLogEmbed(moderator, discordUser.user, timeoutReason, timeoutDuration.toString(), formattedDate), + ], + }); } catch { await interaction.followUp({ embeds: [noModLogs], ephemeral: true }); return; diff --git a/src/commands/moderation/infractions/functions/unbanInfractions.ts b/src/commands/moderation/infractions/functions/unbanInfractions.ts index 48894f24..964566e1 100644 --- a/src/commands/moderation/infractions/functions/unbanInfractions.ts +++ b/src/commands/moderation/infractions/functions/unbanInfractions.ts @@ -9,44 +9,48 @@ const noConnEmbed = makeEmbed({ color: Colors.Red, }); -const failedUnbanEmbed = (userID: string) => makeEmbed({ - title: 'Unban - Failed', - description: `Failed to Unban ${userID}, this user may not be banned.`, - color: Colors.Red, -}); - -const unbanEmbed = (userID: string) => makeEmbed({ - title: `${userID} was unbanned successfully`, - color: Colors.Green, -}); - -const modLogEmbed = (moderator: User, userID: string, banReason: string, formattedDate: string) => makeEmbed({ - author: { name: `[UNBANNED] ${userID}` }, - fields: [ - { - name: 'User', - value: userID, - }, - { - name: 'Moderator', - value: `${moderator}`, - }, - { - name: 'Reason', - value: `\u200B${banReason}`, - }, - { - name: 'Date', - value: formattedDate, - }, - ], - footer: { text: `User ID: ${userID}` }, - color: Colors.Red, -}); +const failedUnbanEmbed = (userID: string) => + makeEmbed({ + title: 'Unban - Failed', + description: `Failed to Unban ${userID}, this user may not be banned.`, + color: Colors.Red, + }); + +const unbanEmbed = (userID: string) => + makeEmbed({ + title: `${userID} was unbanned successfully`, + color: Colors.Green, + }); + +const modLogEmbed = (moderator: User, userID: string, banReason: string, formattedDate: string) => + makeEmbed({ + author: { name: `[UNBANNED] ${userID}` }, + fields: [ + { + name: 'User', + value: userID, + }, + { + name: 'Moderator', + value: `${moderator}`, + }, + { + name: 'Reason', + value: `\u200B${banReason}`, + }, + { + name: 'Date', + value: formattedDate, + }, + ], + footer: { text: `User ID: ${userID}` }, + color: Colors.Red, + }); const noModLogs = makeEmbed({ title: 'Unban - No Mod Log', - description: 'I can\'t find the mod logs channel. I will still try to unban the user. Please check the channel still exists.', + description: + "I can't find the mod logs channel. I will still try to unban the user. Please check the channel still exists.", color: Colors.Red, }); @@ -72,9 +76,7 @@ export async function handleUnbanInfraction(interaction: ChatInputCommandInterac const moderator = interaction.user; const currentDate = new Date(); - const formattedDate: string = moment(currentDate) - .utcOffset(0) - .format(); + const formattedDate: string = moment(currentDate).utcOffset(0).format(); const modLogsChannel = interaction.guild.channels.resolve(constantsConfig.channels.MOD_LOGS) as TextChannel; //Check if the mod logs channel exists diff --git a/src/commands/moderation/infractions/functions/userNote.ts b/src/commands/moderation/infractions/functions/userNote.ts index 30d58cad..4e2ef024 100644 --- a/src/commands/moderation/infractions/functions/userNote.ts +++ b/src/commands/moderation/infractions/functions/userNote.ts @@ -15,41 +15,43 @@ const noteFailed = makeEmbed({ color: Colors.Red, }); -const modLogEmbed = (formattedDate: any, moderator: User, discordUser: User, note: string) => makeEmbed({ - author: { - name: `[NOTE] ${discordUser.tag}`, - iconURL: discordUser.displayAvatarURL(), - }, - fields: [ - { - inline: false, - name: 'User', - value: discordUser.toString(), +const modLogEmbed = (formattedDate: any, moderator: User, discordUser: User, note: string) => + makeEmbed({ + author: { + name: `[NOTE] ${discordUser.tag}`, + iconURL: discordUser.displayAvatarURL(), }, - { - inline: false, - name: 'Moderator', - value: moderator.toString(), - }, - { - inline: false, - name: 'Note', - value: note, - }, - { - inline: false, - name: 'Date', - value: formattedDate, - }, - ], - footer: { text: `User ID: ${discordUser.id}` }, - color: Colors.Red, -}); - -const noteEmbed = (user: User) => makeEmbed({ - title: `Note for ${user.tag} has been added successfully`, - color: Colors.Green, -}); + fields: [ + { + inline: false, + name: 'User', + value: discordUser.toString(), + }, + { + inline: false, + name: 'Moderator', + value: moderator.toString(), + }, + { + inline: false, + name: 'Note', + value: note, + }, + { + inline: false, + name: 'Date', + value: formattedDate, + }, + ], + footer: { text: `User ID: ${discordUser.id}` }, + color: Colors.Red, + }); + +const noteEmbed = (user: User) => + makeEmbed({ + title: `Note for ${user.tag} has been added successfully`, + color: Colors.Green, + }); const noModLogs = makeEmbed({ title: 'Note - No Mod Log', diff --git a/src/commands/moderation/infractions/functions/warn.ts b/src/commands/moderation/infractions/functions/warn.ts index 120e89f8..62a76dac 100644 --- a/src/commands/moderation/infractions/functions/warn.ts +++ b/src/commands/moderation/infractions/functions/warn.ts @@ -9,74 +9,79 @@ const noConnEmbed = makeEmbed({ color: Colors.Red, }); -const warnFailed = (discordUser: User) => makeEmbed({ - title: 'Warn - Failed', - description: `Failed to warn ${discordUser.toString()}, doc not saved to mongoDB`, - color: Colors.Red, -}); - -const dmEmbed = (guild: Guild, formattedDate: any, moderator: User, reason: string) => makeEmbed({ - title: `You have been warned in ${guild.name}`, - fields: [ - { - inline: false, - name: 'Moderator', - value: moderator.toString(), - }, - { - inline: false, - name: 'Reason', - value: reason, - }, - { - inline: false, - name: 'Date', - value: formattedDate, - }, - ], -}); - -const noDM = (discordUser: User) => makeEmbed({ - title: 'Warn - DM not sent', - description: `DM was not sent to ${discordUser.toString()}, they either have DMs closed or share no mutual servers with the bot.`, - color: Colors.Red, -}); - -const modLogEmbed = (formattedDate: any, moderator: User, discordUser: User, reason: string) => makeEmbed({ - author: { - name: `[WARNED] ${discordUser.tag}`, - iconURL: discordUser.displayAvatarURL(), - }, - fields: [ - { - inline: false, - name: 'User', - value: discordUser.toString(), - }, - { - inline: false, - name: 'Moderator', - value: moderator.toString(), - }, - { - inline: false, - name: 'Reason', - value: reason, - }, - { - inline: false, - name: 'Date', - value: formattedDate, +const warnFailed = (discordUser: User) => + makeEmbed({ + title: 'Warn - Failed', + description: `Failed to warn ${discordUser.toString()}, doc not saved to mongoDB`, + color: Colors.Red, + }); + +const dmEmbed = (guild: Guild, formattedDate: any, moderator: User, reason: string) => + makeEmbed({ + title: `You have been warned in ${guild.name}`, + fields: [ + { + inline: false, + name: 'Moderator', + value: moderator.toString(), + }, + { + inline: false, + name: 'Reason', + value: reason, + }, + { + inline: false, + name: 'Date', + value: formattedDate, + }, + ], + }); + +const noDM = (discordUser: User) => + makeEmbed({ + title: 'Warn - DM not sent', + description: `DM was not sent to ${discordUser.toString()}, they either have DMs closed or share no mutual servers with the bot.`, + color: Colors.Red, + }); + +const modLogEmbed = (formattedDate: any, moderator: User, discordUser: User, reason: string) => + makeEmbed({ + author: { + name: `[WARNED] ${discordUser.tag}`, + iconURL: discordUser.displayAvatarURL(), }, - ], - footer: { text: `User ID: ${discordUser.id}` }, - color: Colors.Red, -}); - -const warnEmbed = (discordUser: User) => makeEmbed({ - title: `${discordUser.tag} was warned successfully`, - color: Colors.Green, -}); + fields: [ + { + inline: false, + name: 'User', + value: discordUser.toString(), + }, + { + inline: false, + name: 'Moderator', + value: moderator.toString(), + }, + { + inline: false, + name: 'Reason', + value: reason, + }, + { + inline: false, + name: 'Date', + value: formattedDate, + }, + ], + footer: { text: `User ID: ${discordUser.id}` }, + color: Colors.Red, + }); + +const warnEmbed = (discordUser: User) => + makeEmbed({ + title: `${discordUser.tag} was warned successfully`, + color: Colors.Green, + }); const noModLogs = makeEmbed({ title: 'Warn - No Mod Log', diff --git a/src/commands/moderation/infractions/infractions.ts b/src/commands/moderation/infractions/infractions.ts index 4da67f02..7aa8e177 100644 --- a/src/commands/moderation/infractions/infractions.ts +++ b/src/commands/moderation/infractions/infractions.ts @@ -197,33 +197,33 @@ export default slashCommand(data, async ({ interaction }) => { const subcommandName = interaction.options.getSubcommand(); switch (subcommandName) { - case 'list': - const userID = interaction.options.getUser('tag_or_id')?.id; - await handleListInfraction(interaction, userID, false); - break; - case 'delete': - await handleDeleteInfraction(interaction); - break; - case 'note': - await handleUserNoteInfraction(interaction); - break; - case 'warn': - await handleWarnInfraction(interaction); - break; - case 'timeout': - await handleTimeoutInfraction(interaction); - break; - case 'remove-timeout': - await handleRemoveTimeoutInfraction(interaction); - break; - case 'ban': - await handleBanInfraction(interaction); - break; - case 'unban': - await handleUnbanInfraction(interaction); - break; + case 'list': + const userID = interaction.options.getUser('tag_or_id')?.id; + await handleListInfraction(interaction, userID, false); + break; + case 'delete': + await handleDeleteInfraction(interaction); + break; + case 'note': + await handleUserNoteInfraction(interaction); + break; + case 'warn': + await handleWarnInfraction(interaction); + break; + case 'timeout': + await handleTimeoutInfraction(interaction); + break; + case 'remove-timeout': + await handleRemoveTimeoutInfraction(interaction); + break; + case 'ban': + await handleBanInfraction(interaction); + break; + case 'unban': + await handleUnbanInfraction(interaction); + break; - default: - await interaction.reply({ content: 'Unknown subcommand', ephemeral: true }); + default: + await interaction.reply({ content: 'Unknown subcommand', ephemeral: true }); } }); diff --git a/src/commands/moderation/listRoleUsers.ts b/src/commands/moderation/listRoleUsers.ts index 8702463d..1da6ed73 100644 --- a/src/commands/moderation/listRoleUsers.ts +++ b/src/commands/moderation/listRoleUsers.ts @@ -1,5 +1,12 @@ import { ApplicationCommandOptionType, ApplicationCommandType } from 'discord.js'; -import { constantsConfig, Logger, makeEmbed, createPaginatedEmbedHandler, slashCommand, slashCommandStructure } from '../../lib'; +import { + constantsConfig, + Logger, + makeEmbed, + createPaginatedEmbedHandler, + slashCommand, + slashCommandStructure, +} from '../../lib'; const data = slashCommandStructure({ name: 'list-role-users', @@ -41,10 +48,12 @@ export default slashCommand(data, async ({ interaction }) => { membersAddedToPage++; if (membersAddedToPage >= pageLimit) { - embeds.push(makeEmbed({ - title: `Role Users | ${role.name} - Page ${currentPage + 1} of ${totalPages}`, - description, - })); + embeds.push( + makeEmbed({ + title: `Role Users | ${role.name} - Page ${currentPage + 1} of ${totalPages}`, + description, + }), + ); description = ''; membersAddedToPage = 0; currentPage++; @@ -52,10 +61,12 @@ export default slashCommand(data, async ({ interaction }) => { } if (description.trim() !== '') { - embeds.push(makeEmbed({ - title: `Role Users | ${role.name} - Page ${currentPage + 1} of ${totalPages}`, - description, - })); + embeds.push( + makeEmbed({ + title: `Role Users | ${role.name} - Page ${currentPage + 1} of ${totalPages}`, + description, + }), + ); } if (embeds.length === 0) { diff --git a/src/commands/moderation/roleAssignment.ts b/src/commands/moderation/roleAssignment.ts index 0ad0c832..d9e32428 100644 --- a/src/commands/moderation/roleAssignment.ts +++ b/src/commands/moderation/roleAssignment.ts @@ -1,9 +1,4 @@ -import { - ActionRowBuilder, - ApplicationCommandType, - ButtonBuilder, - ButtonStyle, -} from 'discord.js'; +import { ActionRowBuilder, ApplicationCommandType, ButtonBuilder, ButtonStyle } from 'discord.js'; import { constantsConfig, makeEmbed, slashCommand, slashCommandStructure } from '../../lib'; const data = slashCommandStructure({ @@ -16,7 +11,8 @@ const data = slashCommandStructure({ const interestedInEmbed = makeEmbed({ title: 'Role Assignment', - description: 'Please react below to set your role according to your skill set. If you do not have the skills in any of the available roles, please do not react as this will not benefit the development of the addon.', + description: + 'Please react below to set your role according to your skill set. If you do not have the skills in any of the available roles, please do not react as this will not benefit the development of the addon.', }); const mediaAnnouncementsEmbed = makeEmbed({ @@ -78,12 +74,12 @@ export default slashCommand(data, async ({ interaction }) => { // Create a single embed for each group type and add all rows to it const interestedInEmbedWithRows = { embeds: [interestedInEmbed], - components: [] as ActionRowBuilder[], + components: [], }; const mediaAnnouncementsEmbedWithRows = { embeds: [mediaAnnouncementsEmbed], - components: [] as ActionRowBuilder[], + components: [], }; interestedInRows.forEach((row) => { diff --git a/src/commands/moderation/rules.ts b/src/commands/moderation/rules.ts index c0c83960..7cfdd839 100644 --- a/src/commands/moderation/rules.ts +++ b/src/commands/moderation/rules.ts @@ -49,7 +49,7 @@ const DISCUSSION_EMBED = makeEmbed({ '- Use of slurs or any form of bigotry is not tolerated', '- No inappropriate, NSFW or NSFL content like (but not limited to) nudity, pornography, gore, ...', '- No general spam', - '- Do not send multiple unsolicited DM\'s', + "- Do not send multiple unsolicited DM's", '- No troll or insensitive messaging, including insensitive inside jokes', '- Inappropriate/offensive profile information/picture will not be tolerated', '- Certain topics like politics, religion and other sensitive subjects will only be tolerated if a careful and respectful conversation is held', @@ -67,7 +67,9 @@ const ROLE_EMBED = makeEmbed({ export default slashCommand(data, async ({ interaction }) => { if (interaction.channel) { - await interaction.channel.send({ embeds: [RULES_EMBED, FAQ_EMBED, POLICIES_EMBED, DISCUSSION_EMBED, ROLE_EMBED] }); + await interaction.channel.send({ + embeds: [RULES_EMBED, FAQ_EMBED, POLICIES_EMBED, DISCUSSION_EMBED, ROLE_EMBED], + }); } else { await interaction.reply({ content: 'This command can only be used in a server.', ephemeral: true }); } diff --git a/src/commands/moderation/slowmode/functions/disable.ts b/src/commands/moderation/slowmode/functions/disable.ts index 2f5dd384..f9f3fb30 100644 --- a/src/commands/moderation/slowmode/functions/disable.ts +++ b/src/commands/moderation/slowmode/functions/disable.ts @@ -1,9 +1,24 @@ import { ChannelType, ChatInputCommandInteraction, Colors } from 'discord.js'; import { Logger } from '../../../../lib'; -export async function handleDisableSlowmode(interaction: ChatInputCommandInteraction<'cached'>, slowmodeChannel: any, modLogsChannel: any, scheduler: any, failedEmbed: any, noChannelEmbed: any, successEmbed: any, modLogEmbed: any, slowModeEmbedField: any) { +export async function handleDisableSlowmode( + interaction: ChatInputCommandInteraction<'cached'>, + slowmodeChannel: any, + modLogsChannel: any, + scheduler: any, + failedEmbed: any, + noChannelEmbed: any, + successEmbed: any, + modLogEmbed: any, + slowModeEmbedField: any, +) { try { - if (slowmodeChannel.type === ChannelType.GuildForum || slowmodeChannel.type === ChannelType.GuildText || slowmodeChannel.type === ChannelType.PrivateThread || slowmodeChannel.type === ChannelType.PublicThread) { + if ( + slowmodeChannel.type === ChannelType.GuildForum || + slowmodeChannel.type === ChannelType.GuildText || + slowmodeChannel.type === ChannelType.PrivateThread || + slowmodeChannel.type === ChannelType.PublicThread + ) { await slowmodeChannel.setRateLimitPerUser(0, 'Slow mode disabled through bot'); if (scheduler) { await scheduler.cancel({ name: 'autoDisableSlowMode', data: { channelId: slowmodeChannel.id } }); @@ -17,14 +32,13 @@ export async function handleDisableSlowmode(interaction: ChatInputCommandInterac try { await modLogsChannel.send({ - embeds: [modLogEmbed('disabled', - slowModeEmbedField( - interaction.user.toString(), - slowmodeChannel.id, - 0, - 0, + embeds: [ + modLogEmbed( + 'disabled', + slowModeEmbedField(interaction.user.toString(), slowmodeChannel.id, 0, 0), + Colors.Green, ), - Colors.Green)], + ], }); } catch { await interaction.reply({ embeds: [noChannelEmbed('Disable', 'Mod Log')] }); diff --git a/src/commands/moderation/slowmode/functions/set.ts b/src/commands/moderation/slowmode/functions/set.ts index 857d504b..e31199f7 100644 --- a/src/commands/moderation/slowmode/functions/set.ts +++ b/src/commands/moderation/slowmode/functions/set.ts @@ -1,8 +1,25 @@ import { ChannelType, ChatInputCommandInteraction, Colors } from 'discord.js'; -export async function handleSetSlowmode(interaction: ChatInputCommandInteraction<'cached'>, duration: number, slowmodeChannel: any, autoDisable: any, modLogsChannel: any, scheduler: any, failedEmbed: any, noChannelEmbed: any, successEmbed: any, modLogEmbed: any, slowModeEmbedField: any) { +export async function handleSetSlowmode( + interaction: ChatInputCommandInteraction<'cached'>, + duration: number, + slowmodeChannel: any, + autoDisable: any, + modLogsChannel: any, + scheduler: any, + failedEmbed: any, + noChannelEmbed: any, + successEmbed: any, + modLogEmbed: any, + slowModeEmbedField: any, +) { try { - if (slowmodeChannel.type === ChannelType.GuildForum || slowmodeChannel.type === ChannelType.GuildText || slowmodeChannel.type === ChannelType.PrivateThread || slowmodeChannel.type === ChannelType.PublicThread) { + if ( + slowmodeChannel.type === ChannelType.GuildForum || + slowmodeChannel.type === ChannelType.GuildText || + slowmodeChannel.type === ChannelType.PrivateThread || + slowmodeChannel.type === ChannelType.PublicThread + ) { await slowmodeChannel.setRateLimitPerUser(duration / 1000, 'Slow mode enabled through bot'); if (scheduler) { await scheduler.cancel({ name: 'autoDisableSlowMode', data: { channelId: slowmodeChannel.id } }); @@ -19,14 +36,18 @@ export async function handleSetSlowmode(interaction: ChatInputCommandInteraction try { await modLogsChannel.send({ - embeds: [modLogEmbed('Set', - slowModeEmbedField( - interaction.user.toString(), - slowmodeChannel.id, - duration, - autoDisable && scheduler ? autoDisable.toString() : 0, + embeds: [ + modLogEmbed( + 'Set', + slowModeEmbedField( + interaction.user.toString(), + slowmodeChannel.id, + duration, + autoDisable && scheduler ? autoDisable.toString() : 0, + ), + Colors.Green, ), - Colors.Green)], + ], }); } catch { await interaction.reply({ embeds: [noChannelEmbed('set', 'mod logs')], ephemeral: true }); diff --git a/src/commands/moderation/slowmode/slowmode.ts b/src/commands/moderation/slowmode/slowmode.ts index f192e5c0..85522a0b 100644 --- a/src/commands/moderation/slowmode/slowmode.ts +++ b/src/commands/moderation/slowmode/slowmode.ts @@ -1,5 +1,12 @@ import { ApplicationCommandOptionType, ApplicationCommandType, Colors, EmbedField, TextChannel } from 'discord.js'; -import { constantsConfig, slashCommand, slashCommandStructure, makeEmbed, durationInEnglish, getScheduler } from '../../../lib'; +import { + constantsConfig, + slashCommand, + slashCommandStructure, + makeEmbed, + durationInEnglish, + getScheduler, +} from '../../../lib'; import { handleSetSlowmode } from './functions/set'; import { handleDisableSlowmode } from './functions/disable'; @@ -85,19 +92,26 @@ const noSchedulerEmbed = makeEmbed({ color: Colors.Red, }); -const failedEmbed = (action: string, channel: string) => makeEmbed({ - title: `Slow Mode - ${action} failed`, - description: `Failed to ${action} the slow mode for channel <@${channel}>.`, - color: Colors.Red, -}); +const failedEmbed = (action: string, channel: string) => + makeEmbed({ + title: `Slow Mode - ${action} failed`, + description: `Failed to ${action} the slow mode for channel <@${channel}>.`, + color: Colors.Red, + }); -const modLogEmbed = (action: string, fields: any, color: number) => makeEmbed({ - title: `Slow Mode - ${action}`, - fields, - color, -}); +const modLogEmbed = (action: string, fields: any, color: number) => + makeEmbed({ + title: `Slow Mode - ${action}`, + fields, + color, + }); -const slowModeEmbedField = (moderator: string, channel: string, duration: number, autoDisable: string): EmbedField[] => [ +const slowModeEmbedField = ( + moderator: string, + channel: string, + duration: number, + autoDisable: string, +): EmbedField[] => [ { inline: true, name: 'Channel', @@ -120,17 +134,19 @@ const slowModeEmbedField = (moderator: string, channel: string, duration: number }, ]; -const noChannelEmbed = (action:string, channelName: string) => makeEmbed({ - title: `Slow Mode - ${action} - No ${channelName} channel`, - description: `The command was successful, but no message to ${channelName} was sent. Please check the channel still exists.`, - color: Colors.Yellow, -}); +const noChannelEmbed = (action: string, channelName: string) => + makeEmbed({ + title: `Slow Mode - ${action} - No ${channelName} channel`, + description: `The command was successful, but no message to ${channelName} was sent. Please check the channel still exists.`, + color: Colors.Yellow, + }); -const successEmbed = (action: string, channel: string) => makeEmbed({ - title: `Slow Mode - ${action} successful`, - description: `Slow mode for channel <#${channel}> has been ${action} successfully.`, - color: Colors.Green, -}); +const successEmbed = (action: string, channel: string) => + makeEmbed({ + title: `Slow Mode - ${action} successful`, + description: `Slow mode for channel <#${channel}> has been ${action} successfully.`, + color: Colors.Green, + }); export default slashCommand(data, async ({ interaction }) => { const scheduler = getScheduler(); @@ -146,14 +162,36 @@ export default slashCommand(data, async ({ interaction }) => { const subcommandName = interaction.options.getSubcommand(); switch (subcommandName) { - case 'set': - await handleSetSlowmode(interaction, duration, slowmodeChannel, autoDisable, modLogsChannel, scheduler, failedEmbed, noChannelEmbed, successEmbed, modLogEmbed, slowModeEmbedField); - break; - case 'disable': - await handleDisableSlowmode(interaction, slowmodeChannel, modLogsChannel, scheduler, failedEmbed, noChannelEmbed, successEmbed, modLogEmbed, slowModeEmbedField); - break; + case 'set': + await handleSetSlowmode( + interaction, + duration, + slowmodeChannel, + autoDisable, + modLogsChannel, + scheduler, + failedEmbed, + noChannelEmbed, + successEmbed, + modLogEmbed, + slowModeEmbedField, + ); + break; + case 'disable': + await handleDisableSlowmode( + interaction, + slowmodeChannel, + modLogsChannel, + scheduler, + failedEmbed, + noChannelEmbed, + successEmbed, + modLogEmbed, + slowModeEmbedField, + ); + break; - default: - await interaction.reply({ content: 'Unknown subcommand', ephemeral: true }); + default: + await interaction.reply({ content: 'Unknown subcommand', ephemeral: true }); } }); diff --git a/src/commands/moderation/welcome.ts b/src/commands/moderation/welcome.ts index 2b1f160e..bb6889c1 100644 --- a/src/commands/moderation/welcome.ts +++ b/src/commands/moderation/welcome.ts @@ -25,7 +25,6 @@ const WELCOME_EMBED = makeEmbed({ '', `Feel free to download, test, and share your feedback, or if you are interested in developing, assign your <#${constantsConfig.channels.ROLES}>, and get cracking!`, ]), - }); const SOCIAL_EMBED = makeEmbed({ @@ -50,7 +49,8 @@ const SUPPORT_EMBED = makeEmbed({ const IMPORTANT_INFO_EMBED = makeEmbed({ title: '<:Partnered:921520970123059231> FlyByWireSimulations | Important Info', - description: 'By being a member of our Discord Server, you agree to the following, and failure to do so can result in removal from the server.', + description: + 'By being a member of our Discord Server, you agree to the following, and failure to do so can result in removal from the server.', fields: [ { name: 'Appropriate Content', @@ -92,7 +92,6 @@ const HELP_EMBED = makeEmbed({ name: 'Flight School', value: `We've opened our <#${constantsConfig.channels.FLIGHT_SCHOOL}> channel for any questions you have pertaining to the operation of the A32NX in the simulator.`, }, - ], }); diff --git a/src/commands/moderation/whois.ts b/src/commands/moderation/whois.ts index 917cba5a..23a3fd5f 100644 --- a/src/commands/moderation/whois.ts +++ b/src/commands/moderation/whois.ts @@ -8,12 +8,14 @@ const data = slashCommandStructure({ type: ApplicationCommandType.ChatInput, default_member_permissions: constantsConfig.commandPermission.MANAGE_SERVER, //Overrides need to be added for admin and moderator roles dm_permission: false, - options: [{ - name: 'tag_or_id', - description: 'Provide a user\'s tag or id to get information about them.', - type: ApplicationCommandOptionType.User, - required: false, - }], + options: [ + { + name: 'tag_or_id', + description: "Provide a user's tag or id to get information about them.", + type: ApplicationCommandOptionType.User, + required: false, + }, + ], }); const beautifiedStatus: { [key: string]: string } = { @@ -72,7 +74,11 @@ export default slashCommand(data, async ({ interaction }) => { }, { name: 'Permissions', - value: targetMember.permissions.toArray().join(', ').toLowerCase().replace(/_/g, ' ') + value: targetMember.permissions + .toArray() + .join(', ') + .toLowerCase() + .replace(/_/g, ' ') .replace(/(^\w)|(\s+\w)/g, (char) => char.toUpperCase()), }, ], diff --git a/src/commands/utils/avatar.ts b/src/commands/utils/avatar.ts index 941e37e4..6c3f1bb6 100644 --- a/src/commands/utils/avatar.ts +++ b/src/commands/utils/avatar.ts @@ -3,14 +3,16 @@ import { slashCommand, slashCommandStructure, makeEmbed } from '../../lib'; const data = slashCommandStructure({ name: 'avatar', - description: 'Shows the selected user\'s avatar', + description: "Shows the selected user's avatar", type: ApplicationCommandType.ChatInput, - options: [{ - name: 'tag_or_id', - description: 'Please provide a user tag or ID.', - type: ApplicationCommandOptionType.User, - required: false, - }], + options: [ + { + name: 'tag_or_id', + description: 'Please provide a user tag or ID.', + type: ApplicationCommandOptionType.User, + required: false, + }, + ], }); export default slashCommand(data, async ({ interaction }) => { diff --git a/src/commands/utils/birthday/birthday.ts b/src/commands/utils/birthday/birthday.ts index 71fab53f..1efc77e7 100644 --- a/src/commands/utils/birthday/birthday.ts +++ b/src/commands/utils/birthday/birthday.ts @@ -84,17 +84,17 @@ export default slashCommand(data, async ({ interaction }) => { const subcommandName = interaction.options.getSubcommand(); switch (subcommandName) { - case 'set': - await handleSetBirthday(interaction); - break; - case 'remove': - await handleRemoveBirthday(interaction); - break; - case 'list': - await handleListBirthday(interaction); - break; + case 'set': + await handleSetBirthday(interaction); + break; + case 'remove': + await handleRemoveBirthday(interaction); + break; + case 'list': + await handleListBirthday(interaction); + break; - default: - await interaction.reply({ content: 'Unknown subcommand', ephemeral: true }); + default: + await interaction.reply({ content: 'Unknown subcommand', ephemeral: true }); } }); diff --git a/src/commands/utils/birthday/functions/listBirthday.ts b/src/commands/utils/birthday/functions/listBirthday.ts index 82369cad..023fc671 100644 --- a/src/commands/utils/birthday/functions/listBirthday.ts +++ b/src/commands/utils/birthday/functions/listBirthday.ts @@ -1,18 +1,19 @@ import { ChatInputCommandInteraction } from 'discord.js'; import { Birthday, Logger, makeEmbed } from '../../../../lib'; -const birthdayListEmbed = (fields: Array) => makeEmbed({ - title: 'Birthday - Birthday List', - description: fields.length > 0 ? undefined : 'No birthdays set', - fields, -}); +const birthdayListEmbed = (fields: Array) => + makeEmbed({ + title: 'Birthday - Birthday List', + description: fields.length > 0 ? undefined : 'No birthdays set', + fields, + }); export async function handleListBirthday(interaction: ChatInputCommandInteraction<'cached'>) { await interaction.deferReply(); try { const birthdays = await Birthday.find({}).sort({ day: 1 }); // Only day sort required, months are bucketized - const members = await interaction.guild!.members.fetch(); + const members = await interaction.guild.members.fetch(); const monthBuckets: Array> = [ ['January', []], @@ -30,10 +31,12 @@ export async function handleListBirthday(interaction: ChatInputCommandInteractio ]; for (const birthday of birthdays) { - const member = members.get(birthday.userID!); + const member = members.get(birthday.userID); if (member) { - monthBuckets[birthday.utcDatetime!.getUTCMonth()][1].push(`${member.displayName} - ${birthday.day}/${birthday.month} (Z${birthday.timezone! < 0 ? '' : '+'}${birthday.timezone})`); + monthBuckets[birthday.utcDatetime!.getUTCMonth()][1].push( + `${member.displayName} - ${birthday.day}/${birthday.month} (Z${birthday.timezone! < 0 ? '' : '+'}${birthday.timezone})`, + ); } } diff --git a/src/commands/utils/birthday/functions/removeBirthday.ts b/src/commands/utils/birthday/functions/removeBirthday.ts index 49c4539e..a2d6d90b 100644 --- a/src/commands/utils/birthday/functions/removeBirthday.ts +++ b/src/commands/utils/birthday/functions/removeBirthday.ts @@ -1,16 +1,18 @@ import { ChatInputCommandInteraction, Colors, User } from 'discord.js'; import { Birthday, makeEmbed } from '../../../../lib'; -const noBirthdayEmbed = (discordUser: User) => makeEmbed({ - title: 'Birthday remove failed', - description: `${discordUser} doesn't have a birthday set`, - color: Colors.Red, -}); +const noBirthdayEmbed = (discordUser: User) => + makeEmbed({ + title: 'Birthday remove failed', + description: `${discordUser} doesn't have a birthday set`, + color: Colors.Red, + }); -const birthdayRemovedEmbed = (discordUser: User) => makeEmbed({ - title: 'Birthday removed', - description: `${discordUser}'s birthday has been removed`, -}); +const birthdayRemovedEmbed = (discordUser: User) => + makeEmbed({ + title: 'Birthday removed', + description: `${discordUser}'s birthday has been removed`, + }); export async function handleRemoveBirthday(interaction: ChatInputCommandInteraction<'cached'>) { const userID = interaction.user.id; diff --git a/src/commands/utils/birthday/functions/setBirthday.ts b/src/commands/utils/birthday/functions/setBirthday.ts index 67714cfb..e55879db 100644 --- a/src/commands/utils/birthday/functions/setBirthday.ts +++ b/src/commands/utils/birthday/functions/setBirthday.ts @@ -31,10 +31,11 @@ const invalidDateEmbed = makeEmbed({ color: Colors.Red, }); -const birthdaySetEmbed = (discordUser: User, birthdayDay: number, birthdayMonth: number, birthdayTimezone: number) => makeEmbed({ - title: 'Birthday - Birthday Set', - description: `${discordUser}'s birthday has been set to ${birthdayDay}/${birthdayMonth} and their timezone is UTC${birthdayTimezone < 0 ? '' : '+'}${birthdayTimezone}`, -}); +const birthdaySetEmbed = (discordUser: User, birthdayDay: number, birthdayMonth: number, birthdayTimezone: number) => + makeEmbed({ + title: 'Birthday - Birthday Set', + description: `${discordUser}'s birthday has been set to ${birthdayDay}/${birthdayMonth} and their timezone is UTC${birthdayTimezone < 0 ? '' : '+'}${birthdayTimezone}`, + }); export async function handleSetBirthday(interaction: ChatInputCommandInteraction<'cached'>) { const selectedDay = interaction.options.getInteger('day')!; diff --git a/src/commands/utils/count.ts b/src/commands/utils/count.ts index ad6bf7dd..1f3b13f0 100644 --- a/src/commands/utils/count.ts +++ b/src/commands/utils/count.ts @@ -17,7 +17,7 @@ const data = slashCommandStructure({ }); export default slashCommand(data, async ({ interaction }) => { -// check if user has the role + // check if user has the role const hasRole = interaction.member.roles.cache.has(constantsConfig.roles.BOT_DEVELOPER); if (!hasRole) { @@ -25,7 +25,7 @@ export default slashCommand(data, async ({ interaction }) => { return; } - const countThread = interaction.guild.channels.resolve(constantsConfig.threads.COUNT_THREAD) as TextChannel | null; + const countThread = interaction.guild.channels.resolve(constantsConfig.threads.COUNT_THREAD); if (!countThread) { await interaction.reply({ content: 'Count thread not found.', ephemeral: true }); diff --git a/src/commands/utils/docSearch.ts b/src/commands/utils/docSearch.ts index 4a4ee487..fc941422 100644 --- a/src/commands/utils/docSearch.ts +++ b/src/commands/utils/docSearch.ts @@ -6,13 +6,15 @@ const data = slashCommandStructure({ name: 'doc-search', description: 'Searches the FlyByWire Documentation for a given query.', type: ApplicationCommandType.ChatInput, - options: [{ - name: 'query', - description: 'The query to search for.', - type: ApplicationCommandOptionType.String, - max_length: 100, - required: true, - }], + options: [ + { + name: 'query', + description: 'The query to search for.', + type: ApplicationCommandOptionType.String, + max_length: 100, + required: true, + }, + ], }); const DOCS_BASE_URL = 'https://docs.flybywiresim.com'; @@ -33,7 +35,9 @@ export default slashCommand(data, async ({ interaction }) => { color: Colors.Red, }); return interaction.reply({ embeds: [URLEmbed] }); - } catch (_) { /**/ } + } catch (_) { + /**/ + } const filter = new Filter(); if (filter.isProfane(searchWord)) { diff --git a/src/commands/utils/github/functions/githubPullRequest.ts b/src/commands/utils/github/functions/githubPullRequest.ts index c656d566..f656d479 100644 --- a/src/commands/utils/github/functions/githubPullRequest.ts +++ b/src/commands/utils/github/functions/githubPullRequest.ts @@ -35,7 +35,9 @@ export async function handleGithubPullRequest(interaction: ChatInputCommandInter } } else { try { - const response = await request('GET /repos/flybywiresim/a32nx/pulls/{pull_number}', { pull_number: cleanedPrNumber }); + const response = await request('GET /repos/flybywiresim/a32nx/pulls/{pull_number}', { + pull_number: cleanedPrNumber, + }); return interaction.reply(response.data.html_url); } catch { return interaction.reply({ embeds: [invalidEmbed] }); diff --git a/src/commands/utils/github/functions/handleGithubIssue.ts b/src/commands/utils/github/functions/handleGithubIssue.ts index cb7864a4..0611e36b 100644 --- a/src/commands/utils/github/functions/handleGithubIssue.ts +++ b/src/commands/utils/github/functions/handleGithubIssue.ts @@ -35,7 +35,9 @@ export async function handleGithubIssue(interaction: ChatInputCommandInteraction } } else { try { - const response = await request('GET /repos/flybywiresim/a32nx/issues/{issue_number}', { issue_number: cleanedIssueNumber }); + const response = await request('GET /repos/flybywiresim/a32nx/issues/{issue_number}', { + issue_number: cleanedIssueNumber, + }); return interaction.reply(response.data.html_url); } catch { return interaction.reply({ embeds: [invalidEmbed] }); diff --git a/src/commands/utils/github/github.ts b/src/commands/utils/github/github.ts index 3cfec522..0de351c8 100644 --- a/src/commands/utils/github/github.ts +++ b/src/commands/utils/github/github.ts @@ -12,36 +12,38 @@ const data = slashCommandStructure({ name: 'pr', description: 'Retrieves the link of the provided GitHub pull request.', type: ApplicationCommandOptionType.Subcommand, - options: [{ - name: 'pr_number', - description: 'Please provide the pull request number.', - type: ApplicationCommandOptionType.String, - required: true, - }, - { - name: 'repo', - description: 'Please provide the repo name.', - type: ApplicationCommandOptionType.String, - required: false, - }, + options: [ + { + name: 'pr_number', + description: 'Please provide the pull request number.', + type: ApplicationCommandOptionType.String, + required: true, + }, + { + name: 'repo', + description: 'Please provide the repo name.', + type: ApplicationCommandOptionType.String, + required: false, + }, ], }, { name: 'issue', description: 'Retrieves the link of the provided GitHub issue.', type: ApplicationCommandOptionType.Subcommand, - options: [{ - name: 'issue_number', - description: 'Please provide the issue number.', - type: ApplicationCommandOptionType.String, - required: true, - }, - { - name: 'repo', - description: 'Please provide the repo name.', - type: ApplicationCommandOptionType.String, - required: false, - }, + options: [ + { + name: 'issue_number', + description: 'Please provide the issue number.', + type: ApplicationCommandOptionType.String, + required: true, + }, + { + name: 'repo', + description: 'Please provide the repo name.', + type: ApplicationCommandOptionType.String, + required: false, + }, ], }, ], @@ -51,14 +53,14 @@ export default slashCommand(data, async ({ interaction }) => { const subcommandName = interaction.options.getSubcommand(); switch (subcommandName) { - case 'pr': - await handleGithubPullRequest(interaction); - break; - case 'issue': - await handleGithubIssue(interaction); - break; + case 'pr': + await handleGithubPullRequest(interaction); + break; + case 'issue': + await handleGithubIssue(interaction); + break; - default: - await interaction.reply({ content: 'Unknown subcommand', ephemeral: true }); + default: + await interaction.reply({ content: 'Unknown subcommand', ephemeral: true }); } }); diff --git a/src/commands/utils/help.ts b/src/commands/utils/help.ts index 7702a60a..3c92ee1e 100644 --- a/src/commands/utils/help.ts +++ b/src/commands/utils/help.ts @@ -46,52 +46,55 @@ export default slashCommand(data, async ({ interaction }: { interaction: Command const totalPages = Math.ceil(sortedCommands.length / pageLimit); // Build the description with subcommands and subcommand groups - const description = currentCommands.map((command) => { - let { description } = command; - - // Check if it's a context-specific message command - const isMessageCommand = command.type === ApplicationCommandType.Message; - - // Check if it's a context-specific user command - const isUserCommand = command.type === ApplicationCommandType.User; - - const subcommandList = command.options?.filter( - (option) => option.type === ApplicationCommandOptionType.Subcommand - || option.type === ApplicationCommandOptionType.SubcommandGroup, - ); - - if (subcommandList && subcommandList.length > 0) { - const subcommandDescription = subcommandList - .map((subcommand) => { - if (subcommand.type === ApplicationCommandOptionType.Subcommand) { - return subcommand.name; - } - if (subcommand.type === ApplicationCommandOptionType.SubcommandGroup) { - const groupSubcommands = subcommand.options?.filter( - (sub) => sub.type === ApplicationCommandOptionType.Subcommand, - ); - if (groupSubcommands && groupSubcommands.length > 0) { - return `${subcommand.name} [${groupSubcommands - .map((sub) => sub.name) - .join(', ')}]`; + const description = currentCommands + .map((command) => { + let { description } = command; + + // Check if it's a context-specific message command + const isMessageCommand = command.type === ApplicationCommandType.Message; + + // Check if it's a context-specific user command + const isUserCommand = command.type === ApplicationCommandType.User; + + const subcommandList = command.options?.filter( + (option) => + option.type === ApplicationCommandOptionType.Subcommand || + option.type === ApplicationCommandOptionType.SubcommandGroup, + ); + + if (subcommandList && subcommandList.length > 0) { + const subcommandDescription = subcommandList + .map((subcommand) => { + if (subcommand.type === ApplicationCommandOptionType.Subcommand) { + return subcommand.name; } - return `${subcommand.name} [None]`; - } - return ''; - }) - .join(', '); // Use a comma to separate subcommands - description += `\n**Subcommands and Groups:** \n${subcommandDescription}`; - } - - // Append a label for context-specific message and user commands - if (isMessageCommand) { - description += '\n(Context Command - Message)'; - } else if (isUserCommand) { - description += '\n(Context Command - User)'; - } - - return `**${command.name}**: ${description}`; - }).join('\n\n'); + if (subcommand.type === ApplicationCommandOptionType.SubcommandGroup) { + const groupSubcommands = subcommand.options?.filter( + (sub) => sub.type === ApplicationCommandOptionType.Subcommand, + ); + if (groupSubcommands && groupSubcommands.length > 0) { + return `${subcommand.name} [${groupSubcommands + .map((sub) => sub.name) + .join(', ')}]`; + } + return `${subcommand.name} [None]`; + } + return ''; + }) + .join(', '); // Use a comma to separate subcommands + description += `\n**Subcommands and Groups:** \n${subcommandDescription}`; + } + + // Append a label for context-specific message and user commands + if (isMessageCommand) { + description += '\n(Context Command - Message)'; + } else if (isUserCommand) { + description += '\n(Context Command - User)'; + } + + return `**${command.name}**: ${description}`; + }) + .join('\n\n'); const embed = makeEmbed({ title: `Bot Commands - Page ${page + 1} of ${totalPages}`, diff --git a/src/commands/utils/locate/functions/filterSearchResults.ts b/src/commands/utils/locate/functions/filterSearchResults.ts index c0779d4d..ceb1d4f6 100644 --- a/src/commands/utils/locate/functions/filterSearchResults.ts +++ b/src/commands/utils/locate/functions/filterSearchResults.ts @@ -3,7 +3,9 @@ import { Panel } from '../panels/panel'; export const filterSearchResults = (query: string, source: Map) => { // Get any target that includes the query string. - const possibleTargets = Array.from(source.keys()).filter((current) => current.toLowerCase().includes(query.toLowerCase())); + const possibleTargets = Array.from(source.keys()).filter((current) => + current.toLowerCase().includes(query.toLowerCase()), + ); // Sort possible targets based on the length of the match. -> More equal characters between query and target = higher ranking possibleTargets.sort((a, b) => a.indexOf(query) - b.indexOf(query)); diff --git a/src/commands/utils/locate/functions/handleCommand.ts b/src/commands/utils/locate/functions/handleCommand.ts index 9f339b6d..35ae8e24 100644 --- a/src/commands/utils/locate/functions/handleCommand.ts +++ b/src/commands/utils/locate/functions/handleCommand.ts @@ -15,17 +15,18 @@ const invalidTargetEmbed = makeEmbed({ color: Colors.Red, }); -const locateEmbed = (panel: Panel) => makeEmbed({ - title: panel.title, - url: panel.docsUrl, - description: makeLines([ - `Learn more about the ${panel.name} and the flight deck:`, - `* [${panel.name} Documentation](${panel.docsUrl})`, - `* [Flight Deck Overview](${panel.flightDeckUrl})`, - ]), - image: { url: panel.imageUrl }, - footer: { text: 'Tip: Click the image to view in full size' }, -}); +const locateEmbed = (panel: Panel) => + makeEmbed({ + title: panel.title, + url: panel.docsUrl, + description: makeLines([ + `Learn more about the ${panel.name} and the flight deck:`, + `* [${panel.name} Documentation](${panel.docsUrl})`, + `* [Flight Deck Overview](${panel.flightDeckUrl})`, + ]), + image: { url: panel.imageUrl }, + footer: { text: 'Tip: Click the image to view in full size' }, + }); export async function handleCommand(interaction: ChatInputCommandInteraction<'cached'>, panelMap: Map) { const target = interaction.options.getString('target'); diff --git a/src/commands/utils/locate/locate.ts b/src/commands/utils/locate/locate.ts index 13dd0f6e..a50b4838 100644 --- a/src/commands/utils/locate/locate.ts +++ b/src/commands/utils/locate/locate.ts @@ -68,34 +68,38 @@ const autocompleteCallback: AutocompleteCallback = ({ interaction }) => { let choices: ApplicationCommandOptionChoiceData[]; switch (subcommand) { - case 'a32nx': - choices = filterSearchResults(cleanTarget, a32nxPanelMap); - break; - /* case 'a380x': + case 'a32nx': + choices = filterSearchResults(cleanTarget, a32nxPanelMap); + break; + /* case 'a380x': choices = filterSearchResults(cleanTarget, a380xPanelMap); break; */ - default: - return interaction.respond([]); + default: + return interaction.respond([]); } return interaction.respond(choices); }; -export default slashCommand(data, async ({ interaction }) => { - await interaction.deferReply(); +export default slashCommand( + data, + async ({ interaction }) => { + await interaction.deferReply(); - const subcommand = interaction.options.getSubcommand(); + const subcommand = interaction.options.getSubcommand(); - switch (subcommand) { - case 'a32nx': - await handleCommand(interaction, a32nxPanelMap); - break; - /* case 'a380x': + switch (subcommand) { + case 'a32nx': + await handleCommand(interaction, a32nxPanelMap); + break; + /* case 'a380x': await handleCommand(interaction, a380xPanelMap); break; */ - default: - await interaction.editReply({ content: 'Unknown subcommand' }); - } -}, autocompleteCallback); + default: + await interaction.editReply({ content: 'Unknown subcommand' }); + } + }, + autocompleteCallback, +); diff --git a/src/commands/utils/locate/panels/a32nx/a32nx-panels.ts b/src/commands/utils/locate/panels/a32nx/a32nx-panels.ts index 51272118..91632077 100644 --- a/src/commands/utils/locate/panels/a32nx/a32nx-panels.ts +++ b/src/commands/utils/locate/panels/a32nx/a32nx-panels.ts @@ -1,9 +1,73 @@ import { Panel } from '../panel'; import { flyPad } from './flyPad'; -import { accuPressPanel, autobrakeAndGearPanel, clockPanel, dcdu, ewd, instrumentLightingPanel, isis, nd, pfd, sd } from './front-panel'; +import { + accuPressPanel, + autobrakeAndGearPanel, + clockPanel, + dcdu, + ewd, + instrumentLightingPanel, + isis, + nd, + pfd, + sd, +} from './front-panel'; import { efisPanel, fcuPanel, lightKnobsPanel, warningPanel } from './glareshield'; -import { antiIcePanel, adirsPanel, apuPanel, callsPanel, cvrPanel, emerElecPwrPanel, evacPanel, extLtPanel, fltCtlPanel, gpwsPanel, intLtPanel, oxyPanel, paVideoPanel, signsPanel, wiperPanel, cabinPressPanel, airCondPanel, elecPanel, fuelPanel, hydPanel, firePanel, engManStartPanel, ventilationPanel, cargoSmokePanel, cargoVentPanel, thirdACP, readingLightsJumpSeats, cockpitDoorIndicatorPanel, eltPanel, pedestalLightPanel, emerCbPanel, fmsLoadPanel, maintenancePanel } from './overhead'; -import { aidsDfdrPanel, atcTcasPanel, captPedestalLightingPanel, cockpitDoorPanel, console, ecamControlPanel, engPanel, flaps, gravityGearExtensionPanel, mcdu, parkBrkPanel, printer, rmpAcpPanel, rudderTrim, speedBrake, switchingPanel, thrLvrPitchTrim, wxPanel } from './pedestal'; +import { + antiIcePanel, + adirsPanel, + apuPanel, + callsPanel, + cvrPanel, + emerElecPwrPanel, + evacPanel, + extLtPanel, + fltCtlPanel, + gpwsPanel, + intLtPanel, + oxyPanel, + paVideoPanel, + signsPanel, + wiperPanel, + cabinPressPanel, + airCondPanel, + elecPanel, + fuelPanel, + hydPanel, + firePanel, + engManStartPanel, + ventilationPanel, + cargoSmokePanel, + cargoVentPanel, + thirdACP, + readingLightsJumpSeats, + cockpitDoorIndicatorPanel, + eltPanel, + pedestalLightPanel, + emerCbPanel, + fmsLoadPanel, + maintenancePanel, +} from './overhead'; +import { + aidsDfdrPanel, + atcTcasPanel, + captPedestalLightingPanel, + cockpitDoorPanel, + console, + ecamControlPanel, + engPanel, + flaps, + gravityGearExtensionPanel, + mcdu, + parkBrkPanel, + printer, + rmpAcpPanel, + rudderTrim, + speedBrake, + switchingPanel, + thrLvrPitchTrim, + wxPanel, +} from './pedestal'; import { rearBackCbPanel } from './rear-cb-panel'; export const a32nxPanels: Panel[] = [ diff --git a/src/commands/utils/locate/panels/a32nx/flyPad.ts b/src/commands/utils/locate/panels/a32nx/flyPad.ts index 36e4dc0a..0b8e7194 100644 --- a/src/commands/utils/locate/panels/a32nx/flyPad.ts +++ b/src/commands/utils/locate/panels/a32nx/flyPad.ts @@ -7,9 +7,5 @@ export const flyPad: Panel = { docsUrl: LOCATE_DOCS_BASE_URLS.a32nx.flypad, flightDeckUrl: LOCATE_DOCS_BASE_URLS.a32nx.flightdeck, imageUrl: `${LOCATE_IMAGE_BASE_URLS.a32nx.flypad}/efb_downscaled.gif`, - identifiers: [ - 'flypad', - 'efb', - 'electronic-flight-bag', - ], + identifiers: ['flypad', 'efb', 'electronic-flight-bag'], }; diff --git a/src/commands/utils/locate/panels/a32nx/front-panel.ts b/src/commands/utils/locate/panels/a32nx/front-panel.ts index 6a75d57b..50c2e862 100644 --- a/src/commands/utils/locate/panels/a32nx/front-panel.ts +++ b/src/commands/utils/locate/panels/a32nx/front-panel.ts @@ -51,13 +51,7 @@ export const nd: Panel = { docsUrl: `${FRONT_DOCS_BASE_URL}/nd`, flightDeckUrl: LOCATE_DOCS_BASE_URLS.a32nx.flightdeck, imageUrl: `${FRONT_IMAGE_BASE_URL}/nd.png`, - identifiers: [ - 'nd', - 'navigation-display', - 'weather-radar', - 'terrain-map', - 'terr-on-nd-switch', - ], + identifiers: ['nd', 'navigation-display', 'weather-radar', 'terrain-map', 'terr-on-nd-switch'], }; export const isis: Panel = { @@ -66,11 +60,7 @@ export const isis: Panel = { docsUrl: `${FRONT_DOCS_BASE_URL}/isis`, flightDeckUrl: LOCATE_DOCS_BASE_URLS.a32nx.flightdeck, imageUrl: `${FRONT_IMAGE_BASE_URL}/isis.png`, - identifiers: [ - 'isis', - 'integrated-standby-instrument-system', - 'backup-pfd', - ], + identifiers: ['isis', 'integrated-standby-instrument-system', 'backup-pfd'], }; export const dcdu: Panel = { @@ -79,11 +69,7 @@ export const dcdu: Panel = { docsUrl: `${FRONT_DOCS_BASE_URL}/dcdu`, flightDeckUrl: LOCATE_DOCS_BASE_URLS.a32nx.flightdeck, imageUrl: `${FRONT_IMAGE_BASE_URL}/dcdu.png`, - identifiers: [ - 'dcdu', - 'datalink-ctl-and-display-unit', - 'cpdlc', - ], + identifiers: ['dcdu', 'datalink-ctl-and-display-unit', 'cpdlc'], }; export const ewd: Panel = { @@ -92,13 +78,7 @@ export const ewd: Panel = { docsUrl: `${FRONT_DOCS_BASE_URL}/upper-ecam`, flightDeckUrl: LOCATE_DOCS_BASE_URLS.a32nx.flightdeck, imageUrl: `${FRONT_IMAGE_BASE_URL}/ewd.png`, - identifiers: [ - 'ecam-upper', - 'upper-ecam', - 'ewd', - 'engine-and-warning-display', - 'n1-display', - ], + identifiers: ['ecam-upper', 'upper-ecam', 'ewd', 'engine-and-warning-display', 'n1-display'], }; export const sd: Panel = { @@ -144,10 +124,7 @@ export const clockPanel: Panel = { docsUrl: `${FRONT_DOCS_BASE_URL}/clock`, flightDeckUrl: LOCATE_DOCS_BASE_URLS.a32nx.flightdeck, imageUrl: `${FRONT_IMAGE_BASE_URL}/clock.png`, - identifiers: [ - 'clock', - 'date', - ], + identifiers: ['clock', 'date'], }; export const accuPressPanel: Panel = { @@ -156,9 +133,5 @@ export const accuPressPanel: Panel = { docsUrl: `${FRONT_DOCS_BASE_URL}/accu`, flightDeckUrl: LOCATE_DOCS_BASE_URLS.a32nx.flightdeck, imageUrl: `${FRONT_IMAGE_BASE_URL}/accu_press.png`, - identifiers: [ - 'accu-press', - 'accumulator-pressure-indicator', - 'brake-pressure-indicator', - ], + identifiers: ['accu-press', 'accumulator-pressure-indicator', 'brake-pressure-indicator'], }; diff --git a/src/commands/utils/locate/panels/a32nx/glareshield.ts b/src/commands/utils/locate/panels/a32nx/glareshield.ts index c7f999a5..c49ccad7 100644 --- a/src/commands/utils/locate/panels/a32nx/glareshield.ts +++ b/src/commands/utils/locate/panels/a32nx/glareshield.ts @@ -93,9 +93,5 @@ export const lightKnobsPanel: Panel = { docsUrl: `${GLARESHIELD_DOCS_BASE_URL}/light-knobs/`, flightDeckUrl: LOCATE_DOCS_BASE_URLS.a32nx.flightdeck, imageUrl: `${GLARESHIELD_IMAGE_BASE_URL}/light_knobs.png`, - identifiers: [ - 'table-light-knob', - 'integral-glareshield-lighting-knob', - 'fcu-brightness-knob', - ], + identifiers: ['table-light-knob', 'integral-glareshield-lighting-knob', 'fcu-brightness-knob'], }; diff --git a/src/commands/utils/locate/panels/a32nx/overhead.ts b/src/commands/utils/locate/panels/a32nx/overhead.ts index bb3c89b0..05d55d0c 100644 --- a/src/commands/utils/locate/panels/a32nx/overhead.ts +++ b/src/commands/utils/locate/panels/a32nx/overhead.ts @@ -32,11 +32,7 @@ export const callsPanel: Panel = { docsUrl: `${OVHD_DOCS_BASE_URL}/calls/`, flightDeckUrl: LOCATE_DOCS_BASE_URLS.a32nx.flightdeck, imageUrl: `${OVHD_IMAGE_BASE_URL}/calls.png`, - identifiers: [ - 'calls-panel', - 'call', - 'calls', - ], + identifiers: ['calls-panel', 'call', 'calls'], }; export const oxyPanel: Panel = { @@ -45,13 +41,7 @@ export const oxyPanel: Panel = { docsUrl: `${OVHD_DOCS_BASE_URL}/oxygen/`, flightDeckUrl: LOCATE_DOCS_BASE_URLS.a32nx.flightdeck, imageUrl: `${OVHD_IMAGE_BASE_URL}/oxygen.png`, - identifiers: [ - 'oxy', - 'oxygen-panel', - 'oxygen', - 'mask-man-on-switch', - 'crew-supply-switch', - ], + identifiers: ['oxy', 'oxygen-panel', 'oxygen', 'mask-man-on-switch', 'crew-supply-switch'], }; export const cvrPanel: Panel = { @@ -113,14 +103,7 @@ export const evacPanel: Panel = { docsUrl: `${OVHD_DOCS_BASE_URL}/evacuation/`, flightDeckUrl: LOCATE_DOCS_BASE_URLS.a32nx.flightdeck, imageUrl: `${OVHD_IMAGE_BASE_URL}/evac.png`, - identifiers: [ - 'evac-panel', - 'evac', - 'evacuation', - 'command-switch', - 'horn-shut-off-button', - 'capt-purs-switch', - ], + identifiers: ['evac-panel', 'evac', 'evacuation', 'command-switch', 'horn-shut-off-button', 'capt-purs-switch'], }; export const fltCtlPanel: Panel = { @@ -129,14 +112,7 @@ export const fltCtlPanel: Panel = { docsUrl: `${OVHD_DOCS_BASE_URL}/flight-control-computer/`, flightDeckUrl: LOCATE_DOCS_BASE_URLS.a32nx.flightdeck, imageUrl: `${OVHD_IMAGE_BASE_URL}/flt_ctl.png`, - identifiers: [ - 'flight-controls', - 'flight-control-panel', - 'flt-ctl', - 'elac', - 'sec', - 'fac', - ], + identifiers: ['flight-controls', 'flight-control-panel', 'flt-ctl', 'elac', 'sec', 'fac'], }; export const adirsPanel: Panel = { @@ -145,14 +121,7 @@ export const adirsPanel: Panel = { docsUrl: `${OVHD_DOCS_BASE_URL}/adirs/`, flightDeckUrl: LOCATE_DOCS_BASE_URLS.a32nx.flightdeck, imageUrl: `${OVHD_IMAGE_BASE_URL}/adirs.png`, - identifiers: [ - 'adirs-panel', - 'adirs', - 'adiru', - 'irs', - 'adr', - 'ir-selector', - ], + identifiers: ['adirs-panel', 'adirs', 'adiru', 'irs', 'adr', 'ir-selector'], }; export const paVideoPanel: Panel = { @@ -161,13 +130,7 @@ export const paVideoPanel: Panel = { docsUrl: `${OVHD_DOCS_BASE_URL}/pa-cockpit-video/`, flightDeckUrl: LOCATE_DOCS_BASE_URLS.a32nx.flightdeck, imageUrl: `${OVHD_IMAGE_BASE_URL}/pa_video.png`, - identifiers: [ - 'pa-panel', - 'video', - 'cockpit-video-panel', - 'cockpit-door-video', - 'cockpit-door-video-switch', - ], + identifiers: ['pa-panel', 'video', 'cockpit-video-panel', 'cockpit-door-video', 'cockpit-door-video-switch'], }; export const extLtPanel: Panel = { @@ -202,13 +165,7 @@ export const apuPanel: Panel = { docsUrl: `${OVHD_DOCS_BASE_URL}/apu/`, flightDeckUrl: LOCATE_DOCS_BASE_URLS.a32nx.flightdeck, imageUrl: `${OVHD_IMAGE_BASE_URL}/apu.png`, - identifiers: [ - 'apu-panel', - 'apu', - 'auxiliary-power-unit', - 'apu-master-switch', - 'apu-start-button', - ], + identifiers: ['apu-panel', 'apu', 'auxiliary-power-unit', 'apu-master-switch', 'apu-start-button'], }; export const signsPanel: Panel = { @@ -348,15 +305,7 @@ export const fuelPanel: Panel = { docsUrl: `${OVHD_DOCS_BASE_URL}/fuel/`, flightDeckUrl: LOCATE_DOCS_BASE_URLS.a32nx.flightdeck, imageUrl: `${OVHD_IMAGE_BASE_URL}/fuel.png`, - identifiers: [ - 'fuel', - 'fuel-panel', - 'fuel-pumps', - 'x-feed', - 'cross-feed', - 'wing-tanks', - 'center-tanks', - ], + identifiers: ['fuel', 'fuel-panel', 'fuel-pumps', 'x-feed', 'cross-feed', 'wing-tanks', 'center-tanks'], }; export const hydPanel: Panel = { @@ -386,13 +335,7 @@ export const firePanel: Panel = { docsUrl: `${OVHD_DOCS_BASE_URL}/fire/`, flightDeckUrl: LOCATE_DOCS_BASE_URLS.a32nx.flightdeck, imageUrl: `${OVHD_IMAGE_BASE_URL}/fire.png`, - identifiers: [ - 'engine-fire-panel', - 'fire', - 'smoke', - 'fire-agent', - 'disch', - ], + identifiers: ['engine-fire-panel', 'fire', 'smoke', 'fire-agent', 'disch'], }; export const engManStartPanel: Panel = { @@ -401,11 +344,7 @@ export const engManStartPanel: Panel = { docsUrl: `${OVHD_DOCS_BASE_URL}/eng-man/`, flightDeckUrl: LOCATE_DOCS_BASE_URLS.a32nx.flightdeck, imageUrl: `${OVHD_IMAGE_BASE_URL}/eng_n1.png`, - identifiers: [ - 'eng-n1', - 'manual-engine-start', - 'eng-man-start-switch', - ], + identifiers: ['eng-n1', 'manual-engine-start', 'eng-man-start-switch'], }; export const ventilationPanel: Panel = { @@ -414,13 +353,7 @@ export const ventilationPanel: Panel = { docsUrl: `${OVHD_DOCS_BASE_URL}/vent/`, flightDeckUrl: LOCATE_DOCS_BASE_URLS.a32nx.flightdeck, imageUrl: `${OVHD_IMAGE_BASE_URL}/ventilation.png`, - identifiers: [ - 'vent', - 'ventilation-panel', - 'cabin-fans', - 'blower-switch', - 'extract-ventilation-switch', - ], + identifiers: ['vent', 'ventilation-panel', 'cabin-fans', 'blower-switch', 'extract-ventilation-switch'], }; export const cargoSmokePanel: Panel = { @@ -429,10 +362,7 @@ export const cargoSmokePanel: Panel = { docsUrl: `${OVHD_DOCS_BASE_URL}/cargo-smoke/`, flightDeckUrl: LOCATE_DOCS_BASE_URLS.a32nx.flightdeck, imageUrl: `${OVHD_IMAGE_BASE_URL}/cargo_smoke.png`, - identifiers: [ - 'cargo-fire', - 'cargo-smoke-panel', - ], + identifiers: ['cargo-fire', 'cargo-smoke-panel'], }; export const cargoVentPanel: Panel = { @@ -441,11 +371,7 @@ export const cargoVentPanel: Panel = { docsUrl: `${OVHD_DOCS_BASE_URL}/cargo-vent/`, flightDeckUrl: LOCATE_DOCS_BASE_URLS.a32nx.flightdeck, imageUrl: `${OVHD_IMAGE_BASE_URL}/cargo_vent.png`, - identifiers: [ - 'cargo-vent-panel', - 'cargo-ventilation', - 'aft-isol-valve-switch', - ], + identifiers: ['cargo-vent-panel', 'cargo-ventilation', 'aft-isol-valve-switch'], }; export const thirdACP: Panel = { @@ -454,11 +380,7 @@ export const thirdACP: Panel = { docsUrl: `${OVHD_DOCS_BASE_URL}/3rd-acp/`, flightDeckUrl: LOCATE_DOCS_BASE_URLS.a32nx.flightdeck, imageUrl: `${OVHD_IMAGE_BASE_URL}/acp_3.png`, - identifiers: [ - 'acp3', - '3rd-acp', - '3rd-audio-control-panel', - ], + identifiers: ['acp3', '3rd-acp', '3rd-audio-control-panel'], }; export const readingLightsJumpSeats: Panel = { @@ -467,10 +389,7 @@ export const readingLightsJumpSeats: Panel = { docsUrl: `${AFT_OVHD_DOCS_BASE_URL}/reading-light/`, flightDeckUrl: LOCATE_DOCS_BASE_URLS.a32nx.flightdeck, imageUrl: `${AFT_OVHD_IMAGE_BASE_URL}/jump_seat_reading_lt.png`, - identifiers: [ - 'reading-lights-jump-seat', - 'jump-seat-reading-lights', - ], + identifiers: ['reading-lights-jump-seat', 'jump-seat-reading-lights'], }; export const cockpitDoorIndicatorPanel: Panel = { @@ -479,10 +398,7 @@ export const cockpitDoorIndicatorPanel: Panel = { docsUrl: `${AFT_OVHD_DOCS_BASE_URL}/cockpit-door/#description`, flightDeckUrl: LOCATE_DOCS_BASE_URLS.a32nx.flightdeck, imageUrl: `${AFT_OVHD_IMAGE_BASE_URL}/ckpt_door_cont.png`, - identifiers: [ - 'cockpit-door-cont', - 'cockpit-door-indicator-panel', - ], + identifiers: ['cockpit-door-cont', 'cockpit-door-indicator-panel'], }; export const eltPanel: Panel = { @@ -491,11 +407,7 @@ export const eltPanel: Panel = { docsUrl: `${AFT_OVHD_DOCS_BASE_URL}/elt/`, flightDeckUrl: LOCATE_DOCS_BASE_URLS.a32nx.flightdeck, imageUrl: `${AFT_OVHD_IMAGE_BASE_URL}/elt.png`, - identifiers: [ - 'elt', - 'elt-panel', - 'emergency-locator-transmitter', - ], + identifiers: ['elt', 'elt-panel', 'emergency-locator-transmitter'], }; export const pedestalLightPanel: Panel = { @@ -504,11 +416,7 @@ export const pedestalLightPanel: Panel = { docsUrl: `${AFT_OVHD_DOCS_BASE_URL}/pedestal-light/`, flightDeckUrl: LOCATE_DOCS_BASE_URLS.a32nx.flightdeck, imageUrl: `${AFT_OVHD_IMAGE_BASE_URL}/pedestal_light.png`, - identifiers: [ - 'pedestal-light-panel', - 'acp3-switching-selector', - 'audio-control-panel-3-switching-selector', - ], + identifiers: ['pedestal-light-panel', 'acp3-switching-selector', 'audio-control-panel-3-switching-selector'], }; export const emerCbPanel: Panel = { @@ -517,10 +425,7 @@ export const emerCbPanel: Panel = { docsUrl: `${AFT_OVHD_DOCS_BASE_URL}/circuit/`, flightDeckUrl: LOCATE_DOCS_BASE_URLS.a32nx.flightdeck, imageUrl: `${AFT_OVHD_IMAGE_BASE_URL}/emer_cb.png`, - identifiers: [ - 'emer-cb', - 'emergency-circuit-breaker-panel', - ], + identifiers: ['emer-cb', 'emergency-circuit-breaker-panel'], }; export const fmsLoadPanel: Panel = { @@ -529,9 +434,7 @@ export const fmsLoadPanel: Panel = { docsUrl: `${AFT_OVHD_DOCS_BASE_URL}/fms-load/`, flightDeckUrl: LOCATE_DOCS_BASE_URLS.a32nx.flightdeck, imageUrl: `${AFT_OVHD_IMAGE_BASE_URL}/fms_load.png`, - identifiers: [ - 'fms-load-panel', - ], + identifiers: ['fms-load-panel'], }; export const maintenancePanel: Panel = { diff --git a/src/commands/utils/locate/panels/a32nx/pedestal.ts b/src/commands/utils/locate/panels/a32nx/pedestal.ts index d3beb6e3..81f3f862 100644 --- a/src/commands/utils/locate/panels/a32nx/pedestal.ts +++ b/src/commands/utils/locate/panels/a32nx/pedestal.ts @@ -27,12 +27,7 @@ export const mcdu: Panel = { docsUrl: `${PEDESTAL_DOCS_BASE_URL}/mcdu`, flightDeckUrl: LOCATE_DOCS_BASE_URLS.a32nx.flightdeck, imageUrl: `${PEDESTAL_IMAGE_BASE_URL}/mcdu.png`, - identifiers: [ - 'fms', - 'cdu', - 'mcdu', - 'fmgc', - ], + identifiers: ['fms', 'cdu', 'mcdu', 'fmgc'], }; export const rmpAcpPanel: Panel = { @@ -41,13 +36,7 @@ export const rmpAcpPanel: Panel = { docsUrl: `${PEDESTAL_DOCS_BASE_URL}/rmp`, flightDeckUrl: LOCATE_DOCS_BASE_URLS.a32nx.flightdeck, imageUrl: `${PEDESTAL_IMAGE_BASE_URL}/rmp_acp.png`, - identifiers: [ - 'rmp', - 'radio-management-panel', - 'acp', - 'audio-control-panel', - 'atc-panel', - ], + identifiers: ['rmp', 'radio-management-panel', 'acp', 'audio-control-panel', 'atc-panel'], }; export const captPedestalLightingPanel: Panel = { @@ -56,9 +45,7 @@ export const captPedestalLightingPanel: Panel = { docsUrl: `${PEDESTAL_DOCS_BASE_URL}/lighting-capt`, flightDeckUrl: LOCATE_DOCS_BASE_URLS.a32nx.flightdeck, imageUrl: `${PEDESTAL_IMAGE_BASE_URL}/capt_pedestal_lt.png`, - identifiers: [ - 'captain-pedestal-lighting-panel', - ], + identifiers: ['captain-pedestal-lighting-panel'], }; export const wxPanel: Panel = { @@ -67,13 +54,7 @@ export const wxPanel: Panel = { docsUrl: `${PEDESTAL_DOCS_BASE_URL}/radar`, flightDeckUrl: LOCATE_DOCS_BASE_URLS.a32nx.flightdeck, imageUrl: `${PEDESTAL_IMAGE_BASE_URL}/wx_radar.png`, - identifiers: [ - 'wx', - 'weather-radar', - 'wx-radar', - 'pws', - 'predictive-windshear-systems', - ], + identifiers: ['wx', 'weather-radar', 'wx-radar', 'pws', 'predictive-windshear-systems'], }; export const speedBrake: Panel = { @@ -82,12 +63,7 @@ export const speedBrake: Panel = { docsUrl: `${PEDESTAL_DOCS_BASE_URL}/speedbrake`, flightDeckUrl: LOCATE_DOCS_BASE_URLS.a32nx.flightdeck, imageUrl: `${PEDESTAL_IMAGE_BASE_URL}/spd_brk.png`, - identifiers: [ - 'speed-brake', - 'spd-brk', - 'spoilers', - 'gnd-sprls', - ], + identifiers: ['speed-brake', 'spd-brk', 'spoilers', 'gnd-sprls'], }; export const cockpitDoorPanel: Panel = { @@ -96,12 +72,7 @@ export const cockpitDoorPanel: Panel = { docsUrl: `${PEDESTAL_DOCS_BASE_URL}/cockpit-door`, flightDeckUrl: LOCATE_DOCS_BASE_URLS.a32nx.flightdeck, imageUrl: `${PEDESTAL_IMAGE_BASE_URL}/cockpit_door.png`, - identifiers: [ - 'cockpit-door', - 'cockpit-door-panel', - 'cockpit-door-switch', - 'cockpit-door-video-button', - ], + identifiers: ['cockpit-door', 'cockpit-door-panel', 'cockpit-door-switch', 'cockpit-door-video-button'], }; export const switchingPanel: Panel = { @@ -180,9 +151,7 @@ export const rudderTrim: Panel = { docsUrl: `${PEDESTAL_DOCS_BASE_URL}/rudder-trim`, flightDeckUrl: LOCATE_DOCS_BASE_URLS.a32nx.flightdeck, imageUrl: `${PEDESTAL_IMAGE_BASE_URL}/rudder_trim.png`, - identifiers: [ - 'rudder-trim', - ], + identifiers: ['rudder-trim'], }; export const parkBrkPanel: Panel = { @@ -191,10 +160,7 @@ export const parkBrkPanel: Panel = { docsUrl: `${PEDESTAL_DOCS_BASE_URL}/parking-brake`, flightDeckUrl: LOCATE_DOCS_BASE_URLS.a32nx.flightdeck, imageUrl: `${PEDESTAL_IMAGE_BASE_URL}/park_brk.png`, - identifiers: [ - 'parking-brake', - 'park-brk', - ], + identifiers: ['parking-brake', 'park-brk'], }; export const gravityGearExtensionPanel: Panel = { @@ -203,9 +169,7 @@ export const gravityGearExtensionPanel: Panel = { docsUrl: `${PEDESTAL_DOCS_BASE_URL}/gravity-gear-ext`, flightDeckUrl: LOCATE_DOCS_BASE_URLS.a32nx.flightdeck, imageUrl: `${PEDESTAL_IMAGE_BASE_URL}/gravity_gear_extn.png`, - identifiers: [ - 'gravity-gear-extension', - ], + identifiers: ['gravity-gear-extension'], }; export const aidsDfdrPanel: Panel = { @@ -214,14 +178,7 @@ export const aidsDfdrPanel: Panel = { docsUrl: `${PEDESTAL_DOCS_BASE_URL}/lighting-aids-dfdr`, flightDeckUrl: LOCATE_DOCS_BASE_URLS.a32nx.flightdeck, imageUrl: `${PEDESTAL_IMAGE_BASE_URL}/aids_dfdr.png`, - identifiers: [ - 'aids', - 'dfdr', - 'ped-flood-lt-knob', - 'pedestal-flood-light-knob', - 'aids-button', - 'dfdr-button', - ], + identifiers: ['aids', 'dfdr', 'ped-flood-lt-knob', 'pedestal-flood-light-knob', 'aids-button', 'dfdr-button'], }; export const atcTcasPanel: Panel = { @@ -230,13 +187,7 @@ export const atcTcasPanel: Panel = { docsUrl: `${PEDESTAL_DOCS_BASE_URL}/atc-tcas`, flightDeckUrl: LOCATE_DOCS_BASE_URLS.a32nx.flightdeck, imageUrl: `${PEDESTAL_IMAGE_BASE_URL}/atc_tcas.png`, - identifiers: [ - 'xpdr', - 'atc-tcas-panel', - 'transponder', - 'tcas', - 'alt-rptg-switch', - ], + identifiers: ['xpdr', 'atc-tcas-panel', 'transponder', 'tcas', 'alt-rptg-switch'], }; export const flaps: Panel = { @@ -245,9 +196,7 @@ export const flaps: Panel = { docsUrl: `${PEDESTAL_DOCS_BASE_URL}/flaps`, flightDeckUrl: LOCATE_DOCS_BASE_URLS.a32nx.flightdeck, imageUrl: `${PEDESTAL_IMAGE_BASE_URL}/flaps.png`, - identifiers: [ - 'flaps', - ], + identifiers: ['flaps'], }; export const printer: Panel = { @@ -256,7 +205,5 @@ export const printer: Panel = { docsUrl: `${PEDESTAL_DOCS_BASE_URL}/printer`, flightDeckUrl: LOCATE_DOCS_BASE_URLS.a32nx.flightdeck, imageUrl: `${PEDESTAL_IMAGE_BASE_URL}/printer.png`, - identifiers: [ - 'printer', - ], + identifiers: ['printer'], }; diff --git a/src/commands/utils/locate/panels/a32nx/rear-cb-panel.ts b/src/commands/utils/locate/panels/a32nx/rear-cb-panel.ts index 87f6037f..5a801244 100644 --- a/src/commands/utils/locate/panels/a32nx/rear-cb-panel.ts +++ b/src/commands/utils/locate/panels/a32nx/rear-cb-panel.ts @@ -7,8 +7,5 @@ export const rearBackCbPanel: Panel = { docsUrl: `${LOCATE_DOCS_BASE_URLS.a32nx.aftOverhead}/circuit/#rear-right-back-panel`, flightDeckUrl: LOCATE_DOCS_BASE_URLS.a32nx.flightdeck, imageUrl: `${LOCATE_IMAGE_BASE_URLS.a32nx.rearCb}/rear_right_back.jpg`, - identifiers: [ - 'rear-back-circuit-breaker-panel', - 'secondary-circuit-breaker-panel', - ], + identifiers: ['rear-back-circuit-breaker-panel', 'secondary-circuit-breaker-panel'], }; diff --git a/src/commands/utils/metar.ts b/src/commands/utils/metar.ts index dd688e48..4a5ae8b3 100644 --- a/src/commands/utils/metar.ts +++ b/src/commands/utils/metar.ts @@ -6,14 +6,16 @@ const data = slashCommandStructure({ name: 'metar', description: 'Provides the METAR report of the requested airport', type: ApplicationCommandType.ChatInput, - options: [{ - name: 'icao', - description: 'Provide an airport ICAO code.', - type: ApplicationCommandOptionType.String, - max_length: 4, - min_length: 4, - required: true, - }], + options: [ + { + name: 'icao', + description: 'Provide an airport ICAO code.', + type: ApplicationCommandOptionType.String, + max_length: 4, + min_length: 4, + required: true, + }, + ], }); export default slashCommand(data, async ({ interaction }) => { @@ -36,8 +38,7 @@ export default slashCommand(data, async ({ interaction }) => { const metarReport: any = await fetch(`https://avwx.rest/api/metar/${icao}`, { method: 'GET', headers: { Authorization: metarToken }, - }) - .then((res) => res.json()); + }).then((res) => res.json()); if (metarReport.error) { const invalidEmbed = makeEmbed({ @@ -70,7 +71,9 @@ export default slashCommand(data, async ({ interaction }) => { inline: false, }, ], - footer: { text: 'This METAR report may not accurately reflect the weather in the simulator. However, it will always be similar to the current conditions present in the sim.' }, + footer: { + text: 'This METAR report may not accurately reflect the weather in the simulator. However, it will always be similar to the current conditions present in the sim.', + }, }); return interaction.editReply({ embeds: [metarEmbed] }); diff --git a/src/commands/utils/ping.ts b/src/commands/utils/ping.ts index 5d29b95b..93c8f6a5 100644 --- a/src/commands/utils/ping.ts +++ b/src/commands/utils/ping.ts @@ -5,13 +5,15 @@ const data = slashCommandStructure({ name: 'ping', description: 'Ping the bot for a response.', type: ApplicationCommandType.ChatInput, - options: [{ - name: 'message', - description: 'Provide some text to send back.', - type: ApplicationCommandOptionType.String, - max_length: 100, - required: false, - }], + options: [ + { + name: 'message', + description: 'Provide some text to send back.', + type: ApplicationCommandOptionType.String, + max_length: 100, + required: false, + }, + ], }); export default slashCommand(data, async ({ interaction }) => { diff --git a/src/commands/utils/reportedIssues.ts b/src/commands/utils/reportedIssues.ts index c00677e7..0390431f 100644 --- a/src/commands/utils/reportedIssues.ts +++ b/src/commands/utils/reportedIssues.ts @@ -6,17 +6,20 @@ const data = slashCommandStructure({ name: 'reported-issues', description: 'Provides a link to the reported issues page within docs.', type: ApplicationCommandType.ChatInput, - options: [{ - name: 'query', - description: 'Provide a query to search for.', - type: ApplicationCommandOptionType.String, - max_length: 100, - required: true, - }], + options: [ + { + name: 'query', + description: 'Provide a query to search for.', + type: ApplicationCommandOptionType.String, + max_length: 100, + required: true, + }, + ], }); const FBW_DOCS_REPORTED_ISSUES_URL = 'https://docs.flybywiresim.com/fbw-a32nx/support/reported-issues/'; -const FBW_DOCS_AUTOPILOT_ISSUES_URL = 'https://docs.flybywiresim.com/fbw-a32nx/feature-guides/autopilot-fbw/#typical-issues-and-how-to-solve-them'; +const FBW_DOCS_AUTOPILOT_ISSUES_URL = + 'https://docs.flybywiresim.com/fbw-a32nx/feature-guides/autopilot-fbw/#typical-issues-and-how-to-solve-them'; const FBW_DOCS_SIMBRIDGE_ISSUES_URL = 'https://docs.flybywiresim.com/simbridge/troubleshooting/'; const genericReportedIssuesEmbed = makeEmbed({ @@ -24,11 +27,13 @@ const genericReportedIssuesEmbed = makeEmbed({ description: `I couldn't find a match foy your query. Please see [this link](${FBW_DOCS_REPORTED_ISSUES_URL}) for a current list of reported issues.`, }); -const issueInSubsectionEmbed = (fields: EmbedField[]) => makeEmbed({ - title: 'FlyByWire A32NX | Reported Issues', - description: 'Your issue is in our reported issues list. Please try the possible solutions in the following link(s) and report back if they didn\'t help. Include all the steps you tried.', - fields, -}); +const issueInSubsectionEmbed = (fields: EmbedField[]) => + makeEmbed({ + title: 'FlyByWire A32NX | Reported Issues', + description: + "Your issue is in our reported issues list. Please try the possible solutions in the following link(s) and report back if they didn't help. Include all the steps you tried.", + fields, + }); const subsectionLinkEmbedField = (id: string, title: string): EmbedField[] => [ { @@ -50,12 +55,15 @@ const simbridgeEmbed = makeEmbed({ const generalTroubleshootingEmbed = makeEmbed({ title: 'FlyByWire A32NX | Reported Issues', - description: 'Please try the general troubleshooting steps from our reported issues page and report back if they didn\'t help. Include all the steps you tried.', - fields: [{ - inline: false, - name: 'General Troubleshooting Steps', - value: `[Link to reported issues section](${FBW_DOCS_REPORTED_ISSUES_URL}#general-troubleshooting-steps)`, - }], + description: + "Please try the general troubleshooting steps from our reported issues page and report back if they didn't help. Include all the steps you tried.", + fields: [ + { + inline: false, + name: 'General Troubleshooting Steps', + value: `[Link to reported issues section](${FBW_DOCS_REPORTED_ISSUES_URL}#general-troubleshooting-steps)`, + }, + ], }); const tooManyResultsEmbed = makeEmbed({ @@ -102,7 +110,9 @@ export default slashCommand(data, async ({ interaction }) => { return interaction.reply({ embeds: [genericReportedIssuesEmbed] }); } - const fields = reportedIssues.map((sectionElement: any) => subsectionLinkEmbedField(sectionElement.id, sectionElement.title)).flat(); + const fields = reportedIssues + .map((sectionElement: any) => subsectionLinkEmbedField(sectionElement.id, sectionElement.title)) + .flat(); return interaction.reply({ embeds: [issueInSubsectionEmbed(fields)] }); } catch (error: any) { Logger.error(error); diff --git a/src/commands/utils/roleInfo.ts b/src/commands/utils/roleInfo.ts index 8ba7233f..86c87e2a 100644 --- a/src/commands/utils/roleInfo.ts +++ b/src/commands/utils/roleInfo.ts @@ -3,14 +3,16 @@ import { slashCommand, slashCommandStructure, makeEmbed } from '../../lib'; const data = slashCommandStructure({ name: 'role-info', - description: 'Lists the given role\'s amount of members.', + description: "Lists the given role's amount of members.", type: ApplicationCommandType.ChatInput, - options: [{ - name: 'role', - description: 'Provide the role to get info about.', - type: ApplicationCommandOptionType.Role, - required: true, - }], + options: [ + { + name: 'role', + description: 'Provide the role to get info about.', + type: ApplicationCommandOptionType.Role, + required: true, + }, + ], }); export default slashCommand(data, async ({ interaction }) => { diff --git a/src/commands/utils/searchFaq.ts b/src/commands/utils/searchFaq.ts index 465a07c2..29ebe50b 100644 --- a/src/commands/utils/searchFaq.ts +++ b/src/commands/utils/searchFaq.ts @@ -16,20 +16,21 @@ const data = slashCommandStructure({ ], }); -const noFaqsFoundEmbed = (searchTerm: string) => makeEmbed({ - title: `No FAQs found - ${searchTerm}`, - description: 'No FAQs found matching your search term. Please try again or see the links below.', - fields: [ - { - name: '**FAQ Channel**', - value: `<#${constantsConfig.channels.FAQ}>`, - }, - { - name: '**Docs FAQ**', - value: 'https://docs.flybywiresim.com/fbw-a32nx/faq/', - }, - ], -}); +const noFaqsFoundEmbed = (searchTerm: string) => + makeEmbed({ + title: `No FAQs found - ${searchTerm}`, + description: 'No FAQs found matching your search term. Please try again or see the links below.', + fields: [ + { + name: '**FAQ Channel**', + value: `<#${constantsConfig.channels.FAQ}>`, + }, + { + name: '**Docs FAQ**', + value: 'https://docs.flybywiresim.com/fbw-a32nx/faq/', + }, + ], + }); export default slashCommand(data, async ({ interaction }) => { const searchTerm = interaction.options.getString('search_term') ?? ''; diff --git a/src/commands/utils/simbriefData.ts b/src/commands/utils/simbriefData.ts index 26f81e69..50e456ce 100644 --- a/src/commands/utils/simbriefData.ts +++ b/src/commands/utils/simbriefData.ts @@ -11,13 +11,15 @@ const data = slashCommandStructure({ name: 'retrieve', description: 'Shows data for your last filed flight plan.', type: ApplicationCommandOptionType.Subcommand, - options: [{ - name: 'pilot_id', - description: 'Please provide your pilot ID.', - type: ApplicationCommandOptionType.String, - max_length: 100, - required: true, - }], + options: [ + { + name: 'pilot_id', + description: 'Please provide your pilot ID.', + type: ApplicationCommandOptionType.String, + max_length: 100, + required: true, + }, + ], }, { name: 'support-request', @@ -40,31 +42,33 @@ const simbriefdatarequestEmbed = makeEmbed({ ]), }); -const errorEmbed = (errorMessage: any) => makeEmbed({ - title: 'SimBrief Error', - description: makeLines(['SimBrief data could not be read.', errorMessage]), - color: Colors.Red, -}); - -const simbriefIdMismatchEmbed = (enteredId: any, flightplanId: any) => makeEmbed({ - title: 'SimBrief Data', - description: makeLines([ - `Entered pilotId ${enteredId} and returned pilotId ${flightplanId} don't match. The pilotId might be used as username by someone else.`, - ]), -}); +const errorEmbed = (errorMessage: any) => + makeEmbed({ + title: 'SimBrief Error', + description: makeLines(['SimBrief data could not be read.', errorMessage]), + color: Colors.Red, + }); -const simbriefEmbed = (flightplan: any) => makeEmbed({ - title: 'SimBrief Data', - description: makeLines([ - `**Generated at**: ${moment(flightplan.params.time_generated * 1000).format('DD.MM.YYYY, HH:mm:ss')}`, - `**AirFrame**: ${flightplan.aircraft.name} ${flightplan.aircraft.internal_id} ${(flightplan.aircraft.internal_id === FBW_AIRFRAME_ID) ? '(provided by FBW)' : ''}`, - `**AIRAC Cycle**: ${flightplan.params.airac}`, - `**Origin**: ${flightplan.origin.icao_code}`, - `**Destination**: ${flightplan.destination.icao_code}`, - `**Route**: ${flightplan.general.route}`, - ]), +const simbriefIdMismatchEmbed = (enteredId: any, flightplanId: any) => + makeEmbed({ + title: 'SimBrief Data', + description: makeLines([ + `Entered pilotId ${enteredId} and returned pilotId ${flightplanId} don't match. The pilotId might be used as username by someone else.`, + ]), + }); -}); +const simbriefEmbed = (flightplan: any) => + makeEmbed({ + title: 'SimBrief Data', + description: makeLines([ + `**Generated at**: ${moment(flightplan.params.time_generated * 1000).format('DD.MM.YYYY, HH:mm:ss')}`, + `**AirFrame**: ${flightplan.aircraft.name} ${flightplan.aircraft.internal_id} ${flightplan.aircraft.internal_id === FBW_AIRFRAME_ID ? '(provided by FBW)' : ''}`, + `**AIRAC Cycle**: ${flightplan.params.airac}`, + `**Origin**: ${flightplan.origin.icao_code}`, + `**Destination**: ${flightplan.destination.icao_code}`, + `**Route**: ${flightplan.general.route}`, + ]), + }); export default slashCommand(data, async ({ interaction }) => { if (interaction.options.getSubcommand() === 'support-request') { @@ -75,7 +79,9 @@ export default slashCommand(data, async ({ interaction }) => { const simbriefId = interaction.options.getString('pilot_id'); if (!simbriefId) return interaction.reply({ content: 'Invalid pilot ID!', ephemeral: true }); - const flightplan = await fetch(`https://www.simbrief.com/api/xml.fetcher.php?json=1&userid=${simbriefId}&username=${simbriefId}`).then((res) => res.json()); + const flightplan = await fetch( + `https://www.simbrief.com/api/xml.fetcher.php?json=1&userid=${simbriefId}&username=${simbriefId}`, + ).then((res) => res.json()); if (flightplan.fetch.status !== 'Success') { interaction.reply({ embeds: [errorEmbed(flightplan.fetch.status)], ephemeral: true }); diff --git a/src/commands/utils/station.ts b/src/commands/utils/station.ts index 8cde14a2..70fa684d 100644 --- a/src/commands/utils/station.ts +++ b/src/commands/utils/station.ts @@ -6,14 +6,16 @@ const data = slashCommandStructure({ name: 'station', description: 'Provides station information.', type: ApplicationCommandType.ChatInput, - options: [{ - name: 'icao', - description: 'Provide an airport ICAO code.', - type: ApplicationCommandOptionType.String, - max_length: 4, - min_length: 4, - required: true, - }], + options: [ + { + name: 'icao', + description: 'Provide an airport ICAO code.', + type: ApplicationCommandOptionType.String, + max_length: 4, + min_length: 4, + required: true, + }, + ], }); const noQueryEmbed = makeEmbed({ @@ -55,9 +57,12 @@ export default slashCommand(data, async ({ interaction }) => { return interaction.editReply({ embeds: [invalidEmbed] }); } - const runwayIdents = stationReport.runways.map((runways: any) => `**${runways.ident1}/${runways.ident2}:** ` - + `${runways.length_ft} ft x ${runways.width_ft} ft / ` - + `${Math.round(runways.length_ft * 0.3048)} m x ${Math.round(runways.width_ft * 0.3048)} m`); + const runwayIdents = stationReport.runways.map( + (runways: any) => + `**${runways.ident1}/${runways.ident2}:** ` + + `${runways.length_ft} ft x ${runways.width_ft} ft / ` + + `${Math.round(runways.length_ft * 0.3048)} m x ${Math.round(runways.width_ft * 0.3048)} m`, + ); const stationEmbed = makeEmbed({ title: `Station Info | ${stationReport.icao}`, diff --git a/src/commands/utils/taf.ts b/src/commands/utils/taf.ts index dba64551..78792ad3 100644 --- a/src/commands/utils/taf.ts +++ b/src/commands/utils/taf.ts @@ -6,14 +6,16 @@ const data = slashCommandStructure({ name: 'taf', description: 'Provides the TAF report of the requested airport.', type: ApplicationCommandType.ChatInput, - options: [{ - name: 'icao', - description: 'Provide an airport ICAO code.', - type: ApplicationCommandOptionType.String, - max_length: 4, - min_length: 4, - required: true, - }], + options: [ + { + name: 'icao', + description: 'Provide an airport ICAO code.', + type: ApplicationCommandOptionType.String, + max_length: 4, + min_length: 4, + required: true, + }, + ], }); const noQueryEmbed = makeEmbed({ @@ -86,7 +88,9 @@ export default slashCommand(data, async ({ interaction }) => { inline: false, }, ], - footer: { text: 'This TAF report is only a forecast, and may not accurately reflect weather in the simulator.' }, + footer: { + text: 'This TAF report is only a forecast, and may not accurately reflect weather in the simulator.', + }, }); return interaction.editReply({ embeds: [tafEmbed] }); diff --git a/src/commands/utils/vatsim/functions/vatsimControllers.ts b/src/commands/utils/vatsim/functions/vatsimControllers.ts index 08e5cd2b..7604c455 100644 --- a/src/commands/utils/vatsim/functions/vatsimControllers.ts +++ b/src/commands/utils/vatsim/functions/vatsimControllers.ts @@ -1,15 +1,21 @@ import { ChatInputCommandInteraction, EmbedField } from 'discord.js'; import { makeEmbed } from '../../../../lib'; -/* eslint-disable camelcase */ +const listEmbed = (type: string, fields: EmbedField[], totalCount: number, shownCount: number, callsign: string) => + makeEmbed({ + title: `VATSIM Data - ${callsign} - ${totalCount} ${type} online`, + description: `A list of ${shownCount} online ${type} matching ${callsign}.`, + fields, + }); -const listEmbed = (type: string, fields: EmbedField[], totalCount: number, shownCount: number, callsign: string) => makeEmbed({ - title: `VATSIM Data - ${callsign} - ${totalCount} ${type} online`, - description: `A list of ${shownCount} online ${type} matching ${callsign}.`, - fields, -}); - -const controllersListEmbedFields = (callsign: string, frequency: string, logon: string, rating: string, atis: string, atisCode: string): EmbedField[] => { +const controllersListEmbedFields = ( + callsign: string, + frequency: string, + logon: string, + rating: string, + atis: string, + atisCode: string, +): EmbedField[] => { const fields = [ { name: 'Callsign', @@ -49,38 +55,58 @@ const controllersListEmbedFields = (callsign: string, frequency: string, logon: return fields; }; -const handleLocaleDateTimeString = (date: Date) => date.toLocaleDateString('en-US', { - hour: 'numeric', - minute: 'numeric', - weekday: 'short', - month: 'short', - day: 'numeric', -}); +const handleLocaleDateTimeString = (date: Date) => + date.toLocaleDateString('en-US', { + hour: 'numeric', + minute: 'numeric', + weekday: 'short', + month: 'short', + day: 'numeric', + }); -export async function handleVatsimControllers(interaction: ChatInputCommandInteraction<'cached'>, vatsimData: any, callsignSearch: any) { - const vatsimAllControllers = vatsimData.controllers ? vatsimData.controllers.filter((controller: { facility: number; }) => controller.facility > 0) : null; +export async function handleVatsimControllers( + interaction: ChatInputCommandInteraction<'cached'>, + vatsimData: any, + callsignSearch: any, +) { + const vatsimAllControllers = vatsimData.controllers + ? vatsimData.controllers.filter((controller: { facility: number }) => controller.facility > 0) + : null; const vatsimControllerRatings = vatsimData.ratings ? vatsimData.ratings : null; - const vatsimControllers = vatsimAllControllers ? vatsimAllControllers.filter((controller: { callsign: string | string[]; }) => controller.callsign.includes(callsignSearch)) : null; - const vatsimAtis = vatsimData.atis ? vatsimData.atis.filter((atis: { callsign: string | string[]; }) => atis.callsign.includes(callsignSearch)) : null; + const vatsimControllers = vatsimAllControllers + ? vatsimAllControllers.filter((controller: { callsign: string | string[] }) => + controller.callsign.includes(callsignSearch), + ) + : null; + const vatsimAtis = vatsimData.atis + ? vatsimData.atis.filter((atis: { callsign: string | string[] }) => atis.callsign.includes(callsignSearch)) + : null; const { keys }: ObjectConstructor = Object; - const fields: EmbedField[] = [...vatsimControllers.sort((a: { facility: number; }, b: { facility: number; }) => b.facility - a.facility), ...vatsimAtis] + const fields: EmbedField[] = [ + ...vatsimControllers.sort((a: { facility: number }, b: { facility: number }) => b.facility - a.facility), + ...vatsimAtis, + ] .map((vatsimController) => { const { callsign, frequency, logon_time, atis_code, text_atis, rating } = vatsimController; const logonTime = new Date(logon_time); const logonTimeString = handleLocaleDateTimeString(logonTime); - const ratingDetail = vatsimControllerRatings.filter((ratingInfo: { id: any; }) => ratingInfo.id === rating); + const ratingDetail = vatsimControllerRatings.filter((ratingInfo: { id: any }) => ratingInfo.id === rating); const { short, long } = ratingDetail[0]; const ratingText = `${short} - ${long}`; const atisText = text_atis ? text_atis.join('\n') : null; return controllersListEmbedFields(callsign, frequency, logonTimeString, ratingText, atisText, atis_code); - }).slice(0, 5).flat(); + }) + .slice(0, 5) + .flat(); const totalCount = keys(vatsimControllers).length + keys(vatsimAtis).length; const shownCount = totalCount < 5 ? totalCount : 5; - return interaction.reply({ embeds: [listEmbed('Controllers & ATIS', fields, totalCount, shownCount, callsignSearch)] }); + return interaction.reply({ + embeds: [listEmbed('Controllers & ATIS', fields, totalCount, shownCount, callsignSearch)], + }); } diff --git a/src/commands/utils/vatsim/functions/vatsimEvents.ts b/src/commands/utils/vatsim/functions/vatsimEvents.ts index 468c8f83..93453c12 100644 --- a/src/commands/utils/vatsim/functions/vatsimEvents.ts +++ b/src/commands/utils/vatsim/functions/vatsimEvents.ts @@ -3,16 +3,18 @@ import { Logger, makeEmbed } from '../../../../lib'; const BASE_VATSIM_URL = 'https://my.vatsim.net'; -const handleLocaleTimeString = (date: Date) => date.toLocaleTimeString('en-US', { - hour: 'numeric', - minute: 'numeric', -}); +const handleLocaleTimeString = (date: Date) => + date.toLocaleTimeString('en-US', { + hour: 'numeric', + minute: 'numeric', + }); -const handleLocaleDateString = (date: Date) => date.toLocaleDateString('en-US', { - weekday: 'short', - month: 'short', - day: 'numeric', -}); +const handleLocaleDateString = (date: Date) => + date.toLocaleDateString('en-US', { + weekday: 'short', + month: 'short', + day: 'numeric', + }); export async function handleVatsimEvents(interaction: ChatInputCommandInteraction<'cached'>) { await interaction.deferReply(); @@ -21,52 +23,54 @@ export async function handleVatsimEvents(interaction: ChatInputCommandInteractio const eventsList = await fetch(`${BASE_VATSIM_URL}/api/v1/events/all`) .then((res) => res.json()) .then((res) => res.data) - .then((res) => res.filter((event: { type: string; }) => event.type === 'Event')) + .then((res) => res.filter((event: { type: string }) => event.type === 'Event')) .then((res) => res.slice(0, 5)); - const fields: EmbedField[] = eventsList.map((event: any) => { - // eslint-disable-next-line camelcase - const { name, organisers, end_time, start_time, link } = event; - const { division } = organisers[0]; - const startDate = new Date(start_time); - const endDate = new Date(end_time); - const startTime = handleLocaleTimeString(startDate); - const endTime = handleLocaleTimeString(endDate); - const startDateString = handleLocaleDateString(startDate); - const endDateString = handleLocaleDateString(endDate); + const fields: EmbedField[] = eventsList + .map((event: any) => { + const { name, organisers, end_time, start_time, link } = event; + const { division } = organisers[0]; + const startDate = new Date(start_time); + const endDate = new Date(end_time); + const startTime = handleLocaleTimeString(startDate); + const endTime = handleLocaleTimeString(endDate); + const startDateString = handleLocaleDateString(startDate); + const endDateString = handleLocaleDateString(endDate); - return [ - { - name: 'Name', - value: name, - inline: false, - }, - { - name: 'Start Time/Date', - value: `${startTime}/${startDateString}`, - inline: true, - }, - { - name: 'End Time/Date', - value: `${endTime}/${endDateString}`, - inline: true, - }, - { - name: 'Division', - value: `${division}`, - inline: true, - }, - { - name: 'Link', - value: `${link}`, - inline: false, - }, - ]; - }).flat(); + return [ + { + name: 'Name', + value: name, + inline: false, + }, + { + name: 'Start Time/Date', + value: `${startTime}/${startDateString}`, + inline: true, + }, + { + name: 'End Time/Date', + value: `${endTime}/${endDateString}`, + inline: true, + }, + { + name: 'Division', + value: `${division}`, + inline: true, + }, + { + name: 'Link', + value: `${link}`, + inline: false, + }, + ]; + }) + .flat(); const eventsEmbed = makeEmbed({ title: 'VATSIM Events', - description: 'A list of upcoming events on the VATSIM network. Find the full list [here.](https://my.vatsim.net/events)', + description: + 'A list of upcoming events on the VATSIM network. Find the full list [here.](https://my.vatsim.net/events)', fields, }); diff --git a/src/commands/utils/vatsim/functions/vatsimObservers.ts b/src/commands/utils/vatsim/functions/vatsimObservers.ts index 48fd6ed1..c3032ad6 100644 --- a/src/commands/utils/vatsim/functions/vatsimObservers.ts +++ b/src/commands/utils/vatsim/functions/vatsimObservers.ts @@ -1,13 +1,12 @@ import { ChatInputCommandInteraction, EmbedField } from 'discord.js'; import { makeEmbed } from '../../../../lib'; -/* eslint-disable camelcase */ - -const listEmbed = (type: string, fields: EmbedField[], totalCount: number, shownCount: number, callsign: string) => makeEmbed({ - title: `VATSIM Data - ${callsign} - ${totalCount} ${type} online`, - description: `A list of ${shownCount} online ${type} matching ${callsign}.`, - fields, -}); +const listEmbed = (type: string, fields: EmbedField[], totalCount: number, shownCount: number, callsign: string) => + makeEmbed({ + title: `VATSIM Data - ${callsign} - ${totalCount} ${type} online`, + description: `A list of ${shownCount} online ${type} matching ${callsign}.`, + fields, + }); const observersListEmbedFields = (callsign: string, logon: string, rating: string, atis: string): EmbedField[] => { const fields = [ @@ -39,33 +38,49 @@ const observersListEmbedFields = (callsign: string, logon: string, rating: strin return fields; }; -const handleLocaleDateTimeString = (date: Date) => date.toLocaleDateString('en-US', { - hour: 'numeric', - minute: 'numeric', - weekday: 'short', - month: 'short', - day: 'numeric', -}); +const handleLocaleDateTimeString = (date: Date) => + date.toLocaleDateString('en-US', { + hour: 'numeric', + minute: 'numeric', + weekday: 'short', + month: 'short', + day: 'numeric', + }); -export async function handleVatsimObservers(interaction: ChatInputCommandInteraction<'cached'>, vatsimData: any, callsignSearch: any) { - const vatsimAllObservers = vatsimData.controllers ? vatsimData.controllers.filter((controller: { facility: number; }) => controller.facility <= 0) : null; +export async function handleVatsimObservers( + interaction: ChatInputCommandInteraction<'cached'>, + vatsimData: any, + callsignSearch: any, +) { + const vatsimAllObservers = vatsimData.controllers + ? vatsimData.controllers.filter((controller: { facility: number }) => controller.facility <= 0) + : null; const vatsimControllerRatings = vatsimData.ratings ? vatsimData.ratings : null; - const vatsimObservers = vatsimAllObservers ? vatsimAllObservers.filter((observer: { callsign: string | any[]; }) => observer.callsign.includes(callsignSearch)) : null; + const vatsimObservers = vatsimAllObservers + ? vatsimAllObservers.filter((observer: { callsign: string | any[] }) => + observer.callsign.includes(callsignSearch), + ) + : null; const { keys }: ObjectConstructor = Object; - const fields: EmbedField[] = [...vatsimObservers.sort((a: { rating: number; }, b: { rating: number; }) => b.rating - a.rating)].map((vatsimObserver) => { - const { callsign, logon_time, text_atis, rating } = vatsimObserver; - const logonTime = new Date(logon_time); - const logonTimeString = handleLocaleDateTimeString(logonTime); - const ratingDetail = vatsimControllerRatings.filter((ratingInfo: { id: any; }) => ratingInfo.id === rating); - const { short, long } = ratingDetail[0]; - const ratingText = `${short} - ${long}`; - const atisText = text_atis ? text_atis.join('\n') : null; + const fields: EmbedField[] = [ + ...vatsimObservers.sort((a: { rating: number }, b: { rating: number }) => b.rating - a.rating), + ] + .map((vatsimObserver) => { + const { callsign, logon_time, text_atis, rating } = vatsimObserver; + const logonTime = new Date(logon_time); + const logonTimeString = handleLocaleDateTimeString(logonTime); + const ratingDetail = vatsimControllerRatings.filter((ratingInfo: { id: any }) => ratingInfo.id === rating); + const { short, long } = ratingDetail[0]; + const ratingText = `${short} - ${long}`; + const atisText = text_atis ? text_atis.join('\n') : null; - return observersListEmbedFields(callsign, logonTimeString, ratingText, atisText); - }).slice(0, 5).flat(); + return observersListEmbedFields(callsign, logonTimeString, ratingText, atisText); + }) + .slice(0, 5) + .flat(); const totalCount = keys(vatsimObservers).length; const shownCount = totalCount < 5 ? totalCount : 5; diff --git a/src/commands/utils/vatsim/functions/vatsimPilots.ts b/src/commands/utils/vatsim/functions/vatsimPilots.ts index e73c6300..3198413d 100644 --- a/src/commands/utils/vatsim/functions/vatsimPilots.ts +++ b/src/commands/utils/vatsim/functions/vatsimPilots.ts @@ -1,13 +1,12 @@ import { ChatInputCommandInteraction, EmbedField } from 'discord.js'; import { makeEmbed } from '../../../../lib'; -/* eslint-disable camelcase */ - -const listEmbed = (type: string, fields: EmbedField[], totalCount: number, shownCount: number, callsign: string) => makeEmbed({ - title: `VATSIM Data - ${callsign} - ${totalCount} ${type} online`, - description: `A list of ${shownCount} online ${type} matching ${callsign}.`, - fields, -}); +const listEmbed = (type: string, fields: EmbedField[], totalCount: number, shownCount: number, callsign: string) => + makeEmbed({ + title: `VATSIM Data - ${callsign} - ${totalCount} ${type} online`, + description: `A list of ${shownCount} online ${type} matching ${callsign}.`, + fields, + }); const pilotsListEmbedFields = (callsign: string, rating: string, flightPlan: any) => { const fields = [ { @@ -41,20 +40,35 @@ const pilotsListEmbedFields = (callsign: string, rating: string, flightPlan: any return fields; }; -export async function handleVatsimPilots(interaction: ChatInputCommandInteraction<'cached'>, vatsimData: any, callsignSearch: any) { +export async function handleVatsimPilots( + interaction: ChatInputCommandInteraction<'cached'>, + vatsimData: any, + callsignSearch: any, +) { const vatsimPilotRatings = vatsimData.pilot_ratings ? vatsimData.pilot_ratings : null; - const vatsimPilots = vatsimData.pilots ? vatsimData.pilots.filter((pilot: { callsign: (string | null)[]; }) => pilot.callsign.includes(callsignSearch)) : null; + const vatsimPilots = vatsimData.pilots + ? vatsimData.pilots.filter((pilot: { callsign: (string | null)[] }) => pilot.callsign.includes(callsignSearch)) + : null; const { keys }: ObjectConstructor = Object; - const fields: EmbedField[] = [...vatsimPilots.sort((a: { pilot_rating: number; }, b: { pilot_rating: number; }) => b.pilot_rating - a.pilot_rating)].map((vatsimPilot) => { - const { callsign, pilot_rating, flight_plan } = vatsimPilot; - const ratingDetail = vatsimPilotRatings.filter((ratingInfo: { id: number; }) => ratingInfo.id === pilot_rating); - const { short_name, long_name } = ratingDetail[0]; - const ratingText = `${short_name} - ${long_name}`; + const fields: EmbedField[] = [ + ...vatsimPilots.sort( + (a: { pilot_rating: number }, b: { pilot_rating: number }) => b.pilot_rating - a.pilot_rating, + ), + ] + .map((vatsimPilot) => { + const { callsign, pilot_rating, flight_plan } = vatsimPilot; + const ratingDetail = vatsimPilotRatings.filter( + (ratingInfo: { id: number }) => ratingInfo.id === pilot_rating, + ); + const { short_name, long_name } = ratingDetail[0]; + const ratingText = `${short_name} - ${long_name}`; - return pilotsListEmbedFields(callsign, ratingText, flight_plan); - }).slice(0, 5).flat(); + return pilotsListEmbedFields(callsign, ratingText, flight_plan); + }) + .slice(0, 5) + .flat(); const totalCount = keys(vatsimPilots).length; const shownCount = totalCount < 5 ? totalCount : 5; diff --git a/src/commands/utils/vatsim/functions/vatsimStats.ts b/src/commands/utils/vatsim/functions/vatsimStats.ts index a37c7c82..19b065fe 100644 --- a/src/commands/utils/vatsim/functions/vatsimStats.ts +++ b/src/commands/utils/vatsim/functions/vatsimStats.ts @@ -1,36 +1,47 @@ import { ChatInputCommandInteraction } from 'discord.js'; import { makeEmbed } from '../../../../lib'; -const statsEmbed = (pilots: string, controllers: string, atis: string, observers: string, callsign: any) => makeEmbed({ - title: callsign ? `VATSIM Data | Statistics for callsign ${callsign}` : 'VATSIM Data | Statistics', - description: callsign ? `An overview of the current active Pilots, Controllers, ATIS and Observers matching ${callsign}.` : 'An overview of the current active Pilots, Controllers, ATIS and Observers.', - fields: [ - { - name: 'Pilots', - value: pilots, - inline: true, - }, - { - name: 'Controllers', - value: controllers, - inline: true, - }, - { - name: 'ATIS', - value: atis, - inline: true, - }, - { - name: 'Observers', - value: observers, - inline: true, - }, - ], -}); +const statsEmbed = (pilots: string, controllers: string, atis: string, observers: string, callsign: any) => + makeEmbed({ + title: callsign ? `VATSIM Data | Statistics for callsign ${callsign}` : 'VATSIM Data | Statistics', + description: callsign + ? `An overview of the current active Pilots, Controllers, ATIS and Observers matching ${callsign}.` + : 'An overview of the current active Pilots, Controllers, ATIS and Observers.', + fields: [ + { + name: 'Pilots', + value: pilots, + inline: true, + }, + { + name: 'Controllers', + value: controllers, + inline: true, + }, + { + name: 'ATIS', + value: atis, + inline: true, + }, + { + name: 'Observers', + value: observers, + inline: true, + }, + ], + }); -export async function handleVatsimStats(interaction: ChatInputCommandInteraction<'cached'>, vatsimData: any, callsignSearch: any) { - const vatsimAllControllers = vatsimData.controllers ? vatsimData.controllers.filter((controller: { facility: number; }) => controller.facility > 0) : null; - const vatsimAllObservers = vatsimData.controllers ? vatsimData.controllers.filter((controller: { facility: number; }) => controller.facility <= 0) : null; +export async function handleVatsimStats( + interaction: ChatInputCommandInteraction<'cached'>, + vatsimData: any, + callsignSearch: any, +) { + const vatsimAllControllers = vatsimData.controllers + ? vatsimData.controllers.filter((controller: { facility: number }) => controller.facility > 0) + : null; + const vatsimAllObservers = vatsimData.controllers + ? vatsimData.controllers.filter((controller: { facility: number }) => controller.facility <= 0) + : null; if (!callsignSearch) { const vatsimPilotCount = vatsimData.pilots ? vatsimData.pilots.length : 0; @@ -38,17 +49,35 @@ export async function handleVatsimStats(interaction: ChatInputCommandInteraction const vatsimAtisCount = vatsimData.atis ? vatsimData.atis.length : 0; const vatsimObserverCount = vatsimAllObservers ? vatsimAllObservers.length : 0; - return interaction.reply({ embeds: [statsEmbed(vatsimPilotCount, vatsimControllerCount, vatsimAtisCount, vatsimObserverCount, null)] }); + return interaction.reply({ + embeds: [statsEmbed(vatsimPilotCount, vatsimControllerCount, vatsimAtisCount, vatsimObserverCount, null)], + }); } - const vatsimPilots = vatsimData.pilots ? vatsimData.pilots.filter((pilot: { callsign: string | string[]; }) => pilot.callsign.includes(callsignSearch)) : null; - const vatsimControllers = vatsimAllControllers ? vatsimAllControllers.filter((controller: { callsign: string | string[]; }) => controller.callsign.includes(callsignSearch)) : null; - const vatsimAtis = vatsimData.atis ? vatsimData.atis.filter((atis: { callsign: string | string[]; }) => atis.callsign.includes(callsignSearch)) : null; - const vatsimObservers = vatsimAllObservers ? vatsimAllObservers.filter((observer: { callsign: string | string[]; }) => observer.callsign.includes(callsignSearch)) : null; + const vatsimPilots = vatsimData.pilots + ? vatsimData.pilots.filter((pilot: { callsign: string | string[] }) => pilot.callsign.includes(callsignSearch)) + : null; + const vatsimControllers = vatsimAllControllers + ? vatsimAllControllers.filter((controller: { callsign: string | string[] }) => + controller.callsign.includes(callsignSearch), + ) + : null; + const vatsimAtis = vatsimData.atis + ? vatsimData.atis.filter((atis: { callsign: string | string[] }) => atis.callsign.includes(callsignSearch)) + : null; + const vatsimObservers = vatsimAllObservers + ? vatsimAllObservers.filter((observer: { callsign: string | string[] }) => + observer.callsign.includes(callsignSearch), + ) + : null; const vatsimPilotCount = vatsimPilots ? vatsimPilots.length : 0; const vatsimControllerCount = vatsimControllers ? vatsimControllers.length : 0; const vatsimAtisCount = vatsimAtis ? vatsimAtis.length : 0; const vatsimObserverCount = vatsimObservers ? vatsimObservers.length : 0; - return interaction.reply({ embeds: [statsEmbed(vatsimPilotCount, vatsimControllerCount, vatsimAtisCount, vatsimObserverCount, callsignSearch)] }); + return interaction.reply({ + embeds: [ + statsEmbed(vatsimPilotCount, vatsimControllerCount, vatsimAtisCount, vatsimObserverCount, callsignSearch), + ], + }); } diff --git a/src/commands/utils/vatsim/vatsim.ts b/src/commands/utils/vatsim/vatsim.ts index c1511937..d159efc7 100644 --- a/src/commands/utils/vatsim/vatsim.ts +++ b/src/commands/utils/vatsim/vatsim.ts @@ -78,11 +78,12 @@ const data = slashCommandStructure({ ], }); -const fetchErrorEmbed = (error: any) => makeEmbed({ - title: 'VATSIM Data - Fetching data failure', - description: `Could not fetch the VATSIM data from the VATSIM API service: ${error}`, - color: Colors.Red, -}); +const fetchErrorEmbed = (error: any) => + makeEmbed({ + title: 'VATSIM Data - Fetching data failure', + description: `Could not fetch the VATSIM data from the VATSIM API service: ${error}`, + color: Colors.Red, + }); export default slashCommand(data, async ({ interaction }) => { // Fetch VATSIM data @@ -112,8 +113,10 @@ export default slashCommand(data, async ({ interaction }) => { const regexMatches = callsign.match(regexCheck); if (!regexMatches || !regexMatches.groups || !regexMatches.groups.callsignSearch) { - // eslint-disable-next-line consistent-return - return interaction.reply({ content: 'You need to provide a valid callsign or part of a callsign to search for', ephemeral: true }); + return interaction.reply({ + content: 'You need to provide a valid callsign or part of a callsign to search for', + ephemeral: true, + }); } callsignSearch = regexMatches.groups.callsignSearch; @@ -124,23 +127,23 @@ export default slashCommand(data, async ({ interaction }) => { const subcommandName = interaction.options.getSubcommand(); switch (subcommandName) { - case 'stats': - await handleVatsimStats(interaction, vatsimData, callsignSearch); - break; - case 'controllers': - await handleVatsimControllers(interaction, vatsimData, callsignSearch); - break; - case 'pilots': - await handleVatsimPilots(interaction, vatsimData, callsignSearch); - break; - case 'observers': - await handleVatsimObservers(interaction, vatsimData, callsignSearch); - break; - case 'events': - await handleVatsimEvents(interaction); - break; + case 'stats': + await handleVatsimStats(interaction, vatsimData, callsignSearch); + break; + case 'controllers': + await handleVatsimControllers(interaction, vatsimData, callsignSearch); + break; + case 'pilots': + await handleVatsimPilots(interaction, vatsimData, callsignSearch); + break; + case 'observers': + await handleVatsimObservers(interaction, vatsimData, callsignSearch); + break; + case 'events': + await handleVatsimEvents(interaction); + break; - default: - await interaction.reply({ content: 'Unknown subcommand', ephemeral: true }); + default: + await interaction.reply({ content: 'Unknown subcommand', ephemeral: true }); } }); diff --git a/src/commands/utils/wolframAlpha.ts b/src/commands/utils/wolframAlpha.ts index 71ed2744..36b83e6a 100644 --- a/src/commands/utils/wolframAlpha.ts +++ b/src/commands/utils/wolframAlpha.ts @@ -5,12 +5,14 @@ const data = slashCommandStructure({ name: 'wolframalpha', description: 'Queries the Wolfram Alpha API.', type: ApplicationCommandType.ChatInput, - options: [{ - name: 'query', - description: 'Please provide a query. For example: `.wa How much is 1 + 1?`.', - type: ApplicationCommandOptionType.String, - required: true, - }], + options: [ + { + name: 'query', + description: 'Please provide a query. For example: `.wa How much is 1 + 1?`.', + type: ApplicationCommandOptionType.String, + required: true, + }, + ], }); const noQueryEmbed = makeEmbed({ @@ -50,8 +52,7 @@ export default slashCommand(data, async ({ interaction }) => { const searchParams = new URLSearchParams(params); try { - const response = await fetch(`${WOLFRAMALPHA_API_URL}${searchParams.toString()}`) - .then((res) => res.json()); + const response = await fetch(`${WOLFRAMALPHA_API_URL}${searchParams.toString()}`).then((res) => res.json()); if (response.error) { const errorEmbed = makeEmbed({ @@ -93,18 +94,14 @@ export default slashCommand(data, async ({ interaction }) => { } const noResultsEmbed = makeEmbed({ title: 'Wolfram Alpha Error | No Results', - description: makeLines([ - 'No results were found for your query.', - ]), + description: makeLines(['No results were found for your query.']), color: Colors.Red, }); return interaction.followUp({ embeds: [noResultsEmbed], ephemeral: true }); } const obscureQueryEmbed = makeEmbed({ title: 'Wolfram Alpha Error | Could not understand query', - description: makeLines([ - 'Wolfram Alpha could not understand your query.', - ]), + description: makeLines(['Wolfram Alpha could not understand your query.']), color: Colors.Red, }); return interaction.followUp({ embeds: [obscureQueryEmbed], ephemeral: true }); diff --git a/src/commands/utils/zulu.ts b/src/commands/utils/zulu.ts index 74575a05..22557283 100644 --- a/src/commands/utils/zulu.ts +++ b/src/commands/utils/zulu.ts @@ -6,12 +6,14 @@ const data = slashCommandStructure({ name: 'zulu', description: 'Get the current time at a given UTC-offset timezone.', type: ApplicationCommandType.ChatInput, - options: [{ - name: 'offset', - description: 'Please provide a timezone within UTC-12 and UTC+14.', - type: ApplicationCommandOptionType.String, - required: false, - }], + options: [ + { + name: 'offset', + description: 'Please provide a timezone within UTC-12 and UTC+14.', + type: ApplicationCommandOptionType.String, + required: false, + }, + ], }); const dateFormat = 'HH:mm (LT)'; @@ -23,15 +25,10 @@ export default slashCommand(data, async ({ interaction }) => { const numericOffset = parseInt(utcOffset); const sign = utcOffset.startsWith('-') ? '-' : '+'; - if (Number.isNaN(numericOffset) - || numericOffset < -12 - || numericOffset > 14) { + if (Number.isNaN(numericOffset) || numericOffset < -12 || numericOffset > 14) { const invalidEmbed = makeEmbed({ title: 'Zulu Error | Invalid Offset', - description: makeLines([ - 'Please provide a timezone within UTC-12 and UTC+14.', - 'For example: `/zulu -5`.', - ]), + description: makeLines(['Please provide a timezone within UTC-12 and UTC+14.', 'For example: `/zulu -5`.']), color: Colors.Red, }); return interaction.reply({ embeds: [invalidEmbed], ephemeral: true }); @@ -39,5 +36,7 @@ export default slashCommand(data, async ({ interaction }) => { const formattedOffset = `${sign}${Math.abs(numericOffset)}`; - return interaction.reply({ content: `It is ${moment().utc().add(utcOffset, 'hours').format(dateFormat)} in that timezone (UTC${formattedOffset}).` }); + return interaction.reply({ + content: `It is ${moment().utc().add(utcOffset, 'hours').format(dateFormat)} in that timezone (UTC${formattedOffset}).`, + }); }); diff --git a/src/events/buttonHandlers/buttonHandler.ts b/src/events/buttonHandlers/buttonHandler.ts index c2cdac81..65000dc9 100644 --- a/src/events/buttonHandlers/buttonHandler.ts +++ b/src/events/buttonHandlers/buttonHandler.ts @@ -14,18 +14,22 @@ export default event(Events.InteractionCreate, async ({ log }, interaction) => { const [prefix, ...params] = interaction.customId.split('_'); switch (prefix) { - case 'roleAssignment': - const [roleID] = params; - await handleRoleAssignment(interaction, roleID); - log(`Button Handler: Role assignment button pressed by ${user.tag} (${user.id}). roleID: ${roleID}`); - break; - default: - if (buttonLabel) { - log(`Button Handler: Custom ID not matched. Skipping...\nCustom ID: ${customId}, Label: ${buttonLabel}, User: ${user.tag}, User ID: ${user.id}`); - } else { - log(`Button Handler: Custom ID not matched. Skipping...\nCustom ID: ${customId}, Label: null, User: ${user.tag}, User ID: ${user.id}`); - } - return; + case 'roleAssignment': + const [roleID] = params; + await handleRoleAssignment(interaction, roleID); + log(`Button Handler: Role assignment button pressed by ${user.tag} (${user.id}). roleID: ${roleID}`); + break; + default: + if (buttonLabel) { + log( + `Button Handler: Custom ID not matched. Skipping...\nCustom ID: ${customId}, Label: ${buttonLabel}, User: ${user.tag}, User ID: ${user.id}`, + ); + } else { + log( + `Button Handler: Custom ID not matched. Skipping...\nCustom ID: ${customId}, Label: null, User: ${user.tag}, User ID: ${user.id}`, + ); + } + return; } } catch (error) { log('Button Handler: Error handling button press', error); diff --git a/src/events/buttonHandlers/functions/handleRoleAssignment.ts b/src/events/buttonHandlers/functions/handleRoleAssignment.ts index 53233829..7d91d2e7 100644 --- a/src/events/buttonHandlers/functions/handleRoleAssignment.ts +++ b/src/events/buttonHandlers/functions/handleRoleAssignment.ts @@ -14,7 +14,7 @@ export async function handleRoleAssignment(interaction: ButtonInteraction, roleI if (!role) { Logger.error('Role Assignment: Role not found'); - interaction.editReply({ content: 'I couldn\'t find that role' }); + interaction.editReply({ content: "I couldn't find that role" }); return; } @@ -36,6 +36,9 @@ export async function handleRoleAssignment(interaction: ButtonInteraction, roleI } } catch (error) { Logger.error(error); - await interaction.editReply({ content: 'Something went wrong, this role may no longer exist. Please try again. The error message has been logged.' }); + await interaction.editReply({ + content: + 'Something went wrong, this role may no longer exist. Please try again. The error message has been logged.', + }); } } diff --git a/src/events/contextInteractionHandler.ts b/src/events/contextInteractionHandler.ts index d8afd555..47728c45 100644 --- a/src/events/contextInteractionHandler.ts +++ b/src/events/contextInteractionHandler.ts @@ -1,9 +1,7 @@ import { Color, ContextMenuCommand, event, Events, makeEmbed, Reply } from '../lib'; import contextArray from '../commands/context'; -const contextMap = new Map( - contextArray.map((c) => [c.meta.name, c]), -); +const contextMap = new Map(contextArray.map((c) => [c.meta.name, c])); export default event(Events.InteractionCreate, async ({ log, client }, interaction) => { if (!interaction.isContextMenuCommand()) { @@ -11,9 +9,7 @@ export default event(Events.InteractionCreate, async ({ log, client }, interacti } if (!interaction.inCachedGuild()) { - await interaction.reply( - Reply('This bot can only be used in a server!', Color.Error), - ); + await interaction.reply(Reply('This bot can only be used in a server!', Color.Error)); return; } diff --git a/src/events/logging/detectBan.ts b/src/events/logging/detectBan.ts index d9ae940a..46e24ef1 100644 --- a/src/events/logging/detectBan.ts +++ b/src/events/logging/detectBan.ts @@ -8,93 +8,96 @@ import { constantsConfig, event, Events, Infraction, Logger, makeEmbed, makeLine const MAX_RETRIES = 5; const SLEEP_TIMER = 0.5 * 1000; -const noLogEmbed = (user: User, guildName: string) => makeEmbed({ - color: Colors.Red, - author: { - name: `[BANNED] ${user.tag}`, - iconURL: user.displayAvatarURL(), - }, - description: makeLines([ - `${user.tag} was banned from ${guildName} but no audit log could be found.`, - '', - bold('NOTE - This was a non bot ban.'), - '', - `Please remember to send the user the reason they were banned and the ban appeal form - ${process.env.BAN_APPEAL_URL}`, - ]), - footer: { text: `User ID: ${user.id}` }, -}); - -const modLogEmbed = (user: User, executor: User, reason: string, formattedDate: string) => makeEmbed({ - color: Colors.Red, - author: { - name: `[BANNED] ${user.tag}`, - iconURL: user.displayAvatarURL(), - }, - description: makeLines([ - bold('NOTE - This was a non bot ban.'), - '', - `Please remember to send the user the reason they were banned and the ban appeal form - ${process.env.BAN_APPEAL_URL}`, - ]), - fields: [ - { - name: 'User', - value: `${user}`, - }, - { - name: 'Moderator', - value: `${executor}`, - }, - { - name: 'Reason', - value: reason || 'No reason provided', - }, - { - name: 'Days of messages deleted', - value: 'Unavailable with a non bot ban', - }, - { - name: 'Date', - value: formattedDate, - }, - ], - footer: { text: `User ID: ${user.id}` }, -}); - -const userBannedIncompleteEmbed = (user: User, formattedDate: string) => makeEmbed({ - color: Colors.Red, - author: { - name: `[BANNED] ${user.tag}`, - iconURL: user.displayAvatarURL(), - }, - description: makeLines([ - bold('NOTE - This was a non bot ban.'), - '', - `Please remember to send the user the reason they were banned and the ban appeal form - ${process.env.BAN_APPEAL_URL}`, - ]), - fields: [ - { - name: 'Member', - value: user.tag, - }, - { - name: 'Moderator', - value: 'Unavailable - Audit log incomplete', - }, - { - name: 'Reason', - value: 'Unavailable - Audit log incomplete', +const noLogEmbed = (user: User, guildName: string) => + makeEmbed({ + color: Colors.Red, + author: { + name: `[BANNED] ${user.tag}`, + iconURL: user.displayAvatarURL(), }, - { - name: 'Days of messages deleted', - value: 'Unavailable with a non bot ban', + description: makeLines([ + `${user.tag} was banned from ${guildName} but no audit log could be found.`, + '', + bold('NOTE - This was a non bot ban.'), + '', + `Please remember to send the user the reason they were banned and the ban appeal form - ${process.env.BAN_APPEAL_URL}`, + ]), + footer: { text: `User ID: ${user.id}` }, + }); + +const modLogEmbed = (user: User, executor: User, reason: string, formattedDate: string) => + makeEmbed({ + color: Colors.Red, + author: { + name: `[BANNED] ${user.tag}`, + iconURL: user.displayAvatarURL(), }, - { - name: 'Date', - value: formattedDate, + description: makeLines([ + bold('NOTE - This was a non bot ban.'), + '', + `Please remember to send the user the reason they were banned and the ban appeal form - ${process.env.BAN_APPEAL_URL}`, + ]), + fields: [ + { + name: 'User', + value: `${user}`, + }, + { + name: 'Moderator', + value: `${executor}`, + }, + { + name: 'Reason', + value: reason || 'No reason provided', + }, + { + name: 'Days of messages deleted', + value: 'Unavailable with a non bot ban', + }, + { + name: 'Date', + value: formattedDate, + }, + ], + footer: { text: `User ID: ${user.id}` }, + }); + +const userBannedIncompleteEmbed = (user: User, formattedDate: string) => + makeEmbed({ + color: Colors.Red, + author: { + name: `[BANNED] ${user.tag}`, + iconURL: user.displayAvatarURL(), }, - ], - footer: { text: `User ID: ${user.id}` }, -}); + description: makeLines([ + bold('NOTE - This was a non bot ban.'), + '', + `Please remember to send the user the reason they were banned and the ban appeal form - ${process.env.BAN_APPEAL_URL}`, + ]), + fields: [ + { + name: 'Member', + value: user.tag, + }, + { + name: 'Moderator', + value: 'Unavailable - Audit log incomplete', + }, + { + name: 'Reason', + value: 'Unavailable - Audit log incomplete', + }, + { + name: 'Days of messages deleted', + value: 'Unavailable with a non bot ban', + }, + { + name: 'Date', + value: formattedDate, + }, + ], + footer: { text: `User ID: ${user.id}` }, + }); const logFailed = makeEmbed({ title: 'Non Bot Ban - Failed to log', @@ -105,23 +108,21 @@ const logFailed = makeEmbed({ export default event(Events.GuildBanAdd, async (_, msg) => { Logger.debug('Starting Ban Handler'); - const guildBanAdd = msg as GuildBan; + const guildBanAdd = msg; if (guildBanAdd.guild === null) { // DMs return; } - const modLogsChannel = await guildBanAdd.guild.channels.resolve(constantsConfig.channels.MOD_LOGS) as TextChannel | null; + const modLogsChannel = await guildBanAdd.guild.channels.resolve(constantsConfig.channels.MOD_LOGS); if (!modLogsChannel) { // Exit as can't post return; } const currentDate = new Date(); - const formattedDate: string = moment(currentDate) - .utcOffset(0) - .format(); + const formattedDate: string = moment(currentDate).utcOffset(0).format(); let executor; let reason; @@ -130,10 +131,9 @@ export default event(Events.GuildBanAdd, async (_, msg) => { do { Logger.debug(`Ban Handler - Finding Audit Log entry retries left: ${retryCount}`); if (retryCount < MAX_RETRIES) { - // eslint-disable-next-line no-await-in-loop await new Promise((f) => setTimeout(f, SLEEP_TIMER)); } - // eslint-disable-next-line no-await-in-loop + const fetchedLogs = await guildBanAdd.guild.fetchAuditLogs({ limit: 1, type: AuditLogEvent.MemberBanAdd, @@ -144,8 +144,7 @@ export default event(Events.GuildBanAdd, async (_, msg) => { } retryCount--; - } - while ((!target || target.id !== guildBanAdd.user.id) && retryCount > 0); + } while ((!target || target.id !== guildBanAdd.user.id) && retryCount > 0); if (!target) { await modLogsChannel.send({ embeds: [noLogEmbed(guildBanAdd.user, guildBanAdd.guild.name)] }); @@ -156,7 +155,10 @@ export default event(Events.GuildBanAdd, async (_, msg) => { return; } if (executor && !constantsConfig.modLogExclude.includes(executor.id)) { - await modLogsChannel.send({ content: executor.toString(), embeds: [modLogEmbed(guildBanAdd.user, executor, reason as string, formattedDate)] }); + await modLogsChannel.send({ + content: executor.toString(), + embeds: [modLogEmbed(guildBanAdd.user, executor, reason as string, formattedDate)], + }); //Log to the DB Logger.info('Starting Infraction process'); diff --git a/src/events/logging/messageDelete.ts b/src/events/logging/messageDelete.ts index 74215e10..a02711c4 100644 --- a/src/events/logging/messageDelete.ts +++ b/src/events/logging/messageDelete.ts @@ -7,12 +7,12 @@ const CONTENT_NOT_AVAIL = 'Unable to find content or embeds.'; export default event(Events.MessageDelete, async (_, msg) => { try { if (msg.guild === null || msg.author === null) { - // DMs + // DMs return; } if (msg.content === null || msg.content.trim() === '') { - // Old Message or empty content + // Old Message or empty content return; } @@ -22,10 +22,8 @@ export default event(Events.MessageDelete, async (_, msg) => { }); const deletionLog = fetchedLogs.entries.first(); const currentDate = new Date(); - const formattedDate: string = moment(currentDate) - .utcOffset(0) - .format('DD, MM, YYYY, HH:mm:ss'); - const userLogsChannel = msg.guild.channels.resolve(constantsConfig.channels.USER_LOGS) as TextChannel | null; + const formattedDate: string = moment(currentDate).utcOffset(0).format('DD, MM, YYYY, HH:mm:ss'); + const userLogsChannel = msg.guild.channels.resolve(constantsConfig.channels.USER_LOGS); const messageEmbeds = msg.embeds.length > 0 ? msg.embeds : []; const messageComponents = []; if (msg.content) { @@ -93,7 +91,10 @@ export default event(Events.MessageDelete, async (_, msg) => { }, { name: 'Deleted by', - value: (deletionLog && deletionLog.target.id === msg.author.id) ? `${deletionLog.executor}` : 'No audit log was found, message was either deleted by author, or a bot', + value: + deletionLog && deletionLog.target.id === msg.author.id + ? `${deletionLog.executor}` + : 'No audit log was found, message was either deleted by author, or a bot', inline: false, }, { @@ -105,7 +106,7 @@ export default event(Events.MessageDelete, async (_, msg) => { footer: { text: `User ID: ${msg.author.id}` }, }); - if (userLogsChannel && !constantsConfig.userLogExclude.includes(msg.author!.id)) { + if (userLogsChannel && !constantsConfig.userLogExclude.includes(msg.author.id)) { await userLogsChannel.send({ embeds: [messageDeleteEmbed] }); } } catch (error) { diff --git a/src/events/logging/messageUpdate.ts b/src/events/logging/messageUpdate.ts index 11d509a5..34d76b98 100644 --- a/src/events/logging/messageUpdate.ts +++ b/src/events/logging/messageUpdate.ts @@ -1,17 +1,17 @@ import { Colors, TextChannel } from 'discord.js'; import { constantsConfig, event, Events, imageBaseUrl, Logger, makeEmbed } from '../../lib'; -const FEATURE_NOT_AVAIL = '(can\'t show embeds or images)'; +const FEATURE_NOT_AVAIL = "(can't show embeds or images)"; export default event(Events.MessageUpdate, async (_, oldMessage, newMessage) => { try { if (oldMessage.guild === null || oldMessage.author === null || newMessage.author === null) { - // DMs + // DMs return; } if (oldMessage.content === null) { - // Old Message + // Old Message return; } @@ -20,7 +20,7 @@ export default event(Events.MessageUpdate, async (_, oldMessage, newMessage) => return; } - const userLogsChannel = oldMessage.guild.channels.resolve(constantsConfig.channels.USER_LOGS) as TextChannel | null; + const userLogsChannel = oldMessage.guild.channels.resolve(constantsConfig.channels.USER_LOGS); const MAX_MESSAGE_LENGTH = 1024; @@ -40,7 +40,7 @@ export default event(Events.MessageUpdate, async (_, oldMessage, newMessage) => editedMessageFieldTitle = 'Edited Message (truncated)'; } - if (userLogsChannel && !constantsConfig.userLogExclude.includes(oldMessage.author!.id)) { + if (userLogsChannel && !constantsConfig.userLogExclude.includes(oldMessage.author.id)) { const messageUpdateEmbed = makeEmbed({ color: Colors.Orange, thumbnail: { url: `${imageBaseUrl}/moderation/message_edited.png` }, @@ -51,8 +51,16 @@ export default event(Events.MessageUpdate, async (_, oldMessage, newMessage) => fields: [ { name: 'Author', value: `${oldMessage.author}`, inline: true }, { name: 'Channel', value: `${oldMessage.channel}`, inline: true }, - { name: originalMessageFieldTitle, value: oldMessageContent ? `\`\`\`${oldMessageContent}\`\`\`` : FEATURE_NOT_AVAIL, inline: false }, - { name: editedMessageFieldTitle, value: newMessageContent ? `\`\`\`${newMessageContent}\`\`\`` : FEATURE_NOT_AVAIL, inline: false }, + { + name: originalMessageFieldTitle, + value: oldMessageContent ? `\`\`\`${oldMessageContent}\`\`\`` : FEATURE_NOT_AVAIL, + inline: false, + }, + { + name: editedMessageFieldTitle, + value: newMessageContent ? `\`\`\`${newMessageContent}\`\`\`` : FEATURE_NOT_AVAIL, + inline: false, + }, ], footer: { text: `User ID: ${oldMessage.author.id}` }, }); diff --git a/src/events/logging/scamLogs.ts b/src/events/logging/scamLogs.ts index 1b2cb265..625ee389 100644 --- a/src/events/logging/scamLogs.ts +++ b/src/events/logging/scamLogs.ts @@ -1,6 +1,16 @@ import { codeBlock, Colors, DMChannel, TextChannel } from 'discord.js'; import mongoose from 'mongoose'; -import { constantsConfig, makeEmbed, makeLines, event, Events, getConn, Infraction, Logger, imageBaseUrl } from '../../lib'; +import { + constantsConfig, + makeEmbed, + makeLines, + event, + Events, + getConn, + Infraction, + Logger, + imageBaseUrl, +} from '../../lib'; const excludedRoles = [ constantsConfig.roles.ADMIN_TEAM, @@ -35,7 +45,7 @@ export default event(Events.MessageCreate, async ({ log }, msg) => { return; } - const scamReportLogs = msg.guild.channels.resolve(constantsConfig.channels.SCAM_REPORT_LOGS) as TextChannel | null; + const scamReportLogs = msg.guild.channels.resolve(constantsConfig.channels.SCAM_REPORT_LOGS); if (scamReportLogs && msg.content.toLowerCase().includes('@everyone') && !msg.author.bot) { const conn = getConn(); if (!conn && scamReportLogs) { @@ -143,7 +153,9 @@ export default event(Events.MessageCreate, async ({ log }, msg) => { } // Try and send a DM try { - await msg.author.send('We have detected use of @everyone in one of our text channels. This function is in place to prevent discord scams and has resulted in an automatic timeout and notification of our moderation team. If this was done in error, our moderation team will reverse the timeout, however please refrain from using the @everyone ping in future.'); + await msg.author.send( + 'We have detected use of @everyone in one of our text channels. This function is in place to prevent discord scams and has resulted in an automatic timeout and notification of our moderation team. If this was done in error, our moderation team will reverse the timeout, however please refrain from using the @everyone ping in future.', + ); } catch (e) { log(e); diff --git a/src/events/ready.ts b/src/events/ready.ts index d907af85..7b7a54fa 100644 --- a/src/events/ready.ts +++ b/src/events/ready.ts @@ -1,15 +1,6 @@ import { ActivityType, TextChannel } from 'discord.js'; import moment from 'moment'; -import { - constantsConfig, - event, - Events, - connect, - setupScheduler, - Logger, - imageBaseUrl, - getScheduler, -} from '../lib'; +import { constantsConfig, event, Events, connect, setupScheduler, Logger, imageBaseUrl, getScheduler } from '../lib'; import { deployCommands } from '../scripts/deployCommands'; import commandArray from '../commands'; import contextArray from '../commands/context'; @@ -35,16 +26,16 @@ export default event(Events.ClientReady, async ({ log }, client) => { if (process.env.DEPLOY === 'true') { log('DEPLOY variable set to true, deploying commands and contexts.'); try { - await deployCommands(commandArray, contextArray) - .then(async (user) => { - const bot = `<@${user.id}>`; + await deployCommands(commandArray, contextArray).then(async (user) => { + const bot = `<@${user.id}>`; - const response = process.env.NODE_ENV === 'production' + const response = + process.env.NODE_ENV === 'production' ? `Deployed ${commandArray.length} commands and ${contextArray.length} contexts globally as ${bot}!` : `Deployed ${commandArray.length} commands and ${contextArray.length} contexts to \`<@${constantsConfig.guildId}>\` as ${bot}!`; - log(response); - }); + log(response); + }); } catch (error) { log('Failed to deploy commands:', error); } @@ -81,14 +72,18 @@ export default event(Events.ClientReady, async ({ log }, client) => { if (scheduler) { const heartbeatJobList = await scheduler.jobs({ name: 'sendHeartbeat' }); if (heartbeatJobList.length === 0) { - scheduler.every(`${process.env.HEARTBEAT_INTERVAL} seconds`, 'sendHeartbeat', { interval: process.env.HEARTBEAT_INTERVAL }); + scheduler.every(`${process.env.HEARTBEAT_INTERVAL} seconds`, 'sendHeartbeat', { + interval: process.env.HEARTBEAT_INTERVAL, + }); Logger.info(`Heartbeat job scheduled with interval ${process.env.HEARTBEAT_INTERVAL}`); } else { const heartbeatJob = heartbeatJobList[0]; const { interval } = heartbeatJob.attrs.data as { interval: string }; if (interval !== process.env.HEARTBEAT_INTERVAL) { await scheduler.cancel({ name: 'sendHeartbeat' }); - scheduler.every(`${process.env.HEARTBEAT_INTERVAL} seconds`, 'sendHeartbeat', { interval: process.env.HEARTBEAT_INTERVAL }); + scheduler.every(`${process.env.HEARTBEAT_INTERVAL} seconds`, 'sendHeartbeat', { + interval: process.env.HEARTBEAT_INTERVAL, + }); Logger.info(`Heartbeat job rescheduled with new interval ${process.env.HEARTBEAT_INTERVAL}`); } else { Logger.info('Heartbeat job already scheduled'); @@ -103,14 +98,18 @@ export default event(Events.ClientReady, async ({ log }, client) => { if (scheduler) { const birthdayJobList = await scheduler.jobs({ name: 'postBirthdays' }); if (birthdayJobList.length === 0) { - scheduler.every(`${process.env.BIRTHDAY_INTERVAL} seconds`, 'postBirthdays', { interval: process.env.BIRTHDAY_INTERVAL }); + scheduler.every(`${process.env.BIRTHDAY_INTERVAL} seconds`, 'postBirthdays', { + interval: process.env.BIRTHDAY_INTERVAL, + }); Logger.info(`Birthday job scheduled with interval ${process.env.BIRTHDAY_INTERVAL}`); } else { const birthdayJob = birthdayJobList[0]; const { interval } = birthdayJob.attrs.data as { interval: string }; if (interval !== process.env.BIRTHDAY_INTERVAL) { await scheduler.cancel({ name: 'postBirthdays' }); - scheduler.every(`${process.env.BIRTHDAY_INTERVAL} seconds`, 'postBirthdays', { interval: process.env.BIRTHDAY_INTERVAL }); + scheduler.every(`${process.env.BIRTHDAY_INTERVAL} seconds`, 'postBirthdays', { + interval: process.env.BIRTHDAY_INTERVAL, + }); Logger.info(`Birthday job rescheduled with new interval ${process.env.BIRTHDAY_INTERVAL}`); } else { Logger.info('Birthday job already scheduled'); @@ -123,9 +122,7 @@ export default event(Events.ClientReady, async ({ log }, client) => { const botDevChannel = client.channels.resolve(constantsConfig.channels.MOD_LOGS) as TextChannel; if (botDevChannel) { const currentDate = new Date(); - const formattedDate = moment(currentDate) - .utcOffset(0) - .format(); + const formattedDate = moment(currentDate).utcOffset(0).format(); // Include the database connection and scheduler status in the mod logs message. let logMessage = `<@&${constantsConfig.roles.BOT_DEVELOPER}>\n[${formattedDate}] - ${client.user?.username} has connected! - DB State: ${dbConnected ? 'Connected' : 'Disconnected'}`; diff --git a/src/events/slashCommandHandler.ts b/src/events/slashCommandHandler.ts index 0d6edaf0..513acbc3 100644 --- a/src/events/slashCommandHandler.ts +++ b/src/events/slashCommandHandler.ts @@ -1,8 +1,6 @@ import { Color, SlashCommand, event, Events, Reply, makeEmbed } from '../lib'; import commandArray from '../commands'; -/* eslint-disable no-underscore-dangle */ - const commandMap = new Map(); for (const cmd of commandArray) { @@ -15,14 +13,12 @@ export default event(Events.InteractionCreate, async ({ log, client }, interacti } if (!interaction.inCachedGuild()) { - await interaction.reply( - Reply('This bot can only be used in a server!', Color.Error), - ); + await interaction.reply(Reply('This bot can only be used in a server!', Color.Error)); return; } try { - const { commandName, options } = interaction as{ + const { commandName, options } = interaction as { commandName: any; options: any; }; diff --git a/src/lib/config.ts b/src/lib/config.ts index 7a9e9760..8fb45900 100644 --- a/src/lib/config.ts +++ b/src/lib/config.ts @@ -8,8 +8,8 @@ const imageBaseUrl = originalBaseUrl.endsWith('/') ? originalBaseUrl.slice(0, -1 export { imageBaseUrl }; interface roleAssignmentId { - group: string, - roles: { id: string, label: string}[] + group: string; + roles: { id: string; label: string }[]; } // Config constants that are directly used in code should be mandatory, @@ -19,62 +19,62 @@ interface roleAssignmentId { // not mandatory, as they can be dynamic. interface Config { aircraftTypeList: { - [x: string]: string, - }, + [x: string]: string; + }; channels: { - A32NX_SUPPORT: string, - FAQ: string, - FLIGHT_SCHOOL: string, - KNOWN_ISSUES: string, - MOD_ALERTS: string, - MOD_LOGS: string, - ROLES: string, - SCAM_REPORT_LOGS: string, - TEAM: string, - USER_LOGS: string, - VIDEOS: string, - [x: string]: string, - }, + A32NX_SUPPORT: string; + FAQ: string; + FLIGHT_SCHOOL: string; + KNOWN_ISSUES: string; + MOD_ALERTS: string; + MOD_LOGS: string; + ROLES: string; + SCAM_REPORT_LOGS: string; + TEAM: string; + USER_LOGS: string; + VIDEOS: string; + [x: string]: string; + }; colors: { - FBW_CYAN: string, - [x: string]: string, - }, + FBW_CYAN: string; + [x: string]: string; + }; commandPermission: { - MANAGE_SERVER: string, - [x: string]: string, - }, - guildId: string, - modLogExclude: string[], - roleAssignmentIds: roleAssignmentId[], + MANAGE_SERVER: string; + [x: string]: string; + }; + guildId: string; + modLogExclude: string[]; + roleAssignmentIds: roleAssignmentId[]; roleGroups: { - [x: string]: string[], - }, + [x: string]: string[]; + }; roles: { - ADMIN_TEAM: string, - BOT_DEVELOPER: string, - COMMUNITY_SUPPORT: string, - DEVELOPMENT_TEAM: string, - FBW_EMERITUS: string, - MEDIA_TEAM: string, - MODERATION_TEAM: string, - [x: string]: string, - }, + ADMIN_TEAM: string; + BOT_DEVELOPER: string; + COMMUNITY_SUPPORT: string; + DEVELOPMENT_TEAM: string; + FBW_EMERITUS: string; + MEDIA_TEAM: string; + MODERATION_TEAM: string; + [x: string]: string; + }; threads: { - BIRTHDAY_THREAD: string, - COUNT_THREAD: string, - [x: string]: string, - }, + BIRTHDAY_THREAD: string; + COUNT_THREAD: string; + [x: string]: string; + }; units: { - CELSIUS: string, - DEGREES: string, - [x: string]: string, - }, - userLogExclude: string[], + CELSIUS: string; + DEGREES: string; + [x: string]: string; + }; + userLogExclude: string[]; } let parsedConfig: Config; try { - parsedConfig = (botConfig as unknown as Config); + parsedConfig = botConfig as unknown as Config; if (!parsedConfig.commandPermission.MANAGE_SERVER) { // Making sure this is always set, even if an empty string is given parsedConfig.commandPermission.MANAGE_SERVER = '32'; diff --git a/src/lib/contextMenuCommand.ts b/src/lib/contextMenuCommand.ts index 33051c80..6b1856bb 100644 --- a/src/lib/contextMenuCommand.ts +++ b/src/lib/contextMenuCommand.ts @@ -2,7 +2,8 @@ import { Awaitable, Client, ContextMenuCommandBuilder, - RESTPostAPIApplicationCommandsJSONBody, ContextMenuCommandInteraction, + RESTPostAPIApplicationCommandsJSONBody, + ContextMenuCommandInteraction, } from 'discord.js'; import { LogMethods } from './index'; @@ -14,9 +15,7 @@ export interface ContextMenuCommandProps { export type ContextMenuCommandCallback = (props: ContextMenuCommandProps) => Awaitable; -export type ContextMenuCommandStructure = - | ContextMenuCommandBuilder - | RESTPostAPIApplicationCommandsJSONBody +export type ContextMenuCommandStructure = ContextMenuCommandBuilder | RESTPostAPIApplicationCommandsJSONBody; export interface ContextMenuCommand { meta: ContextMenuCommandStructure; @@ -27,6 +26,9 @@ export function contextMenuCommandStructure(data: RESTPostAPIApplicationCommands return data; } -export function contextMenuCommand(meta: ContextMenuCommandStructure, callback: ContextMenuCommandCallback): ContextMenuCommand { +export function contextMenuCommand( + meta: ContextMenuCommandStructure, + callback: ContextMenuCommandCallback, +): ContextMenuCommand { return { meta, callback }; } diff --git a/src/lib/durationInEnglish.ts b/src/lib/durationInEnglish.ts index 1b15515a..fcade0af 100644 --- a/src/lib/durationInEnglish.ts +++ b/src/lib/durationInEnglish.ts @@ -3,10 +3,12 @@ export function durationInEnglish(milliseconds: any) { if (seconds < 60) { return `${Math.floor(seconds)} second${Math.floor(seconds) === 1 ? '' : 's'}`; - } if (seconds < 3600) { + } + if (seconds < 3600) { const minutes = seconds / 60; return `${Math.floor(minutes)} minute${Math.floor(minutes) === 1 ? '' : 's'}`; - } if (seconds < 86400) { + } + if (seconds < 86400) { const hours = seconds / 3600; return `${Math.floor(hours)} hour${Math.floor(hours) === 1 ? '' : 's'}`; } diff --git a/src/lib/embed.ts b/src/lib/embed.ts index 5d3f3155..e1d17a9d 100644 --- a/src/lib/embed.ts +++ b/src/lib/embed.ts @@ -16,11 +16,11 @@ export function makeLines(lines: string[]): string { export const makeList = (lines: string[], type?: ListTypes): string => { switch (type) { - case 'bullet': - return lines.map((line) => `• ${line}`).join('\n'); - case 'ordered': - return lines.map((line, index) => `${index + 1}. ${line}`).join('\n'); - default: - return lines.map((line) => `- ${line}`).join('\n'); + case 'bullet': + return lines.map((line) => `• ${line}`).join('\n'); + case 'ordered': + return lines.map((line, index) => `${index + 1}. ${line}`).join('\n'); + default: + return lines.map((line) => `- ${line}`).join('\n'); } }; diff --git a/src/lib/events.ts b/src/lib/events.ts index cc3e23a4..b3240f29 100644 --- a/src/lib/events.ts +++ b/src/lib/events.ts @@ -11,10 +11,7 @@ export interface EventProps { log: LogMethods; } -export type EventCallback = ( - props: EventProps, - ...args: ClientEvents[T] -) => Awaitable; +export type EventCallback = (props: EventProps, ...args: ClientEvents[T]) => Awaitable; export interface Event { key: T; @@ -28,7 +25,6 @@ export function event(key: T, callback: EventCallback): export function registerEvents(client: Client, events: Event[]): void { for (const { key, callback } of events) { client.on(key, (...args) => { - // eslint-disable-next-line no-console const log = console.log.bind(Logger, `[Event: ${key}]`); try { diff --git a/src/lib/genericEmbedPagination.ts b/src/lib/genericEmbedPagination.ts index e1024331..e3422c6d 100644 --- a/src/lib/genericEmbedPagination.ts +++ b/src/lib/genericEmbedPagination.ts @@ -1,6 +1,20 @@ -import { ActionRowBuilder, ButtonBuilder, ButtonInteraction, ButtonStyle, CommandInteraction, ComponentType, EmbedBuilder, Interaction, InteractionResponse, Message } from 'discord.js'; +import { + ActionRowBuilder, + ButtonBuilder, + ButtonInteraction, + ButtonStyle, + CommandInteraction, + ComponentType, + EmbedBuilder, + Interaction, + InteractionResponse, + Message, +} from 'discord.js'; -export async function createPaginatedEmbedHandler(initialInteraction: CommandInteraction, embeds: EmbedBuilder[]): Promise { +export async function createPaginatedEmbedHandler( + initialInteraction: CommandInteraction, + embeds: EmbedBuilder[], +): Promise { let currentPage = 0; const nextButton = new ButtonBuilder() @@ -25,7 +39,11 @@ export async function createPaginatedEmbedHandler(initialInteraction: CommandInt } const filter = (buttonInteraction: Interaction) => initialInteraction.user.id === buttonInteraction.user.id; - const collector = message.createMessageComponentCollector({ filter, componentType: ComponentType.Button, time: 120_000 }); + const collector = message.createMessageComponentCollector({ + filter, + componentType: ComponentType.Button, + time: 120_000, + }); collector.on('collect', async (collectedInteraction: ButtonInteraction) => { await collectedInteraction.deferUpdate(); @@ -51,7 +69,14 @@ export async function createPaginatedEmbedHandler(initialInteraction: CommandInt function handleEmbedExpire() { const embed = embeds[currentPage]; - initialInteraction.editReply({ embeds: [embed.setFooter({ text: `${embed.data.footer ? `${embed.data.footer.text} - ` : ''}This embed has expired.` })], components: [] }); + initialInteraction.editReply({ + embeds: [ + embed.setFooter({ + text: `${embed.data.footer ? `${embed.data.footer.text} - ` : ''}This embed has expired.`, + }), + ], + components: [], + }); } function setButtonDisabledStates() { diff --git a/src/lib/infractionEmbedPagination.ts b/src/lib/infractionEmbedPagination.ts index a5150526..3c268884 100644 --- a/src/lib/infractionEmbedPagination.ts +++ b/src/lib/infractionEmbedPagination.ts @@ -1,6 +1,26 @@ -import { ActionRowBuilder, ButtonBuilder, ButtonStyle, Interaction, CommandInteraction, ButtonInteraction, EmbedBuilder } from 'discord.js'; - -export async function createPaginatedInfractionEmbedHandler(initialInteraction: CommandInteraction, user:string, embeds: EmbedBuilder[], infractionsLengths: { warnsLength: string; timeoutsLength: string; scamLogsLength: string; bansLength: string; unbansLength: string; notesLength: string; }): Promise { +import { + ActionRowBuilder, + ButtonBuilder, + ButtonStyle, + Interaction, + CommandInteraction, + ButtonInteraction, + EmbedBuilder, +} from 'discord.js'; + +export async function createPaginatedInfractionEmbedHandler( + initialInteraction: CommandInteraction, + user: string, + embeds: EmbedBuilder[], + infractionsLengths: { + warnsLength: string; + timeoutsLength: string; + scamLogsLength: string; + bansLength: string; + unbansLength: string; + notesLength: string; + }, +): Promise { let currentPage = 0; const aboutButton = new ButtonBuilder() @@ -39,8 +59,16 @@ export async function createPaginatedInfractionEmbedHandler(initialInteraction: .setStyle(ButtonStyle.Primary); const buttonRow1 = new ActionRowBuilder().addComponents(aboutButton, warnButton, timeoutButton); - const buttonRow2 = new ActionRowBuilder().addComponents(scamLogButton, banButton, unbanButton, noteButton); - const message = await initialInteraction.followUp({ embeds: [embeds[currentPage]], components: [buttonRow1, buttonRow2] }); + const buttonRow2 = new ActionRowBuilder().addComponents( + scamLogButton, + banButton, + unbanButton, + noteButton, + ); + const message = await initialInteraction.followUp({ + embeds: [embeds[currentPage]], + components: [buttonRow1, buttonRow2], + }); const filter = (interaction: Interaction) => interaction.user.id === user; const collector = message.createMessageComponentCollector({ filter, time: 120_000 }); @@ -85,6 +113,13 @@ export async function createPaginatedInfractionEmbedHandler(initialInteraction: function handleEmbedExpire() { const embed = embeds[currentPage]; - initialInteraction.editReply({ embeds: [embed.setFooter({ text: `${embed.data.footer ? `${embed.data.footer.text} - ` : ''}This embed has expired.` })], components: [] }); + initialInteraction.editReply({ + embeds: [ + embed.setFooter({ + text: `${embed.data.footer ? `${embed.data.footer.text} - ` : ''}This embed has expired.`, + }), + ], + components: [], + }); } } diff --git a/src/lib/logger.ts b/src/lib/logger.ts index d2f2e6f4..c8237154 100644 --- a/src/lib/logger.ts +++ b/src/lib/logger.ts @@ -19,7 +19,5 @@ const format = () => { export const Logger = winston.createLogger({ level: level(), format: format(), - transports: [ - new winston.transports.Console(), - ], + transports: [new winston.transports.Console()], }); diff --git a/src/lib/replies.ts b/src/lib/replies.ts index 472fcf34..e25d588f 100644 --- a/src/lib/replies.ts +++ b/src/lib/replies.ts @@ -11,15 +11,17 @@ export enum Color { export const EditReply = (msg: string, color: Color = Color.Info): InteractionEditReplyOptions => ({ content: undefined, - embeds: [{ - description: msg, - color, - }], + embeds: [ + { + description: msg, + color, + }, + ], components: [], files: [], }); export const Reply = (msg: string, color: Color = Color.Info): InteractionReplyOptions => ({ ephemeral: true, - ...EditReply(msg, color) as InteractionReplyOptions, + ...(EditReply(msg, color) as InteractionReplyOptions), }); diff --git a/src/lib/schedulerJobs/autoDisableSlowMode.ts b/src/lib/schedulerJobs/autoDisableSlowMode.ts index 1684d5e2..ac9e8e83 100644 --- a/src/lib/schedulerJobs/autoDisableSlowMode.ts +++ b/src/lib/schedulerJobs/autoDisableSlowMode.ts @@ -3,17 +3,19 @@ import { ChannelType, TextChannel, Colors } from 'discord.js'; import { client } from '../../client'; import { constantsConfig, makeEmbed, Logger, getScheduler } from '../index'; -const failedEmbed = (action: string, channel: string) => makeEmbed({ - title: `Slow Message - ${action} failed`, - description: `Failed to ${action} the slow mode for channel <#${channel}>.`, - color: Colors.Red, -}); +const failedEmbed = (action: string, channel: string) => + makeEmbed({ + title: `Slow Message - ${action} failed`, + description: `Failed to ${action} the slow mode for channel <#${channel}>.`, + color: Colors.Red, + }); -const modLogEmbed = (action: string, fields: any, color: number) => makeEmbed({ - title: `Slow Mode - ${action}`, - fields, - color, -}); +const modLogEmbed = (action: string, fields: any, color: number) => + makeEmbed({ + title: `Slow Mode - ${action}`, + fields, + color, + }); export async function autoDisableSlowMode(job: Job) { const scheduler = getScheduler(); @@ -22,7 +24,7 @@ export async function autoDisableSlowMode(job: Job) { return; } // Needed because of https://github.com/agenda/agenda/issues/401 - // eslint-disable-next-line no-underscore-dangle + const matchingJobs = await scheduler.jobs({ _id: job.attrs._id }); if (matchingJobs.length !== 1) { Logger.debug('Job has been deleted already, skipping execution.'); @@ -31,7 +33,12 @@ export async function autoDisableSlowMode(job: Job) { const { channelId } = job.attrs.data as { channelId: string }; const modLogsChannel = client.channels.resolve(constantsConfig.channels.MOD_LOGS) as TextChannel | null; const slowmodeChannel = client.channels.resolve(channelId); - if (!slowmodeChannel || [ChannelType.GuildText, ChannelType.GuildForum, ChannelType.PublicThread, ChannelType.PrivateThread].indexOf(slowmodeChannel.type) === -1) { + if ( + !slowmodeChannel || + [ChannelType.GuildText, ChannelType.GuildForum, ChannelType.PublicThread, ChannelType.PrivateThread].indexOf( + slowmodeChannel.type, + ) === -1 + ) { Logger.error('Slow mode - Auto disable - Unable to disable for non-existing channel'); if (modLogsChannel) { await modLogsChannel.send({ embeds: [failedEmbed('Auto disable', channelId)] }); @@ -39,7 +46,12 @@ export async function autoDisableSlowMode(job: Job) { return; } try { - if (slowmodeChannel.type === ChannelType.GuildForum || slowmodeChannel.type === ChannelType.GuildText || slowmodeChannel.type === ChannelType.PrivateThread || slowmodeChannel.type === ChannelType.PublicThread) { + if ( + slowmodeChannel.type === ChannelType.GuildForum || + slowmodeChannel.type === ChannelType.GuildText || + slowmodeChannel.type === ChannelType.PrivateThread || + slowmodeChannel.type === ChannelType.PublicThread + ) { await slowmodeChannel.setRateLimitPerUser(0, 'Slow mode disabled through bot'); } await job.remove(); @@ -51,29 +63,34 @@ export async function autoDisableSlowMode(job: Job) { try { // @ts-ignore await modLogsChannel.send({ - embeds: [modLogEmbed('Auto Disable', [ - { - inline: true, - name: 'Channel', - value: `<#${channelId}>`, - }, - { - inline: true, - name: 'Slow mode limit', - value: 'Disabled', - }, - { - inline: true, - name: 'Auto disable timeout', - value: 'None', - }, - { - inline: true, - name: 'Moderator', - value: 'FBW Bot', - }, + embeds: [ + modLogEmbed( + 'Auto Disable', + [ + { + inline: true, + name: 'Channel', + value: `<#${channelId}>`, + }, + { + inline: true, + name: 'Slow mode limit', + value: 'Disabled', + }, + { + inline: true, + name: 'Auto disable timeout', + value: 'None', + }, + { + inline: true, + name: 'Moderator', + value: 'FBW Bot', + }, + ], + Colors.Green, + ), ], - Colors.Green)], }); } catch (err) { Logger.warn(`Failed to send Mod Log for auto disable of slow mode for channel <#${channelId}>: ${err}`); diff --git a/src/lib/schedulerJobs/postBirthdays.ts b/src/lib/schedulerJobs/postBirthdays.ts index 6b11f669..74ebb305 100644 --- a/src/lib/schedulerJobs/postBirthdays.ts +++ b/src/lib/schedulerJobs/postBirthdays.ts @@ -25,14 +25,13 @@ export async function postBirthdays(job: Job) { return; } - // eslint-disable-next-line no-underscore-dangle const matchingJobs = await scheduler.jobs({ _id: job.attrs._id }); if (matchingJobs.length !== 1) { Logger.debug('Job has been deleted already, skipping execution.'); return; } - const guild = client.guilds.resolve(constantsConfig.guildId) as Guild | null; + const guild = client.guilds.resolve(constantsConfig.guildId); if (!guild) { Logger.error('BirthdayHandler - Guild not found.'); return; @@ -47,7 +46,7 @@ export async function postBirthdays(job: Job) { // Get all threads (archived included) await channel.threads.fetch({ archived: {} }); - const thread = channel.threads.cache.find((t) => t.id === constantsConfig.threads.BIRTHDAY_THREAD) as ThreadChannel | null; + const thread = channel.threads.cache.find((t) => t.id === constantsConfig.threads.BIRTHDAY_THREAD); if (!thread) { Logger.error('Birthday handler - Thread not found'); return; @@ -85,8 +84,7 @@ export async function postBirthdays(job: Job) { for (const birthday of birthdays) { let user; try { - // eslint-disable-next-line no-await-in-loop - user = await guild.members.fetch(birthday.userID!); + user = await guild.members.fetch(birthday.userID); } catch (error) { Logger.error('BirthdayHandler - Failed to fetch user', error); } @@ -106,7 +104,9 @@ export async function postBirthdays(job: Job) { }); // Update birthday to next year - const nextBirthdayDatetime = new Date(Date.UTC(currentDate.getUTCFullYear() + 1, birthday.month! - 1, birthday.day!)); + const nextBirthdayDatetime = new Date( + Date.UTC(currentDate.getUTCFullYear() + 1, birthday.month! - 1, birthday.day), + ); nextBirthdayDatetime.setUTCHours(10 - birthday.timezone!); birthday.utcDatetime = nextBirthdayDatetime; try { diff --git a/src/lib/schedulerJobs/sendHeartbeat.ts b/src/lib/schedulerJobs/sendHeartbeat.ts index 8aa36286..a5dbb3fb 100644 --- a/src/lib/schedulerJobs/sendHeartbeat.ts +++ b/src/lib/schedulerJobs/sendHeartbeat.ts @@ -9,7 +9,7 @@ export async function sendHeartbeat(job: Job) { } // Needed because of https://github.com/agenda/agenda/issues/401 - // eslint-disable-next-line no-underscore-dangle + const matchingJobs = await scheduler.jobs({ _id: job.attrs._id }); if (matchingJobs.length !== 1) { Logger.debug('Job has been deleted already, skipping execution.'); diff --git a/src/lib/slashCommand.ts b/src/lib/slashCommand.ts index 9184c8f3..a30019c7 100644 --- a/src/lib/slashCommand.ts +++ b/src/lib/slashCommand.ts @@ -1,34 +1,43 @@ -import type { Awaitable, Client, ChatInputCommandInteraction, SlashCommandBuilder, SlashCommandSubcommandsOnlyBuilder, RESTPostAPIApplicationCommandsJSONBody } from 'discord.js'; +import type { + Awaitable, + Client, + ChatInputCommandInteraction, + SlashCommandBuilder, + SlashCommandSubcommandsOnlyBuilder, + RESTPostAPIApplicationCommandsJSONBody, +} from 'discord.js'; import { LogMethods, AutocompleteCallback } from './index'; /// Props that will be passed through the command callback. export interface SlashCommandProps { - interaction: ChatInputCommandInteraction<'cached'>, - client: Client, - log: LogMethods, + interaction: ChatInputCommandInteraction<'cached'>; + client: Client; + log: LogMethods; } export type SlashCommandCallback = (props: SlashCommandProps) => Awaitable; /// Command structure for slash commands -export type SlashCommandStructure = - | SlashCommandBuilder & { category?: string } - | SlashCommandSubcommandsOnlyBuilder & { category?: string } - | Omit & { category?: string } - | RESTPostAPIApplicationCommandsJSONBody & { category?: string }; +export type SlashCommandStructure = SlashCommandBuilder & { category?: string }; /// Internal structure that represents a command and its callback. export interface SlashCommand { - meta: SlashCommandStructure, - callback: SlashCommandCallback, - autocompleteCallback?: AutocompleteCallback, + meta: SlashCommandStructure; + callback: SlashCommandCallback; + autocompleteCallback?: AutocompleteCallback; } /// Function to provide data for slash commands -export function slashCommandStructure(data: RESTPostAPIApplicationCommandsJSONBody & { category?: string }): SlashCommandStructure { +export function slashCommandStructure( + data: RESTPostAPIApplicationCommandsJSONBody & { category?: string }, +): SlashCommandStructure { return data; } /// Creates command structure -export function slashCommand(meta: SlashCommandStructure, callback: SlashCommandCallback, autocompleteCallback?: AutocompleteCallback): SlashCommand { +export function slashCommand( + meta: SlashCommandStructure, + callback: SlashCommandCallback, + autocompleteCallback?: AutocompleteCallback, +): SlashCommand { return { meta, callback, autocompleteCallback }; } diff --git a/src/scripts/deployCommands.ts b/src/scripts/deployCommands.ts index d350c027..2de43807 100644 --- a/src/scripts/deployCommands.ts +++ b/src/scripts/deployCommands.ts @@ -12,15 +12,13 @@ if (!process.env.BOT_SECRET) { const rest = new REST({ version: '10' }).setToken(process.env.BOT_SECRET); export async function deployCommands(commandArray: any[], contextArray: any[]) { - const body = [ - ...commandArray.map((cmd) => cmd.meta), - ...contextArray.map((ctx) => ctx.meta), - ]; - const currentUser = await rest.get(Routes.user()) as APIUser; + const body = [...commandArray.map((cmd) => cmd.meta), ...contextArray.map((ctx) => ctx.meta)]; + const currentUser = (await rest.get(Routes.user())) as APIUser; - const endpoint = process.env.NODE_ENV === 'production' - ? Routes.applicationCommands(currentUser.id) - : Routes.applicationGuildCommands(currentUser.id, constantsConfig.guildId); + const endpoint = + process.env.NODE_ENV === 'production' + ? Routes.applicationCommands(currentUser.id) + : Routes.applicationGuildCommands(currentUser.id, constantsConfig.guildId); await rest.put(endpoint, { body }); From dbfee06ecea0b8a3d60ba55acec528c04c00b2f1 Mon Sep 17 00:00:00 2001 From: ExampleWasTaken <58574351+ExampleWasTaken@users.noreply.github.com> Date: Mon, 17 Jun 2024 20:31:26 +0200 Subject: [PATCH 05/82] Revert "eslint --fix including prettier write" This reverts commit 0adefb7b263386e122d4def3c11fb6affd886e00. --- src/client.ts | 9 +- src/commands/context/index.ts | 6 +- src/commands/context/message/reportMessage.ts | 119 +++++------ src/commands/context/user/userInfo.ts | 6 +- src/commands/moderation/cacheUpdate.ts | 61 +++--- src/commands/moderation/clearMessages.ts | 37 +--- src/commands/moderation/commandTable.ts | 14 +- src/commands/moderation/deployCommands.ts | 43 ++-- src/commands/moderation/faq/faq.ts | 28 +-- .../moderation/faq/functions/addFaq.ts | 101 +++++----- .../moderation/faq/functions/faqPrintAll.ts | 4 +- .../moderation/faq/functions/listFaq.ts | 43 ++-- .../moderation/faq/functions/removeFaq.ts | 54 ++--- .../moderation/infractions/functions/ban.ts | 160 +++++++-------- .../functions/deleteInfractions.ts | 61 +++--- .../infractions/functions/listInfractions.ts | 123 ++++++------ .../infractions/functions/removeTimeout.ts | 80 ++++---- .../infractions/functions/timeout.ts | 189 ++++++++--------- .../infractions/functions/unbanInfractions.ts | 78 ++++--- .../infractions/functions/userNote.ts | 70 ++++--- .../moderation/infractions/functions/warn.ts | 139 ++++++------- .../moderation/infractions/infractions.ts | 54 ++--- src/commands/moderation/listRoleUsers.ts | 29 +-- src/commands/moderation/roleAssignment.ts | 14 +- src/commands/moderation/rules.ts | 6 +- .../moderation/slowmode/functions/disable.ts | 32 +-- .../moderation/slowmode/functions/set.ts | 39 +--- src/commands/moderation/slowmode/slowmode.ts | 98 +++------ src/commands/moderation/welcome.ts | 5 +- src/commands/moderation/whois.ts | 20 +- src/commands/utils/avatar.ts | 16 +- src/commands/utils/birthday/birthday.ts | 22 +- .../utils/birthday/functions/listBirthday.ts | 19 +- .../birthday/functions/removeBirthday.ts | 20 +- .../utils/birthday/functions/setBirthday.ts | 9 +- src/commands/utils/count.ts | 4 +- src/commands/utils/docSearch.ts | 20 +- .../github/functions/githubPullRequest.ts | 4 +- .../github/functions/handleGithubIssue.ts | 4 +- src/commands/utils/github/github.ts | 66 +++--- src/commands/utils/help.ts | 93 +++++---- .../locate/functions/filterSearchResults.ts | 4 +- .../utils/locate/functions/handleCommand.ts | 23 +-- src/commands/utils/locate/locate.ts | 40 ++-- .../utils/locate/panels/a32nx/a32nx-panels.ts | 70 +------ .../utils/locate/panels/a32nx/flyPad.ts | 6 +- .../utils/locate/panels/a32nx/front-panel.ts | 39 +++- .../utils/locate/panels/a32nx/glareshield.ts | 6 +- .../utils/locate/panels/a32nx/overhead.ts | 137 +++++++++++-- .../utils/locate/panels/a32nx/pedestal.ts | 79 ++++++-- .../locate/panels/a32nx/rear-cb-panel.ts | 5 +- src/commands/utils/metar.ts | 25 +-- src/commands/utils/ping.ts | 16 +- src/commands/utils/reportedIssues.ts | 50 ++--- src/commands/utils/roleInfo.ts | 16 +- src/commands/utils/searchFaq.ts | 29 ++- src/commands/utils/simbriefData.ts | 68 +++---- src/commands/utils/station.ts | 27 +-- src/commands/utils/taf.ts | 22 +- .../vatsim/functions/vatsimControllers.ts | 72 +++---- .../utils/vatsim/functions/vatsimEvents.ts | 102 +++++----- .../utils/vatsim/functions/vatsimObservers.ts | 69 +++---- .../utils/vatsim/functions/vatsimPilots.ts | 46 ++--- .../utils/vatsim/functions/vatsimStats.ts | 99 ++++----- src/commands/utils/vatsim/vatsim.ts | 51 +++-- src/commands/utils/wolframAlpha.ts | 25 ++- src/commands/utils/zulu.ts | 27 +-- src/events/buttonHandlers/buttonHandler.ts | 28 ++- .../functions/handleRoleAssignment.ts | 7 +- src/events/contextInteractionHandler.ts | 8 +- src/events/logging/detectBan.ts | 190 +++++++++--------- src/events/logging/messageDelete.ts | 17 +- src/events/logging/messageUpdate.ts | 22 +- src/events/logging/scamLogs.ts | 18 +- src/events/ready.ts | 43 ++-- src/events/slashCommandHandler.ts | 8 +- src/lib/config.ts | 94 ++++----- src/lib/contextMenuCommand.ts | 12 +- src/lib/durationInEnglish.ts | 6 +- src/lib/embed.ts | 12 +- src/lib/events.ts | 6 +- src/lib/genericEmbedPagination.ts | 33 +-- src/lib/infractionEmbedPagination.ts | 47 +---- src/lib/logger.ts | 4 +- src/lib/replies.ts | 12 +- src/lib/schedulerJobs/autoDisableSlowMode.ts | 87 ++++---- src/lib/schedulerJobs/postBirthdays.ts | 12 +- src/lib/schedulerJobs/sendHeartbeat.ts | 2 +- src/lib/slashCommand.ts | 37 ++-- src/scripts/deployCommands.ts | 14 +- 90 files changed, 1772 insertions(+), 2099 deletions(-) diff --git a/src/client.ts b/src/client.ts index b1177f80..3801d69a 100644 --- a/src/client.ts +++ b/src/client.ts @@ -26,10 +26,11 @@ export const client = new Client({ registerEvents(client, Events); -client.login(process.env.BOT_SECRET).catch((e) => { - Logger.error(e); - process.exit(1); -}); +client.login(process.env.BOT_SECRET) + .catch((e) => { + Logger.error(e); + process.exit(1); + }); const handleTermination = async () => { Logger.info('Terminating bot...'); diff --git a/src/commands/context/index.ts b/src/commands/context/index.ts index d3e875a0..1346d3e3 100644 --- a/src/commands/context/index.ts +++ b/src/commands/context/index.ts @@ -3,6 +3,10 @@ import userInfo from './user/userInfo'; import reportMessage from './message/reportMessage'; import listInfractions from './user/listInfractions'; -const contextArray: ContextMenuCommand[] = [userInfo, reportMessage, listInfractions]; +const contextArray: ContextMenuCommand[] = [ + userInfo, + reportMessage, + listInfractions, +]; export default contextArray; diff --git a/src/commands/context/message/reportMessage.ts b/src/commands/context/message/reportMessage.ts index d0edead0..ef85cd0b 100644 --- a/src/commands/context/message/reportMessage.ts +++ b/src/commands/context/message/reportMessage.ts @@ -2,8 +2,7 @@ import { ActionRowBuilder, ApplicationCommandType, ContextMenuCommandInteraction, - ModalBuilder, - TextChannel, + ModalBuilder, TextChannel, TextInputBuilder, TextInputStyle, Colors, @@ -16,57 +15,52 @@ const data = contextMenuCommandStructure({ type: ApplicationCommandType.Message, }); -const reportedMessageEmbed = ( - targetMessage: any, - interaction: ContextMenuCommandInteraction<'cached'>, - messageContent: string, - commentContent: string, - formattedDate: string, -) => - makeEmbed({ - author: { - name: `[REPORTED MESSAGE] ${targetMessage.author.tag}`, - iconURL: targetMessage.author.displayAvatarURL(), +const reportedMessageEmbed = (targetMessage: any, interaction: ContextMenuCommandInteraction<'cached'>, messageContent: string, commentContent: string, formattedDate: string) => makeEmbed({ + author: { + name: `[REPORTED MESSAGE] ${targetMessage.author.tag}`, + iconURL: targetMessage.author.displayAvatarURL(), + }, + fields: [ + { + name: 'Reported by', + value: interaction.user.toString(), + inline: true, }, - fields: [ - { - name: 'Reported by', - value: interaction.user.toString(), - inline: true, - }, - { - name: 'Message Author', - value: targetMessage.author.toString(), - inline: true, - }, - { - name: 'Message Content', - value: messageContent, - inline: false, - }, - { - name: 'Link to Message', - value: targetMessage.url, - inline: false, - }, - { - name: 'Additional Comments', - value: commentContent, - inline: false, - }, - { - name: 'Reported at', - value: formattedDate, - inline: false, - }, - ], - color: Colors.Red, - footer: { text: `Reported Users ID: ${targetMessage.author.id}` }, - }); + { + name: 'Message Author', + value: targetMessage.author.toString(), + inline: true, + }, + { + name: 'Message Content', + value: messageContent, + inline: false, + }, + { + name: 'Link to Message', + value: targetMessage.url, + inline: false, + }, + { + name: 'Additional Comments', + value: commentContent, + inline: false, + }, + { + name: 'Reported at', + value: formattedDate, + inline: false, + }, + ], + color: Colors.Red, + footer: { text: `Reported Users ID: ${targetMessage.author.id}` }, +}); export default contextMenuCommand(data, async ({ interaction }) => { const currentDate = new Date(); - const formattedDate: string = moment(currentDate).utcOffset(0).format(); + const formattedDate: string = moment(currentDate) + .utcOffset(0) + .format(); const scamReportLogs = interaction.guild.channels.resolve(constantsConfig.channels.SCAM_REPORT_LOGS) as TextChannel; const modRoleId = constantsConfig.roles.MODERATION_TEAM; @@ -132,8 +126,10 @@ export default contextMenuCommand(data, async ({ interaction }) => { //Modal sent - const filter = (interaction: { customId: string; user: { id: any } }) => - interaction.customId === 'reportMessageModal' && interaction.user.id; + const filter = (interaction: { + customId: string; + user: { id: any; }; + }) => interaction.customId === 'reportMessageModal' && interaction.user.id; let commentContent = 'No additional comments provided.'; @@ -164,10 +160,7 @@ export default contextMenuCommand(data, async ({ interaction }) => { //Send a follow-up message to the user if they are part of the staff role group - if ( - constantsConfig.roleGroups.SUPPORT && - constantsConfig.roleGroups.SUPPORT.some((role) => interaction.member.roles.cache.has(role)) - ) { + if (constantsConfig.roleGroups.SUPPORT && constantsConfig.roleGroups.SUPPORT.some((role) => interaction.member.roles.cache.has(role))) { await interaction.followUp({ content: `Is your report urgent and requires immediate attention from the <@&${modRoleId}>? If so please click yes and I will ping the <@&${modRoleId}>. If not, click no.`, components: [ @@ -193,7 +186,7 @@ export default contextMenuCommand(data, async ({ interaction }) => { }); try { - // Handle the button interactions + // Handle the button interactions const modPingButtonInteraction = await interaction.channel.awaitMessageComponent({ filter: (i) => i.customId === 'pingModerationTeamYes' || i.customId === 'pingModerationTeamNo', time: 60000, @@ -238,11 +231,7 @@ export default contextMenuCommand(data, async ({ interaction }) => { content: 'Unable to find the mod alerts channel. Please contact a Moderator.', ephemeral: true, }); - await scamReportLogs.send({ - embeds: [ - reportedMessageEmbed(targetMessage, interaction, messageContent, commentContent, formattedDate), - ], - }); + await scamReportLogs.send({ embeds: [reportedMessageEmbed(targetMessage, interaction, messageContent, commentContent, formattedDate)] }); return; } @@ -297,9 +286,7 @@ export default contextMenuCommand(data, async ({ interaction }) => { content: `Your report has been submitted and shared in ${modAlertsChannel}.`, ephemeral: true, }); - await scamReportLogs.send({ - content: `Reported message from ${interaction.user.toString()} has been shared in ${modAlertsChannel}.`, - }); + await scamReportLogs.send({ content: `Reported message from ${interaction.user.toString()} has been shared in ${modAlertsChannel}.` }); } if (shareReportButtonInteraction.customId === 'shareReportNo') { @@ -316,7 +303,5 @@ export default contextMenuCommand(data, async ({ interaction }) => { }); } } - await scamReportLogs.send({ - embeds: [reportedMessageEmbed(targetMessage, interaction, messageContent, commentContent, formattedDate)], - }); + await scamReportLogs.send({ embeds: [reportedMessageEmbed(targetMessage, interaction, messageContent, commentContent, formattedDate)] }); }); diff --git a/src/commands/context/user/userInfo.ts b/src/commands/context/user/userInfo.ts index d4e6c654..0d25a548 100644 --- a/src/commands/context/user/userInfo.ts +++ b/src/commands/context/user/userInfo.ts @@ -65,11 +65,7 @@ export default contextMenuCommand(data, async ({ interaction }) => { }, { name: 'Permissions', - value: targetMember.permissions - .toArray() - .join(', ') - .toLowerCase() - .replace(/_/g, ' ') + value: targetMember.permissions.toArray().join(', ').toLowerCase().replace(/_/g, ' ') .replace(/(^\w)|(\s+\w)/g, (char) => char.toUpperCase()), }, ], diff --git a/src/commands/moderation/cacheUpdate.ts b/src/commands/moderation/cacheUpdate.ts index caab4f9b..f16c3d72 100644 --- a/src/commands/moderation/cacheUpdate.ts +++ b/src/commands/moderation/cacheUpdate.ts @@ -31,26 +31,19 @@ const data = slashCommandStructure({ ], }); -const cacheUpdateEmbed = (action: string, fields: any, color: number) => - makeEmbed({ - title: `Cache Update - ${action}`, - fields, - color, - }); +const cacheUpdateEmbed = (action: string, fields: any, color: number) => makeEmbed({ + title: `Cache Update - ${action}`, + fields, + color, +}); -const noChannelEmbed = (action: string, channelName: string) => - makeEmbed({ - title: `Sticky Message - ${action} - No ${channelName} channel`, - description: `The command was successful, but no message to ${channelName} was sent. Please check the channel still exists.`, - color: Colors.Yellow, - }); +const noChannelEmbed = (action:string, channelName: string) => makeEmbed({ + title: `Sticky Message - ${action} - No ${channelName} channel`, + description: `The command was successful, but no message to ${channelName} was sent. Please check the channel still exists.`, + color: Colors.Yellow, +}); -const cacheUpdateEmbedField = ( - moderator: string, - cacheType: string, - cacheSize: string, - duration: string, -): EmbedField[] => [ +const cacheUpdateEmbedField = (moderator: string, cacheType: string, cacheSize: string, duration: string): EmbedField[] => [ { name: 'Type', value: cacheType, @@ -102,34 +95,26 @@ export default slashCommand(data, async ({ interaction }) => { if (cacheSize !== undefined) { await interaction.editReply({ - embeds: [ - cacheUpdateEmbed( + embeds: [cacheUpdateEmbed(interaction.options.getSubcommand(), + cacheUpdateEmbedField( + interaction.user.tag, interaction.options.getSubcommand(), - cacheUpdateEmbedField( - interaction.user.tag, - interaction.options.getSubcommand(), - cacheSize.toString(), - duration, - ), - Colors.Green, + cacheSize.toString(), + duration, ), - ], + Colors.Green)], }); try { await modLogsChannel.send({ - embeds: [ - cacheUpdateEmbed( + embeds: [cacheUpdateEmbed(interaction.options.getSubcommand(), + cacheUpdateEmbedField( + interaction.user.tag, interaction.options.getSubcommand(), - cacheUpdateEmbedField( - interaction.user.tag, - interaction.options.getSubcommand(), - cacheSize.toString(), - duration, - ), - Colors.Green, + cacheSize.toString(), + duration, ), - ], + Colors.Green)], }); } catch (error) { await interaction.followUp({ embeds: [noChannelEmbed(interaction.options.getSubcommand(), 'mod-log')] }); diff --git a/src/commands/moderation/clearMessages.ts b/src/commands/moderation/clearMessages.ts index 9b6c5e05..f5b34eca 100644 --- a/src/commands/moderation/clearMessages.ts +++ b/src/commands/moderation/clearMessages.ts @@ -1,13 +1,4 @@ -import { - ApplicationCommandOptionType, - ApplicationCommandType, - TextChannel, - Colors, - ActionRowBuilder, - ButtonBuilder, - ButtonStyle, - Interaction, -} from 'discord.js'; +import { ApplicationCommandOptionType, ApplicationCommandType, TextChannel, Colors, ActionRowBuilder, ButtonBuilder, ButtonStyle, Interaction } from 'discord.js'; import { slashCommand, slashCommandStructure, makeEmbed, constantsConfig, Logger } from '../../lib'; const data = slashCommandStructure({ @@ -16,16 +7,14 @@ const data = slashCommandStructure({ type: ApplicationCommandType.ChatInput, default_member_permissions: constantsConfig.commandPermission.MANAGE_SERVER, //Overrides need to be added for admin and moderator roles dm_permission: false, - options: [ - { - name: 'amount', - description: 'Number of messages to clear (1-100).', - type: ApplicationCommandOptionType.Integer, - required: true, - min_value: 1, - max_value: 100, - }, - ], + options: [{ + name: 'amount', + description: 'Number of messages to clear (1-100).', + type: ApplicationCommandOptionType.Integer, + required: true, + min_value: 1, + max_value: 100, + }], }); export default slashCommand(data, async ({ interaction }) => { @@ -79,9 +68,7 @@ export default slashCommand(data, async ({ interaction }) => { timestamp: new Date(), }); - const modLogsChannel = interaction.guild.channels.resolve( - constantsConfig.channels.MOD_LOGS, - ) as TextChannel; + const modLogsChannel = interaction.guild.channels.resolve(constantsConfig.channels.MOD_LOGS) as TextChannel; const modLogEmbed = makeEmbed({ title: '🧹 Messages Cleared', description: 'Messages have been cleared.', @@ -111,9 +98,7 @@ export default slashCommand(data, async ({ interaction }) => { return interaction.editReply({ content: '', embeds: [replyEmbed], components: [] }); } catch (error) { Logger.error('Error clearing messages:', error); - return interaction.editReply({ - content: 'There was an error trying to clear messages in this channel. The error has been logged.', - }); + return interaction.editReply({ content: 'There was an error trying to clear messages in this channel. The error has been logged.' }); } } else { const canceledEmbed = makeEmbed({ diff --git a/src/commands/moderation/commandTable.ts b/src/commands/moderation/commandTable.ts index 66ee5f0f..8c98eb4c 100644 --- a/src/commands/moderation/commandTable.ts +++ b/src/commands/moderation/commandTable.ts @@ -42,11 +42,7 @@ export default slashCommand(data, async ({ interaction }: { interaction: Command // eslint-disable-next-line prefer-const let { name, description, type } = command; - const subcommandList = command.options?.filter( - (option) => - option.type === ApplicationCommandOptionType.Subcommand || - option.type === ApplicationCommandOptionType.SubcommandGroup, - ); + const subcommandList = command.options?.filter((option) => option.type === ApplicationCommandOptionType.Subcommand || option.type === ApplicationCommandOptionType.SubcommandGroup); let subcommandDescription = ''; @@ -57,11 +53,11 @@ export default slashCommand(data, async ({ interaction }: { interaction: Command return subcommand.name; } if (subcommand.type === ApplicationCommandOptionType.SubcommandGroup) { - const groupSubcommands = subcommand.options?.filter( - (sub) => sub.type === ApplicationCommandOptionType.Subcommand, - ); + const groupSubcommands = subcommand.options?.filter((sub) => sub.type === ApplicationCommandOptionType.Subcommand); if (groupSubcommands && groupSubcommands.length > 0) { - return `${subcommand.name} [${groupSubcommands.map((sub) => sub.name).join(', ')}]`; + return `${subcommand.name} [${groupSubcommands + .map((sub) => sub.name) + .join(', ')}]`; } return `${subcommand.name} [None]`; } diff --git a/src/commands/moderation/deployCommands.ts b/src/commands/moderation/deployCommands.ts index f7b59a8b..45da2ba4 100644 --- a/src/commands/moderation/deployCommands.ts +++ b/src/commands/moderation/deployCommands.ts @@ -16,37 +16,36 @@ const data = slashCommandStructure({ export default slashCommand(data, async ({ interaction }) => { if (interaction.guild) { try { - await deployCommands(commandArray, contextArray).then(async (user) => { - const bot = `<@${user.id}>`; + await deployCommands(commandArray, contextArray) + .then(async (user) => { + const bot = `<@${user.id}>`; - const guildID = constantsConfig.guildId; - if (!guildID) { - await interaction.reply('guildId configuration constant is not defined.'); - return; - } + const guildID = constantsConfig.guildId; + if (!guildID) { + await interaction.reply('guildId configuration constant is not defined.'); + return; + } - const guildName = client.guilds.cache.get(guildID); + const guildName = client.guilds.cache.get(guildID); - let response; - //If the bot is deployed to a guild and can resolve the name, use the guild name in the response - if (guildName) { - response = - process.env.NODE_ENV === 'production' + let response; + //If the bot is deployed to a guild and can resolve the name, use the guild name in the response + if (guildName) { + response = process.env.NODE_ENV === 'production' ? `Deployed ${commandArray.length} commands and ${contextArray.length} contexts globally as ${bot}!` : `Deployed ${commandArray.length} commands and ${contextArray.length} contexts to \`${guildName}\` as ${bot}!`; - } else { + } else { //If the bot can't gather the guild name, use the ID in the response - response = - process.env.NODE_ENV === 'production' + response = process.env.NODE_ENV === 'production' ? `Deployed ${commandArray.length} commands and ${contextArray.length} contexts globally as ${bot}!` : `Deployed ${commandArray.length} commands and ${contextArray.length} contexts to \`<@${guildID}>\` as ${bot}!`; - } - Logger.info(response); - await interaction.reply({ - content: response, - ephemeral: true, + } + Logger.info(response); + await interaction.reply({ + content: response, + ephemeral: true, + }); }); - }); } catch (error) { await interaction.reply({ content: 'Failed to deploy commands!', diff --git a/src/commands/moderation/faq/faq.ts b/src/commands/moderation/faq/faq.ts index f003ddb1..cccc208f 100644 --- a/src/commands/moderation/faq/faq.ts +++ b/src/commands/moderation/faq/faq.ts @@ -63,20 +63,20 @@ export default slashCommand(data, async ({ interaction }) => { const modLogsChannel = interaction.guild.channels.resolve(constantsConfig.channels.MOD_LOGS) as TextChannel; switch (subcommandName) { - case 'add': - await handleAddFaq(interaction, modLogsChannel); - break; - case 'remove': - await handleRemoveFaq(interaction, faqID, modLogsChannel); - break; - case 'list': - await handleListFaq(interaction); - break; - case 'print-all': - await handlePrintAllFAQ(interaction); - break; + case 'add': + await handleAddFaq(interaction, modLogsChannel); + break; + case 'remove': + await handleRemoveFaq(interaction, faqID, modLogsChannel); + break; + case 'list': + await handleListFaq(interaction); + break; + case 'print-all': + await handlePrintAllFAQ(interaction); + break; - default: - await interaction.reply({ content: 'Unknown subcommand', ephemeral: true }); + default: + await interaction.reply({ content: 'Unknown subcommand', ephemeral: true }); } }); diff --git a/src/commands/moderation/faq/functions/addFaq.ts b/src/commands/moderation/faq/functions/addFaq.ts index bd6d3274..72fa12ec 100644 --- a/src/commands/moderation/faq/functions/addFaq.ts +++ b/src/commands/moderation/faq/functions/addFaq.ts @@ -10,26 +10,25 @@ import { } from 'discord.js'; import { Logger, makeEmbed, FAQ } from '../../../../lib'; -const faqAddedEmbed = (discordUser: User, question: string, answer: string) => - makeEmbed({ - author: { - name: `[FAQ Added] ${discordUser.tag}`, - iconURL: discordUser.displayAvatarURL(), +const faqAddedEmbed = (discordUser: User, question: string, answer: string) => makeEmbed({ + author: { + name: `[FAQ Added] ${discordUser.tag}`, + iconURL: discordUser.displayAvatarURL(), + }, + fields: [ + { + inline: false, + name: 'Question', + value: question, }, - fields: [ - { - inline: false, - name: 'Question', - value: question, - }, - { - inline: false, - name: 'Answer', - value: answer, - }, - ], - color: Colors.Green, - }); + { + inline: false, + name: 'Answer', + value: answer, + }, + ], + color: Colors.Green, +}); export async function handleAddFaq(interaction: ChatInputCommandInteraction<'cached'>, modLogsChannel: TextChannel) { const modal = new ModalBuilder({ @@ -37,23 +36,27 @@ export async function handleAddFaq(interaction: ChatInputCommandInteraction<'cac title: 'Add an FAQ entry', }); - const faqTitleInput = new TextInputBuilder({ - customId: 'faqTitleInput', - label: 'Title', - placeholder: 'Please enter the title of the FAQ.', - style: TextInputStyle.Short, - maxLength: 500, - required: true, - }); - - const faqAnswerInput = new TextInputBuilder({ - customId: 'faqAnswerInput', - label: 'Answer', - placeholder: 'If you wish to mention a role or channel use <@&*ID*> or <#*ID*> respectively.', - style: TextInputStyle.Paragraph, - maxLength: 1000, - required: true, - }); + const faqTitleInput = new TextInputBuilder( + { + customId: 'faqTitleInput', + label: 'Title', + placeholder: 'Please enter the title of the FAQ.', + style: TextInputStyle.Short, + maxLength: 500, + required: true, + }, + ); + + const faqAnswerInput = new TextInputBuilder( + { + customId: 'faqAnswerInput', + label: 'Answer', + placeholder: 'If you wish to mention a role or channel use <@&*ID*> or <#*ID*> respectively.', + style: TextInputStyle.Paragraph, + maxLength: 1000, + required: true, + }, + ); const titleActionRow = new ActionRowBuilder().addComponents(faqTitleInput); const answerActionRow = new ActionRowBuilder().addComponents(faqAnswerInput); @@ -64,8 +67,10 @@ export async function handleAddFaq(interaction: ChatInputCommandInteraction<'cac //Modal sent - const filter = (interaction: { customId: string; user: { id: any } }) => - interaction.customId === 'faqAddModal' && interaction.user.id; + const filter = (interaction: { + customId: string; + user: { id: any; }; + }) => interaction.customId === 'faqAddModal' && interaction.user.id; try { //Await a modal response @@ -90,16 +95,13 @@ export async function handleAddFaq(interaction: ChatInputCommandInteraction<'cac if (!faqData) { faqData = new FAQ({ - faqTitle: faqTitle, - faqAnswer: faqAnswer, + faqTitle: faqTitle!, + faqAnswer: faqAnswer!, moderatorID: discordUser.id, dateSet: currentDate, }); } else { - await interaction.followUp({ - content: 'FAQ with this title already exists. Please choose another title', - ephemeral: true, - }); + await interaction.followUp({ content: 'FAQ with this title already exists. Please choose another title', ephemeral: true }); return; } @@ -107,10 +109,7 @@ export async function handleAddFaq(interaction: ChatInputCommandInteraction<'cac await faqData.save(); } catch (error) { Logger.error(error); - await interaction.followUp({ - content: 'Could not add FAQ, error has been logged, please notify the bot team.', - ephemeral: true, - }); + await interaction.followUp({ content: 'Could not add FAQ, error has been logged, please notify the bot team.', ephemeral: true }); return; } @@ -118,11 +117,7 @@ export async function handleAddFaq(interaction: ChatInputCommandInteraction<'cac await modLogsChannel.send({ embeds: [faqAddedEmbed(discordUser, faqTitle, faqAnswer)] }); } catch (error) { Logger.error(error); - await interaction.followUp({ - content: - 'FAQ added successfully, but could not send mod log, error has been logged, please notify the bot team.', - ephemeral: true, - }); + await interaction.followUp({ content: 'FAQ added successfully, but could not send mod log, error has been logged, please notify the bot team.', ephemeral: true }); return; } diff --git a/src/commands/moderation/faq/functions/faqPrintAll.ts b/src/commands/moderation/faq/functions/faqPrintAll.ts index 72394937..e9f573ea 100644 --- a/src/commands/moderation/faq/functions/faqPrintAll.ts +++ b/src/commands/moderation/faq/functions/faqPrintAll.ts @@ -34,8 +34,7 @@ export async function handlePrintAllFAQ(interaction: ChatInputCommandInteraction if (faqs.length === 0) { return interaction.followUp('No FAQs found.'); - } - if (interaction.channel) { + } if (interaction.channel) { await interaction.channel.send({ files: [FLIGHT_DECK_IMAGE_URL] }); // Divide the FAQs into sets of 5 @@ -56,6 +55,7 @@ export async function handlePrintAllFAQ(interaction: ChatInputCommandInteraction })), }); + // eslint-disable-next-line no-await-in-loop await interaction.channel.send({ embeds: [faqEmbed] }); } diff --git a/src/commands/moderation/faq/functions/listFaq.ts b/src/commands/moderation/faq/functions/listFaq.ts index b4098862..965d87dd 100644 --- a/src/commands/moderation/faq/functions/listFaq.ts +++ b/src/commands/moderation/faq/functions/listFaq.ts @@ -2,11 +2,10 @@ import { ChatInputCommandInteraction } from 'discord.js'; import moment from 'moment/moment'; import { Logger, makeEmbed, FAQ, createPaginatedEmbedHandler } from '../../../../lib'; -const faqListEmbed = (faqFields: { name: string; value: string }[], currentPage: number, totalPages: number) => - makeEmbed({ - title: `FAQ List (Page ${currentPage} of ${totalPages})`, - fields: faqFields, - }); +const faqListEmbed = (faqFields: { name: string; value: string; }[], currentPage: number, totalPages: number) => makeEmbed({ + title: `FAQ List (Page ${currentPage} of ${totalPages})`, + fields: faqFields, +}); export async function handleListFaq(interaction: ChatInputCommandInteraction<'cached'>) { try { @@ -21,19 +20,16 @@ export async function handleListFaq(interaction: ChatInputCommandInteraction<'ca const embeds = []; let currentPage = 1; let faqsAddedToPage = 0; - const faqFields: { name: string; value: string }[] = []; + const faqFields: { name: string; value: string; }[] = []; - const moderatorPromises = faqs.map((currentFaq) => - interaction.client.users - .fetch(currentFaq.moderatorID) - // Added for better readability - - .catch(() => { - return new Promise((resolve) => { - resolve(`I can't find the moderator, here is the stored ID: ${currentFaq.moderatorID}`); - }); - }), - ); + const moderatorPromises = faqs.map((currentFaq) => interaction.client.users.fetch(currentFaq.moderatorID!) + // Added for better readability + // eslint-disable-next-line arrow-body-style + .catch(() => { + return new Promise((resolve) => { + resolve(`I can't find the moderator, here is the stored ID: ${currentFaq.moderatorID}`); + }); + })); const moderatorUsers = await Promise.all(moderatorPromises); for (let i = 0; i < faqs.length; i++) { @@ -43,10 +39,10 @@ export async function handleListFaq(interaction: ChatInputCommandInteraction<'ca { name: `**Title:** ${faqs[i].faqTitle}`, value: - `**Answer:** ${faqs[i].faqAnswer}\n` + - `**Moderator:** ${moderatorUsers[i]}\n` + - `**Date Set:** ${formattedDate}\n` + - `**FAQ ID:** ${faqs[i].id}\n`, + `**Answer:** ${faqs[i].faqAnswer}\n` + + `**Moderator:** ${moderatorUsers[i]}\n` + + `**Date Set:** ${formattedDate}\n` + + `**FAQ ID:** ${faqs[i].id}\n`, }, { name: '', @@ -75,9 +71,6 @@ export async function handleListFaq(interaction: ChatInputCommandInteraction<'ca await createPaginatedEmbedHandler(interaction, embeds); } catch (error) { Logger.error(error); - await interaction.reply({ - content: 'Could not list FAQs, error has been logged, please notify the bot team.', - ephemeral: true, - }); + await interaction.reply({ content: 'Could not list FAQs, error has been logged, please notify the bot team.', ephemeral: true }); } } diff --git a/src/commands/moderation/faq/functions/removeFaq.ts b/src/commands/moderation/faq/functions/removeFaq.ts index 30b508fc..80fb2937 100644 --- a/src/commands/moderation/faq/functions/removeFaq.ts +++ b/src/commands/moderation/faq/functions/removeFaq.ts @@ -1,32 +1,27 @@ import { ChatInputCommandInteraction, Colors, TextChannel, User } from 'discord.js'; import { Logger, makeEmbed, FAQ } from '../../../../lib'; -const faqRemovedEmbed = (discordUser: User, faqQuestion: string, faqAnswer: string) => - makeEmbed({ - author: { - name: `[FAQ Removed] ${discordUser.tag}`, - iconURL: discordUser.displayAvatarURL(), +const faqRemovedEmbed = (discordUser: User, faqQuestion: string, faqAnswer: string) => makeEmbed({ + author: { + name: `[FAQ Removed] ${discordUser.tag}`, + iconURL: discordUser.displayAvatarURL(), + }, + fields: [ + { + inline: false, + name: 'Question', + value: faqQuestion, }, - fields: [ - { - inline: false, - name: 'Question', - value: faqQuestion, - }, - { - inline: false, - name: 'Answer', - value: faqAnswer, - }, - ], - color: Colors.Red, - }); + { + inline: false, + name: 'Answer', + value: faqAnswer, + }, + ], + color: Colors.Red, +}); -export async function handleRemoveFaq( - interaction: ChatInputCommandInteraction<'cached'>, - faqID: string, - modLogsChannel: TextChannel, -) { +export async function handleRemoveFaq(interaction: ChatInputCommandInteraction<'cached'>, faqID: string, modLogsChannel: TextChannel) { const discordUser = interaction.user; const faqEntry = await FAQ.findOne({ _id: faqID }); @@ -43,10 +38,7 @@ export async function handleRemoveFaq( await faqEntry.deleteOne(); } catch (error) { Logger.error(error); - await interaction.reply({ - content: 'Could not remove FAQ, error has been logged, please notify the bot team.', - ephemeral: true, - }); + await interaction.reply({ content: 'Could not remove FAQ, error has been logged, please notify the bot team.', ephemeral: true }); return; } @@ -54,11 +46,7 @@ export async function handleRemoveFaq( await modLogsChannel.send({ embeds: [faqRemovedEmbed(discordUser, faqTitle, faqAnswer)] }); } catch (error) { Logger.error(error); - await interaction.reply({ - content: - 'FAQ removed successfully, but could not send mod log, error has been logged, please notify the bot team.', - ephemeral: true, - }); + await interaction.reply({ content: 'FAQ removed successfully, but could not send mod log, error has been logged, please notify the bot team.', ephemeral: true }); return; } diff --git a/src/commands/moderation/infractions/functions/ban.ts b/src/commands/moderation/infractions/functions/ban.ts index 40c2eed6..e141df53 100644 --- a/src/commands/moderation/infractions/functions/ban.ts +++ b/src/commands/moderation/infractions/functions/ban.ts @@ -11,94 +11,82 @@ const noConnEmbed = makeEmbed({ const moderatableFailEmbed = makeEmbed({ color: Colors.Red, - description: "You can't ban a moderator!", + description: 'You can\'t ban a moderator!', }); -const failedBanEmbed = (discordUser: User) => - makeEmbed({ - title: 'Ban - Failed', - description: `Failed to Ban ${discordUser.toString()}`, - color: Colors.Red, - }); - -const DMEmbed = (moderator: User, banReason: string, guild: Guild) => - makeEmbed({ - title: `You have been banned from ${guild.name}`, - description: 'This ban is also logged against your record.', - fields: [ - { - inline: true, - name: 'Moderator', - value: moderator.toString(), - }, - { - inline: false, - name: 'Reason', - value: banReason, - }, - { - inline: false, - name: 'Appeal', - value: `If you would like to appeal your ban, please fill out [this form.](${process.env.BAN_APPEAL_URL})`, - }, - ], - }); - -const banEmbed = (discordUser: User) => - makeEmbed({ - title: `${discordUser.tag} was banned successfully`, - color: Colors.Green, - }); - -const DMFailed = (discordUser: User) => - makeEmbed({ - title: 'Ban - DM not sent', - description: `DM was not sent to ${discordUser.toString()}, they either have DMs closed or share no mutual servers with the bot.`, - color: Colors.Red, - }); - -const modLogEmbed = ( - moderator: User, - discordUser: User, - banReason: string, - daysDeletedNumber: number, - formattedDate: string, -) => - makeEmbed({ - author: { - name: `[BANNED] ${discordUser.tag}`, - iconURL: discordUser.displayAvatarURL(), +const failedBanEmbed = (discordUser: User) => makeEmbed({ + title: 'Ban - Failed', + description: `Failed to Ban ${discordUser.toString()}`, + color: Colors.Red, +}); + +const DMEmbed = (moderator: User, banReason: string, guild: Guild) => makeEmbed({ + title: `You have been banned from ${guild.name}`, + description: 'This ban is also logged against your record.', + fields: [ + { + inline: true, + name: 'Moderator', + value: moderator.toString(), + }, + { + inline: false, + name: 'Reason', + value: banReason, + }, + { + inline: false, + name: 'Appeal', + value: `If you would like to appeal your ban, please fill out [this form.](${process.env.BAN_APPEAL_URL})`, }, - fields: [ - { - name: 'User', - value: discordUser.toString(), - }, - { - name: 'Moderator', - value: `${moderator}`, - }, - { - name: 'Reason', - value: `\u200B${banReason}`, - }, - { - name: 'Days of messages deleted', - value: daysDeletedNumber.toString(), - }, - { - name: 'Date', - value: formattedDate, - }, - ], - footer: { text: `User ID: ${discordUser.id}` }, - color: Colors.Red, - }); + ], +}); + +const banEmbed = (discordUser: User) => makeEmbed({ + title: `${discordUser.tag} was banned successfully`, + color: Colors.Green, +}); + +const DMFailed = (discordUser: User) => makeEmbed({ + title: 'Ban - DM not sent', + description: `DM was not sent to ${discordUser.toString()}, they either have DMs closed or share no mutual servers with the bot.`, + color: Colors.Red, +}); + +const modLogEmbed = (moderator: User, discordUser: User, banReason: string, daysDeletedNumber: number, formattedDate: string) => makeEmbed({ + author: { + name: `[BANNED] ${discordUser.tag}`, + iconURL: discordUser.displayAvatarURL(), + }, + fields: [ + { + name: 'User', + value: discordUser.toString(), + }, + { + name: 'Moderator', + value: `${moderator}`, + }, + { + name: 'Reason', + value: `\u200B${banReason}`, + }, + { + name: 'Days of messages deleted', + value: daysDeletedNumber.toString(), + }, + { + name: 'Date', + value: formattedDate, + }, + ], + footer: { text: `User ID: ${discordUser.id}` }, + color: Colors.Red, +}); const noModLogs = makeEmbed({ title: 'Ban - No Mod Log', - description: - "I can't find the mod logs channel. I will still try to ban the user. Please check the channel still exists.", + description: 'I can\'t find the mod logs channel. I will still try to ban the user. Please check the channel still exists.', color: Colors.Red, }); @@ -124,7 +112,9 @@ export async function handleBanInfraction(interaction: ChatInputCommandInteracti const discordUser = await interaction.guild.members.fetch(userID); const moderator = interaction.user; const currentDate = new Date(); - const formattedDate: string = moment(currentDate).utcOffset(0).format(); + const formattedDate: string = moment(currentDate) + .utcOffset(0) + .format(); const modLogsChannel = interaction.guild.channels.resolve(constantsConfig.channels.MOD_LOGS) as TextChannel; //Check if the user is a moderator @@ -155,9 +145,7 @@ export async function handleBanInfraction(interaction: ChatInputCommandInteracti try { await interaction.guild.members.ban(discordUser, { deleteMessageDays: daysDeletedNumber, reason: banReason }); if (modLogsChannel) { - await modLogsChannel.send({ - embeds: [modLogEmbed(moderator, discordUser.user, banReason, daysDeletedNumber, formattedDate)], - }); + await modLogsChannel.send({ embeds: [modLogEmbed(moderator, discordUser.user, banReason, daysDeletedNumber, formattedDate)] }); } await interaction.followUp({ embeds: [banEmbed(discordUser.user)], ephemeral: true }); } catch (error) { diff --git a/src/commands/moderation/infractions/functions/deleteInfractions.ts b/src/commands/moderation/infractions/functions/deleteInfractions.ts index 388d237b..d2bd7539 100644 --- a/src/commands/moderation/infractions/functions/deleteInfractions.ts +++ b/src/commands/moderation/infractions/functions/deleteInfractions.ts @@ -31,36 +31,35 @@ const errorEmbed = makeEmbed({ color: Colors.Red, }); -const modLogEmbed = (moderator: string, discordUser: User, infractionType: string, infractionReason: string) => - makeEmbed({ - author: { - name: `[INFRACTION DELETE] ${discordUser.tag}`, - iconURL: discordUser.displayAvatarURL(), +const modLogEmbed = (moderator: string, discordUser: User, infractionType: string, infractionReason: string) => makeEmbed({ + author: { + name: `[INFRACTION DELETE] ${discordUser.tag}`, + iconURL: discordUser.displayAvatarURL(), + }, + fields: [ + { + inline: false, + name: 'Deleted by:', + value: moderator, }, - fields: [ - { - inline: false, - name: 'Deleted by:', - value: moderator, - }, - { - inline: false, - name: 'Infraction user:', - value: discordUser.toString(), - }, - { - inline: false, - name: 'Infraction type:', - value: infractionType, - }, - { - inline: false, - name: 'Reason', - value: infractionReason, - }, - ], - color: Colors.Green, - }); + { + inline: false, + name: 'Infraction user:', + value: discordUser.toString(), + }, + { + inline: false, + name: 'Infraction type:', + value: infractionType, + }, + { + inline: false, + name: 'Reason', + value: infractionReason, + }, + ], + color: Colors.Green, +}); export async function handleDeleteInfraction(interaction: ChatInputCommandInteraction<'cached'>) { const conn = getConn(); @@ -106,9 +105,7 @@ export async function handleDeleteInfraction(interaction: ChatInputCommandIntera const modLogsChannel = interaction.guild.channels.resolve(constantsConfig.channels.MOD_LOGS) as TextChannel; if (modLogsChannel) { - await modLogsChannel.send({ - embeds: [modLogEmbed(interaction.user.toString(), discordUser, infractionType, infractionReason)], - }); + await modLogsChannel.send({ embeds: [modLogEmbed(interaction.user.toString(), discordUser, infractionType, infractionReason)] }); } } catch (error) { await interaction.reply({ embeds: [errorEmbed], ephemeral: true }); diff --git a/src/commands/moderation/infractions/functions/listInfractions.ts b/src/commands/moderation/infractions/functions/listInfractions.ts index 794c6fc8..52820386 100644 --- a/src/commands/moderation/infractions/functions/listInfractions.ts +++ b/src/commands/moderation/infractions/functions/listInfractions.ts @@ -8,11 +8,7 @@ const noConnEmbed = makeEmbed({ color: Colors.Red, }); -export async function handleListInfraction( - interaction: CommandInteraction, - userID: string | undefined, - ephemeral = false, -) { +export async function handleListInfraction(interaction: CommandInteraction, userID: string | undefined, ephemeral = false) { const conn = getConn(); if (!conn) { @@ -67,20 +63,22 @@ export async function handleListInfraction( notesLength: userNotes.length.toString(), }; - type InfractionArray = typeof warnInfractions; + type InfractionArray = typeof warnInfractions + | typeof timeoutInfractions + | typeof scamLogInfractions + | typeof banInfractions + | typeof unbanInfractions + | typeof userNotes; const fetchModerators = (infractions: InfractionArray) => { - const moderatorPromises = infractions.map((infraction) => - interaction.client.users - .fetch(infraction.moderatorID) - // Disabled for readability - - .catch(() => { - return new Promise((resolve) => { - resolve(`I can't find the moderator, here is the stored ID: ${infraction.moderatorID}`); - }); - }), - ); + const moderatorPromises = infractions.map((infraction) => interaction.client.users.fetch(infraction.moderatorID!) + // Disabled for readability + // eslint-disable-next-line arrow-body-style + .catch(() => { + return new Promise((resolve) => { + resolve(`I can't find the moderator, here is the stored ID: ${infraction.moderatorID}`); + }); + })); return Promise.all(moderatorPromises); }; @@ -90,17 +88,19 @@ export async function handleListInfraction( const warnModeratorUsers = await fetchModerators(warnInfractions); for (let i = 0; i < warnInfractions.length; i++) { - const formattedDate: string = moment(warnInfractions[i].date).utcOffset(0).format(); + const formattedDate: string = moment(warnInfractions[i].date) + .utcOffset(0) + .format(); warnFields.push( { name: `Warn #${i + 1}`, value: - `**Type:** ${warnInfractions[i].infractionType}\n` + - `**Moderator:** ${warnModeratorUsers[i]}\n` + - `**Reason:** ${warnInfractions[i].reason}\n` + - `**Date:** ${formattedDate}\n` + - `**Infraction ID:** ${warnInfractions[i].infractionID}`, + `**Type:** ${warnInfractions[i].infractionType}\n` + + `**Moderator:** ${warnModeratorUsers[i]}\n` + + `**Reason:** ${warnInfractions[i].reason}\n` + + `**Date:** ${formattedDate}\n` + + `**Infraction ID:** ${warnInfractions[i].infractionID}`, }, { name: '', @@ -124,18 +124,20 @@ export async function handleListInfraction( const timeoutModeratorUsers = await fetchModerators(timeoutInfractions); for (let i = 0; i < timeoutInfractions.length; i++) { - const formattedDate: string = moment(timeoutInfractions[i].date).utcOffset(0).format(); + const formattedDate: string = moment(timeoutInfractions[i].date) + .utcOffset(0) + .format(); timeoutFields.push( { name: `Timeout #${i + 1}`, value: - `**Type:** ${timeoutInfractions[i].infractionType}\n` + - `**Moderator:** ${timeoutModeratorUsers[i]}\n` + - `**Reason:** ${timeoutInfractions[i].reason}\n` + - `**Duration:** ${timeoutInfractions[i].duration !== undefined ? timeoutInfractions[i].duration : 'No duration specified, this user was timed out before the bot upgrade!'}\n` + - `**Date:** ${formattedDate}\n` + - `**Infraction ID:** ${timeoutInfractions[i].infractionID}`, + `**Type:** ${timeoutInfractions[i].infractionType}\n` + + `**Moderator:** ${timeoutModeratorUsers[i]}\n` + + `**Reason:** ${timeoutInfractions[i].reason}\n` + + `**Duration:** ${timeoutInfractions[i].duration !== undefined ? timeoutInfractions[i].duration : 'No duration specified, this user was timed out before the bot upgrade!'}\n` + + `**Date:** ${formattedDate}\n` + + `**Infraction ID:** ${timeoutInfractions[i].infractionID}`, }, { name: '', @@ -159,17 +161,19 @@ export async function handleListInfraction( const scamLogModerators = await fetchModerators(scamLogInfractions); for (let i = 0; i < scamLogInfractions.length; i++) { - const formattedDate: string = moment(scamLogInfractions[i].date).utcOffset(0).format(); + const formattedDate: string = moment(scamLogInfractions[i].date) + .utcOffset(0) + .format(); scamLogFields.push( { name: `Scam Log #${i + 1}`, value: - `**Type:** ${scamLogInfractions[i].infractionType}\n` + - `**Moderator:** ${scamLogModerators[i]}\n` + - `**Message Content:** ${scamLogInfractions[i].reason}\n` + - `**Date:** ${formattedDate}\n` + - `**Infraction ID:** ${scamLogInfractions[i].infractionID}`, + `**Type:** ${scamLogInfractions[i].infractionType}\n` + + `**Moderator:** ${scamLogModerators[i]}\n` + + `**Message Content:** ${scamLogInfractions[i].reason}\n` + + `**Date:** ${formattedDate}\n` + + `**Infraction ID:** ${scamLogInfractions[i].infractionID}`, }, { name: '', @@ -193,17 +197,19 @@ export async function handleListInfraction( const banModerators = await fetchModerators(banInfractions); for (let i = 0; i < banInfractions.length; i++) { - const formattedDate: string = moment(banInfractions[i].date).utcOffset(0).format(); + const formattedDate: string = moment(banInfractions[i].date) + .utcOffset(0) + .format(); banFields.push( { name: `Ban #${i + 1}`, value: - `**Type:** ${banInfractions[i].infractionType}\n` + - `**Moderator:** ${banModerators[i]}\n` + - `**Reason:** ${banInfractions[i].reason}\n` + - `**Date:** ${formattedDate}\n` + - `**Infraction ID:** ${banInfractions[i].infractionID}`, + `**Type:** ${banInfractions[i].infractionType}\n` + + `**Moderator:** ${banModerators[i]}\n` + + `**Reason:** ${banInfractions[i].reason}\n` + + `**Date:** ${formattedDate}\n` + + `**Infraction ID:** ${banInfractions[i].infractionID}`, }, { name: '', @@ -226,17 +232,19 @@ export async function handleListInfraction( const unbanFields: { name: string; value: string }[] = []; const unbanModerators = await fetchModerators(unbanInfractions); for (let i = 0; i < unbanInfractions.length; i++) { - const formattedDate: string = moment(unbanInfractions[i].date).utcOffset(0).format(); + const formattedDate: string = moment(unbanInfractions[i].date) + .utcOffset(0) + .format(); unbanFields.push( { name: `Unban #${i + 1}`, value: - `**Type:** ${unbanInfractions[i].infractionType}\n` + - `**Moderator:** ${unbanModerators[i]}\n` + - `**Reason:** ${unbanInfractions[i].reason}\n` + - `**Date:** ${formattedDate}\n` + - `**Infraction ID:** ${unbanInfractions[i].infractionID}`, + `**Type:** ${unbanInfractions[i].infractionType}\n` + + `**Moderator:** ${unbanModerators[i]}\n` + + `**Reason:** ${unbanInfractions[i].reason}\n` + + `**Date:** ${formattedDate}\n` + + `**Infraction ID:** ${unbanInfractions[i].infractionID}`, }, { name: '', @@ -260,17 +268,19 @@ export async function handleListInfraction( const userNodeModerators = await fetchModerators(userNotes); for (let i = 0; i < userNotes.length; i++) { - const formattedDate: string = moment(userNotes[i].date).utcOffset(0).format(); + const formattedDate: string = moment(userNotes[i].date) + .utcOffset(0) + .format(); noteFields.push( { name: `Note #${i + 1}`, value: - `**Type:** ${userNotes[i].infractionType}\n` + - `**Moderator:** ${userNodeModerators[i]}\n` + - `**Note:** ${userNotes[i].reason}\n` + - `**Date:** ${formattedDate}\n` + - `**Infraction ID:** ${userNotes[i].infractionID}`, + `**Type:** ${userNotes[i].infractionType}\n` + + `**Moderator:** ${userNodeModerators[i]}\n` + + `**Note:** ${userNotes[i].reason}\n` + + `**Date:** ${formattedDate}\n` + + `**Infraction ID:** ${userNotes[i].infractionID}`, }, { name: '', @@ -295,7 +305,7 @@ export async function handleListInfraction( name: `${discordUser.tag}'s Infractions`, iconURL: avatarURL || undefined, }, - description: "Click the buttons below to view the user's infractions in detail.", + description: 'Click the buttons below to view the user\'s infractions in detail.', fields: [ { name: 'UserID', @@ -352,8 +362,7 @@ export async function handleListInfraction( const userNotFound = makeEmbed({ color: Colors.Red, title: 'User not found', - description: - 'An error occurred while fetching user information, please check the userID. If the ID is correct, this user may not exist on Discord anymore - If you need to view their infractions anyway one of the bot team can search the DB manually.', + description: 'An error occurred while fetching user information, please check the userID. If the ID is correct, this user may not exist on Discord anymore - If you need to view their infractions anyway one of the bot team can search the DB manually.', }); await interaction.followUp({ embeds: [userNotFound], ephemeral }); diff --git a/src/commands/moderation/infractions/functions/removeTimeout.ts b/src/commands/moderation/infractions/functions/removeTimeout.ts index 9c1e7c0f..211778a9 100644 --- a/src/commands/moderation/infractions/functions/removeTimeout.ts +++ b/src/commands/moderation/infractions/functions/removeTimeout.ts @@ -2,52 +2,48 @@ import { ChatInputCommandInteraction, Colors, TextChannel, User } from 'discord. import moment from 'moment'; import { constantsConfig, Logger, makeEmbed } from '../../../../lib'; -const notTimedOutEmbed = (discordUser: User) => - makeEmbed({ - title: 'Remove Timeout - Failed', - description: `${discordUser.toString()} is not currently timed out.`, - color: Colors.Red, - }); +const notTimedOutEmbed = (discordUser: User) => makeEmbed({ + title: 'Remove Timeout - Failed', + description: `${discordUser.toString()} is not currently timed out.`, + color: Colors.Red, +}); -const failedRemoveTimeoutEmbed = (discordUser: User) => - makeEmbed({ - title: 'Remove Timeout - Failed', - description: `Failed to remove timeout for ${discordUser.toString()}`, - color: Colors.Red, - }); +const failedRemoveTimeoutEmbed = (discordUser: User) => makeEmbed({ + title: 'Remove Timeout - Failed', + description: `Failed to remove timeout for ${discordUser.toString()}`, + color: Colors.Red, +}); -const modLogEmbed = (moderator: User, discordUser: User, date: string) => - makeEmbed({ - author: { - name: `[TIMEOUT REMOVED] ${discordUser.tag}`, - iconURL: discordUser.displayAvatarURL(), +const modLogEmbed = (moderator: User, discordUser: User, date: string) => makeEmbed({ + author: { + name: `[TIMEOUT REMOVED] ${discordUser.tag}`, + iconURL: discordUser.displayAvatarURL(), + }, + fields: [ + { + inline: true, + name: 'Moderator', + value: moderator.toString(), }, - fields: [ - { - inline: true, - name: 'Moderator', - value: moderator.toString(), - }, - { - inline: true, - name: 'User', - value: discordUser.toString(), - }, - { - inline: false, - name: 'Date', - value: date, - }, - ], - footer: { text: `User ID: ${discordUser.id}` }, - color: Colors.Green, - }); + { + inline: true, + name: 'User', + value: discordUser.toString(), + }, + { + inline: false, + name: 'Date', + value: date, + }, + ], + footer: { text: `User ID: ${discordUser.id}` }, + color: Colors.Green, +}); -const timeoutRemovedEmbed = (discordUser: User) => - makeEmbed({ - title: `${discordUser.tag} was successfully removed from timeout`, - color: Colors.Green, - }); +const timeoutRemovedEmbed = (discordUser: User) => makeEmbed({ + title: `${discordUser.tag} was successfully removed from timeout`, + color: Colors.Green, +}); const noModLogs = makeEmbed({ title: 'Remove Timeout - No Mod Log', diff --git a/src/commands/moderation/infractions/functions/timeout.ts b/src/commands/moderation/infractions/functions/timeout.ts index 264647a0..54af02b6 100644 --- a/src/commands/moderation/infractions/functions/timeout.ts +++ b/src/commands/moderation/infractions/functions/timeout.ts @@ -9,87 +9,80 @@ const noConnEmbed = makeEmbed({ color: Colors.Red, }); -const failedTimeoutEmbed = (discordUser: User, error: any) => - makeEmbed({ - title: 'Timeout - Failed', - description: makeLines([`Failed to timeout ${discordUser.toString()}`, '', error]), - color: Colors.Red, - }); - -const DMEmbed = (moderator: User, timeoutDuration: string, reason: string, guild: Guild, timedOutUntil: Date) => - makeEmbed({ - title: `You have been timed out in ${guild.name}`, - description: 'This timeout is also logged against your record.', - fields: [ - { - inline: true, - name: 'Duration', - value: durationInEnglish(timeoutDuration), - }, - { - inline: true, - name: 'Moderator', - value: moderator.toString(), - }, - { - inline: false, - name: 'Reason', - value: reason, - }, - ], - footer: { text: `Your timeout will be lifted on ${timedOutUntil.toUTCString()}` }, - }); - -const timeoutEmbed = (discordUser: User) => - makeEmbed({ - title: `${discordUser.tag} was timed out successfully`, - color: Colors.Green, - }); - -const DMFailed = (discordUser: User) => - makeEmbed({ - title: 'Timeout - DM not sent', - description: `DM was not sent to ${discordUser.toString()}, they either have DMs closed or share no mutual servers with the bot.`, - color: Colors.Red, - }); - -const modLogEmbed = ( - moderator: User, - discordUser: User, - timeoutReason: string, - timeoutDuration: string, - formattedDate: string, -) => - makeEmbed({ - author: { - name: `[TIMED OUT] ${discordUser.tag}`, - iconURL: discordUser.displayAvatarURL(), +const failedTimeoutEmbed = (discordUser: User, error: any) => makeEmbed({ + title: 'Timeout - Failed', + description: makeLines([ + `Failed to timeout ${discordUser.toString()}`, + '', + error, + ]), + color: Colors.Red, +}); + +const DMEmbed = (moderator: User, timeoutDuration: string, reason: string, guild: Guild, timedOutUntil: Date) => makeEmbed({ + title: `You have been timed out in ${guild.name}`, + description: 'This timeout is also logged against your record.', + fields: [ + { + inline: true, + name: 'Duration', + value: durationInEnglish(timeoutDuration), }, - fields: [ - { - name: 'User', - value: discordUser.toString(), - }, - { - name: 'Moderator', - value: `${moderator}`, - }, - { - name: 'Reason', - value: `\u200B${timeoutReason}`, - }, - { - name: 'Duration', - value: durationInEnglish(timeoutDuration), - }, - { - name: 'Date', - value: formattedDate, - }, - ], - footer: { text: `User ID: ${discordUser.id}` }, - color: Colors.Red, - }); + { + inline: true, + name: 'Moderator', + value: moderator.toString(), + }, + { + inline: false, + name: 'Reason', + value: reason, + }, + ], + footer: { text: `Your timeout will be lifted on ${timedOutUntil.toUTCString()}` }, +}); + +const timeoutEmbed = (discordUser: User) => makeEmbed({ + title: `${discordUser.tag} was timed out successfully`, + color: Colors.Green, +}); + +const DMFailed = (discordUser: User) => makeEmbed({ + title: 'Timeout - DM not sent', + description: `DM was not sent to ${discordUser.toString()}, they either have DMs closed or share no mutual servers with the bot.`, + color: Colors.Red, +}); + +const modLogEmbed = (moderator: User, discordUser: User, timeoutReason: string, timeoutDuration: string, formattedDate: string) => makeEmbed({ + author: { + name: `[TIMED OUT] ${discordUser.tag}`, + iconURL: discordUser.displayAvatarURL(), + }, + fields: [ + { + name: 'User', + value: discordUser.toString(), + }, + { + name: 'Moderator', + value: `${moderator}`, + }, + { + name: 'Reason', + value: `\u200B${timeoutReason}`, + }, + { + name: 'Duration', + value: durationInEnglish(timeoutDuration), + }, + { + name: 'Date', + value: formattedDate, + }, + ], + footer: { text: `User ID: ${discordUser.id}` }, + color: Colors.Red, +}); const noModLogs = makeEmbed({ title: 'Timeout - No Mod Log', @@ -103,12 +96,11 @@ const logFailed = makeEmbed({ color: Colors.Red, }); -const communicationNotDisabledEmbed = (discordUser: User) => - makeEmbed({ - title: 'Timeout - Communication not disabled', - description: `Bot has not detected that ${discordUser.toString()} was successfully timed out. Timeout may have failed.`, - color: Colors.Red, - }); +const communicationNotDisabledEmbed = (discordUser: User) => makeEmbed({ + title: 'Timeout - Communication not disabled', + description: `Bot has not detected that ${discordUser.toString()} was successfully timed out. Timeout may have failed.`, + color: Colors.Red, +}); export async function handleTimeoutInfraction(interaction: ChatInputCommandInteraction<'cached'>) { await interaction.deferReply({ ephemeral: true }); @@ -127,7 +119,9 @@ export async function handleTimeoutInfraction(interaction: ChatInputCommandInter const discordUser = await interaction.guild.members.fetch(userID); const moderator = interaction.user; const currentDate = new Date(); - const formattedDate: string = moment(currentDate).utcOffset(0).format(); + const formattedDate: string = moment(currentDate) + .utcOffset(0) + .format(); const modLogsChannel = interaction.guild.channels.resolve(constantsConfig.channels.MOD_LOGS) as TextChannel; //Try to timeout the user @@ -140,22 +134,11 @@ export async function handleTimeoutInfraction(interaction: ChatInputCommandInter return; } - if (discordUser.isCommunicationDisabled()) { - //Timeout was successful + if (discordUser.isCommunicationDisabled()) { //Timeout was successful await interaction.editReply({ embeds: [timeoutEmbed(discordUser.user)] }); //Try and send a Dm to the user try { - await discordUser.send({ - embeds: [ - DMEmbed( - moderator, - timeoutDuration.toString(), - timeoutReason, - interaction.guild, - discordUser.communicationDisabledUntil, - ), - ], - }); + await discordUser.send({ embeds: [DMEmbed(moderator, timeoutDuration.toString(), timeoutReason, interaction.guild, discordUser.communicationDisabledUntil)] }); } catch { if (modLogsChannel) { await interaction.followUp({ embeds: [DMFailed(discordUser.user)], ephemeral: true }); @@ -163,11 +146,7 @@ export async function handleTimeoutInfraction(interaction: ChatInputCommandInter } //Send a mod log to the mod logs channel try { - await modLogsChannel.send({ - embeds: [ - modLogEmbed(moderator, discordUser.user, timeoutReason, timeoutDuration.toString(), formattedDate), - ], - }); + await modLogsChannel.send({ embeds: [modLogEmbed(moderator, discordUser.user, timeoutReason, timeoutDuration.toString(), formattedDate)] }); } catch { await interaction.followUp({ embeds: [noModLogs], ephemeral: true }); return; diff --git a/src/commands/moderation/infractions/functions/unbanInfractions.ts b/src/commands/moderation/infractions/functions/unbanInfractions.ts index 964566e1..48894f24 100644 --- a/src/commands/moderation/infractions/functions/unbanInfractions.ts +++ b/src/commands/moderation/infractions/functions/unbanInfractions.ts @@ -9,48 +9,44 @@ const noConnEmbed = makeEmbed({ color: Colors.Red, }); -const failedUnbanEmbed = (userID: string) => - makeEmbed({ - title: 'Unban - Failed', - description: `Failed to Unban ${userID}, this user may not be banned.`, - color: Colors.Red, - }); - -const unbanEmbed = (userID: string) => - makeEmbed({ - title: `${userID} was unbanned successfully`, - color: Colors.Green, - }); - -const modLogEmbed = (moderator: User, userID: string, banReason: string, formattedDate: string) => - makeEmbed({ - author: { name: `[UNBANNED] ${userID}` }, - fields: [ - { - name: 'User', - value: userID, - }, - { - name: 'Moderator', - value: `${moderator}`, - }, - { - name: 'Reason', - value: `\u200B${banReason}`, - }, - { - name: 'Date', - value: formattedDate, - }, - ], - footer: { text: `User ID: ${userID}` }, - color: Colors.Red, - }); +const failedUnbanEmbed = (userID: string) => makeEmbed({ + title: 'Unban - Failed', + description: `Failed to Unban ${userID}, this user may not be banned.`, + color: Colors.Red, +}); + +const unbanEmbed = (userID: string) => makeEmbed({ + title: `${userID} was unbanned successfully`, + color: Colors.Green, +}); + +const modLogEmbed = (moderator: User, userID: string, banReason: string, formattedDate: string) => makeEmbed({ + author: { name: `[UNBANNED] ${userID}` }, + fields: [ + { + name: 'User', + value: userID, + }, + { + name: 'Moderator', + value: `${moderator}`, + }, + { + name: 'Reason', + value: `\u200B${banReason}`, + }, + { + name: 'Date', + value: formattedDate, + }, + ], + footer: { text: `User ID: ${userID}` }, + color: Colors.Red, +}); const noModLogs = makeEmbed({ title: 'Unban - No Mod Log', - description: - "I can't find the mod logs channel. I will still try to unban the user. Please check the channel still exists.", + description: 'I can\'t find the mod logs channel. I will still try to unban the user. Please check the channel still exists.', color: Colors.Red, }); @@ -76,7 +72,9 @@ export async function handleUnbanInfraction(interaction: ChatInputCommandInterac const moderator = interaction.user; const currentDate = new Date(); - const formattedDate: string = moment(currentDate).utcOffset(0).format(); + const formattedDate: string = moment(currentDate) + .utcOffset(0) + .format(); const modLogsChannel = interaction.guild.channels.resolve(constantsConfig.channels.MOD_LOGS) as TextChannel; //Check if the mod logs channel exists diff --git a/src/commands/moderation/infractions/functions/userNote.ts b/src/commands/moderation/infractions/functions/userNote.ts index 4e2ef024..30d58cad 100644 --- a/src/commands/moderation/infractions/functions/userNote.ts +++ b/src/commands/moderation/infractions/functions/userNote.ts @@ -15,43 +15,41 @@ const noteFailed = makeEmbed({ color: Colors.Red, }); -const modLogEmbed = (formattedDate: any, moderator: User, discordUser: User, note: string) => - makeEmbed({ - author: { - name: `[NOTE] ${discordUser.tag}`, - iconURL: discordUser.displayAvatarURL(), +const modLogEmbed = (formattedDate: any, moderator: User, discordUser: User, note: string) => makeEmbed({ + author: { + name: `[NOTE] ${discordUser.tag}`, + iconURL: discordUser.displayAvatarURL(), + }, + fields: [ + { + inline: false, + name: 'User', + value: discordUser.toString(), }, - fields: [ - { - inline: false, - name: 'User', - value: discordUser.toString(), - }, - { - inline: false, - name: 'Moderator', - value: moderator.toString(), - }, - { - inline: false, - name: 'Note', - value: note, - }, - { - inline: false, - name: 'Date', - value: formattedDate, - }, - ], - footer: { text: `User ID: ${discordUser.id}` }, - color: Colors.Red, - }); - -const noteEmbed = (user: User) => - makeEmbed({ - title: `Note for ${user.tag} has been added successfully`, - color: Colors.Green, - }); + { + inline: false, + name: 'Moderator', + value: moderator.toString(), + }, + { + inline: false, + name: 'Note', + value: note, + }, + { + inline: false, + name: 'Date', + value: formattedDate, + }, + ], + footer: { text: `User ID: ${discordUser.id}` }, + color: Colors.Red, +}); + +const noteEmbed = (user: User) => makeEmbed({ + title: `Note for ${user.tag} has been added successfully`, + color: Colors.Green, +}); const noModLogs = makeEmbed({ title: 'Note - No Mod Log', diff --git a/src/commands/moderation/infractions/functions/warn.ts b/src/commands/moderation/infractions/functions/warn.ts index 62a76dac..120e89f8 100644 --- a/src/commands/moderation/infractions/functions/warn.ts +++ b/src/commands/moderation/infractions/functions/warn.ts @@ -9,79 +9,74 @@ const noConnEmbed = makeEmbed({ color: Colors.Red, }); -const warnFailed = (discordUser: User) => - makeEmbed({ - title: 'Warn - Failed', - description: `Failed to warn ${discordUser.toString()}, doc not saved to mongoDB`, - color: Colors.Red, - }); - -const dmEmbed = (guild: Guild, formattedDate: any, moderator: User, reason: string) => - makeEmbed({ - title: `You have been warned in ${guild.name}`, - fields: [ - { - inline: false, - name: 'Moderator', - value: moderator.toString(), - }, - { - inline: false, - name: 'Reason', - value: reason, - }, - { - inline: false, - name: 'Date', - value: formattedDate, - }, - ], - }); - -const noDM = (discordUser: User) => - makeEmbed({ - title: 'Warn - DM not sent', - description: `DM was not sent to ${discordUser.toString()}, they either have DMs closed or share no mutual servers with the bot.`, - color: Colors.Red, - }); - -const modLogEmbed = (formattedDate: any, moderator: User, discordUser: User, reason: string) => - makeEmbed({ - author: { - name: `[WARNED] ${discordUser.tag}`, - iconURL: discordUser.displayAvatarURL(), +const warnFailed = (discordUser: User) => makeEmbed({ + title: 'Warn - Failed', + description: `Failed to warn ${discordUser.toString()}, doc not saved to mongoDB`, + color: Colors.Red, +}); + +const dmEmbed = (guild: Guild, formattedDate: any, moderator: User, reason: string) => makeEmbed({ + title: `You have been warned in ${guild.name}`, + fields: [ + { + inline: false, + name: 'Moderator', + value: moderator.toString(), + }, + { + inline: false, + name: 'Reason', + value: reason, + }, + { + inline: false, + name: 'Date', + value: formattedDate, + }, + ], +}); + +const noDM = (discordUser: User) => makeEmbed({ + title: 'Warn - DM not sent', + description: `DM was not sent to ${discordUser.toString()}, they either have DMs closed or share no mutual servers with the bot.`, + color: Colors.Red, +}); + +const modLogEmbed = (formattedDate: any, moderator: User, discordUser: User, reason: string) => makeEmbed({ + author: { + name: `[WARNED] ${discordUser.tag}`, + iconURL: discordUser.displayAvatarURL(), + }, + fields: [ + { + inline: false, + name: 'User', + value: discordUser.toString(), + }, + { + inline: false, + name: 'Moderator', + value: moderator.toString(), + }, + { + inline: false, + name: 'Reason', + value: reason, + }, + { + inline: false, + name: 'Date', + value: formattedDate, }, - fields: [ - { - inline: false, - name: 'User', - value: discordUser.toString(), - }, - { - inline: false, - name: 'Moderator', - value: moderator.toString(), - }, - { - inline: false, - name: 'Reason', - value: reason, - }, - { - inline: false, - name: 'Date', - value: formattedDate, - }, - ], - footer: { text: `User ID: ${discordUser.id}` }, - color: Colors.Red, - }); - -const warnEmbed = (discordUser: User) => - makeEmbed({ - title: `${discordUser.tag} was warned successfully`, - color: Colors.Green, - }); + ], + footer: { text: `User ID: ${discordUser.id}` }, + color: Colors.Red, +}); + +const warnEmbed = (discordUser: User) => makeEmbed({ + title: `${discordUser.tag} was warned successfully`, + color: Colors.Green, +}); const noModLogs = makeEmbed({ title: 'Warn - No Mod Log', diff --git a/src/commands/moderation/infractions/infractions.ts b/src/commands/moderation/infractions/infractions.ts index 7aa8e177..4da67f02 100644 --- a/src/commands/moderation/infractions/infractions.ts +++ b/src/commands/moderation/infractions/infractions.ts @@ -197,33 +197,33 @@ export default slashCommand(data, async ({ interaction }) => { const subcommandName = interaction.options.getSubcommand(); switch (subcommandName) { - case 'list': - const userID = interaction.options.getUser('tag_or_id')?.id; - await handleListInfraction(interaction, userID, false); - break; - case 'delete': - await handleDeleteInfraction(interaction); - break; - case 'note': - await handleUserNoteInfraction(interaction); - break; - case 'warn': - await handleWarnInfraction(interaction); - break; - case 'timeout': - await handleTimeoutInfraction(interaction); - break; - case 'remove-timeout': - await handleRemoveTimeoutInfraction(interaction); - break; - case 'ban': - await handleBanInfraction(interaction); - break; - case 'unban': - await handleUnbanInfraction(interaction); - break; + case 'list': + const userID = interaction.options.getUser('tag_or_id')?.id; + await handleListInfraction(interaction, userID, false); + break; + case 'delete': + await handleDeleteInfraction(interaction); + break; + case 'note': + await handleUserNoteInfraction(interaction); + break; + case 'warn': + await handleWarnInfraction(interaction); + break; + case 'timeout': + await handleTimeoutInfraction(interaction); + break; + case 'remove-timeout': + await handleRemoveTimeoutInfraction(interaction); + break; + case 'ban': + await handleBanInfraction(interaction); + break; + case 'unban': + await handleUnbanInfraction(interaction); + break; - default: - await interaction.reply({ content: 'Unknown subcommand', ephemeral: true }); + default: + await interaction.reply({ content: 'Unknown subcommand', ephemeral: true }); } }); diff --git a/src/commands/moderation/listRoleUsers.ts b/src/commands/moderation/listRoleUsers.ts index 1da6ed73..8702463d 100644 --- a/src/commands/moderation/listRoleUsers.ts +++ b/src/commands/moderation/listRoleUsers.ts @@ -1,12 +1,5 @@ import { ApplicationCommandOptionType, ApplicationCommandType } from 'discord.js'; -import { - constantsConfig, - Logger, - makeEmbed, - createPaginatedEmbedHandler, - slashCommand, - slashCommandStructure, -} from '../../lib'; +import { constantsConfig, Logger, makeEmbed, createPaginatedEmbedHandler, slashCommand, slashCommandStructure } from '../../lib'; const data = slashCommandStructure({ name: 'list-role-users', @@ -48,12 +41,10 @@ export default slashCommand(data, async ({ interaction }) => { membersAddedToPage++; if (membersAddedToPage >= pageLimit) { - embeds.push( - makeEmbed({ - title: `Role Users | ${role.name} - Page ${currentPage + 1} of ${totalPages}`, - description, - }), - ); + embeds.push(makeEmbed({ + title: `Role Users | ${role.name} - Page ${currentPage + 1} of ${totalPages}`, + description, + })); description = ''; membersAddedToPage = 0; currentPage++; @@ -61,12 +52,10 @@ export default slashCommand(data, async ({ interaction }) => { } if (description.trim() !== '') { - embeds.push( - makeEmbed({ - title: `Role Users | ${role.name} - Page ${currentPage + 1} of ${totalPages}`, - description, - }), - ); + embeds.push(makeEmbed({ + title: `Role Users | ${role.name} - Page ${currentPage + 1} of ${totalPages}`, + description, + })); } if (embeds.length === 0) { diff --git a/src/commands/moderation/roleAssignment.ts b/src/commands/moderation/roleAssignment.ts index d9e32428..0ad0c832 100644 --- a/src/commands/moderation/roleAssignment.ts +++ b/src/commands/moderation/roleAssignment.ts @@ -1,4 +1,9 @@ -import { ActionRowBuilder, ApplicationCommandType, ButtonBuilder, ButtonStyle } from 'discord.js'; +import { + ActionRowBuilder, + ApplicationCommandType, + ButtonBuilder, + ButtonStyle, +} from 'discord.js'; import { constantsConfig, makeEmbed, slashCommand, slashCommandStructure } from '../../lib'; const data = slashCommandStructure({ @@ -11,8 +16,7 @@ const data = slashCommandStructure({ const interestedInEmbed = makeEmbed({ title: 'Role Assignment', - description: - 'Please react below to set your role according to your skill set. If you do not have the skills in any of the available roles, please do not react as this will not benefit the development of the addon.', + description: 'Please react below to set your role according to your skill set. If you do not have the skills in any of the available roles, please do not react as this will not benefit the development of the addon.', }); const mediaAnnouncementsEmbed = makeEmbed({ @@ -74,12 +78,12 @@ export default slashCommand(data, async ({ interaction }) => { // Create a single embed for each group type and add all rows to it const interestedInEmbedWithRows = { embeds: [interestedInEmbed], - components: [], + components: [] as ActionRowBuilder[], }; const mediaAnnouncementsEmbedWithRows = { embeds: [mediaAnnouncementsEmbed], - components: [], + components: [] as ActionRowBuilder[], }; interestedInRows.forEach((row) => { diff --git a/src/commands/moderation/rules.ts b/src/commands/moderation/rules.ts index 7cfdd839..c0c83960 100644 --- a/src/commands/moderation/rules.ts +++ b/src/commands/moderation/rules.ts @@ -49,7 +49,7 @@ const DISCUSSION_EMBED = makeEmbed({ '- Use of slurs or any form of bigotry is not tolerated', '- No inappropriate, NSFW or NSFL content like (but not limited to) nudity, pornography, gore, ...', '- No general spam', - "- Do not send multiple unsolicited DM's", + '- Do not send multiple unsolicited DM\'s', '- No troll or insensitive messaging, including insensitive inside jokes', '- Inappropriate/offensive profile information/picture will not be tolerated', '- Certain topics like politics, religion and other sensitive subjects will only be tolerated if a careful and respectful conversation is held', @@ -67,9 +67,7 @@ const ROLE_EMBED = makeEmbed({ export default slashCommand(data, async ({ interaction }) => { if (interaction.channel) { - await interaction.channel.send({ - embeds: [RULES_EMBED, FAQ_EMBED, POLICIES_EMBED, DISCUSSION_EMBED, ROLE_EMBED], - }); + await interaction.channel.send({ embeds: [RULES_EMBED, FAQ_EMBED, POLICIES_EMBED, DISCUSSION_EMBED, ROLE_EMBED] }); } else { await interaction.reply({ content: 'This command can only be used in a server.', ephemeral: true }); } diff --git a/src/commands/moderation/slowmode/functions/disable.ts b/src/commands/moderation/slowmode/functions/disable.ts index f9f3fb30..2f5dd384 100644 --- a/src/commands/moderation/slowmode/functions/disable.ts +++ b/src/commands/moderation/slowmode/functions/disable.ts @@ -1,24 +1,9 @@ import { ChannelType, ChatInputCommandInteraction, Colors } from 'discord.js'; import { Logger } from '../../../../lib'; -export async function handleDisableSlowmode( - interaction: ChatInputCommandInteraction<'cached'>, - slowmodeChannel: any, - modLogsChannel: any, - scheduler: any, - failedEmbed: any, - noChannelEmbed: any, - successEmbed: any, - modLogEmbed: any, - slowModeEmbedField: any, -) { +export async function handleDisableSlowmode(interaction: ChatInputCommandInteraction<'cached'>, slowmodeChannel: any, modLogsChannel: any, scheduler: any, failedEmbed: any, noChannelEmbed: any, successEmbed: any, modLogEmbed: any, slowModeEmbedField: any) { try { - if ( - slowmodeChannel.type === ChannelType.GuildForum || - slowmodeChannel.type === ChannelType.GuildText || - slowmodeChannel.type === ChannelType.PrivateThread || - slowmodeChannel.type === ChannelType.PublicThread - ) { + if (slowmodeChannel.type === ChannelType.GuildForum || slowmodeChannel.type === ChannelType.GuildText || slowmodeChannel.type === ChannelType.PrivateThread || slowmodeChannel.type === ChannelType.PublicThread) { await slowmodeChannel.setRateLimitPerUser(0, 'Slow mode disabled through bot'); if (scheduler) { await scheduler.cancel({ name: 'autoDisableSlowMode', data: { channelId: slowmodeChannel.id } }); @@ -32,13 +17,14 @@ export async function handleDisableSlowmode( try { await modLogsChannel.send({ - embeds: [ - modLogEmbed( - 'disabled', - slowModeEmbedField(interaction.user.toString(), slowmodeChannel.id, 0, 0), - Colors.Green, + embeds: [modLogEmbed('disabled', + slowModeEmbedField( + interaction.user.toString(), + slowmodeChannel.id, + 0, + 0, ), - ], + Colors.Green)], }); } catch { await interaction.reply({ embeds: [noChannelEmbed('Disable', 'Mod Log')] }); diff --git a/src/commands/moderation/slowmode/functions/set.ts b/src/commands/moderation/slowmode/functions/set.ts index e31199f7..857d504b 100644 --- a/src/commands/moderation/slowmode/functions/set.ts +++ b/src/commands/moderation/slowmode/functions/set.ts @@ -1,25 +1,8 @@ import { ChannelType, ChatInputCommandInteraction, Colors } from 'discord.js'; -export async function handleSetSlowmode( - interaction: ChatInputCommandInteraction<'cached'>, - duration: number, - slowmodeChannel: any, - autoDisable: any, - modLogsChannel: any, - scheduler: any, - failedEmbed: any, - noChannelEmbed: any, - successEmbed: any, - modLogEmbed: any, - slowModeEmbedField: any, -) { +export async function handleSetSlowmode(interaction: ChatInputCommandInteraction<'cached'>, duration: number, slowmodeChannel: any, autoDisable: any, modLogsChannel: any, scheduler: any, failedEmbed: any, noChannelEmbed: any, successEmbed: any, modLogEmbed: any, slowModeEmbedField: any) { try { - if ( - slowmodeChannel.type === ChannelType.GuildForum || - slowmodeChannel.type === ChannelType.GuildText || - slowmodeChannel.type === ChannelType.PrivateThread || - slowmodeChannel.type === ChannelType.PublicThread - ) { + if (slowmodeChannel.type === ChannelType.GuildForum || slowmodeChannel.type === ChannelType.GuildText || slowmodeChannel.type === ChannelType.PrivateThread || slowmodeChannel.type === ChannelType.PublicThread) { await slowmodeChannel.setRateLimitPerUser(duration / 1000, 'Slow mode enabled through bot'); if (scheduler) { await scheduler.cancel({ name: 'autoDisableSlowMode', data: { channelId: slowmodeChannel.id } }); @@ -36,18 +19,14 @@ export async function handleSetSlowmode( try { await modLogsChannel.send({ - embeds: [ - modLogEmbed( - 'Set', - slowModeEmbedField( - interaction.user.toString(), - slowmodeChannel.id, - duration, - autoDisable && scheduler ? autoDisable.toString() : 0, - ), - Colors.Green, + embeds: [modLogEmbed('Set', + slowModeEmbedField( + interaction.user.toString(), + slowmodeChannel.id, + duration, + autoDisable && scheduler ? autoDisable.toString() : 0, ), - ], + Colors.Green)], }); } catch { await interaction.reply({ embeds: [noChannelEmbed('set', 'mod logs')], ephemeral: true }); diff --git a/src/commands/moderation/slowmode/slowmode.ts b/src/commands/moderation/slowmode/slowmode.ts index 85522a0b..f192e5c0 100644 --- a/src/commands/moderation/slowmode/slowmode.ts +++ b/src/commands/moderation/slowmode/slowmode.ts @@ -1,12 +1,5 @@ import { ApplicationCommandOptionType, ApplicationCommandType, Colors, EmbedField, TextChannel } from 'discord.js'; -import { - constantsConfig, - slashCommand, - slashCommandStructure, - makeEmbed, - durationInEnglish, - getScheduler, -} from '../../../lib'; +import { constantsConfig, slashCommand, slashCommandStructure, makeEmbed, durationInEnglish, getScheduler } from '../../../lib'; import { handleSetSlowmode } from './functions/set'; import { handleDisableSlowmode } from './functions/disable'; @@ -92,26 +85,19 @@ const noSchedulerEmbed = makeEmbed({ color: Colors.Red, }); -const failedEmbed = (action: string, channel: string) => - makeEmbed({ - title: `Slow Mode - ${action} failed`, - description: `Failed to ${action} the slow mode for channel <@${channel}>.`, - color: Colors.Red, - }); +const failedEmbed = (action: string, channel: string) => makeEmbed({ + title: `Slow Mode - ${action} failed`, + description: `Failed to ${action} the slow mode for channel <@${channel}>.`, + color: Colors.Red, +}); -const modLogEmbed = (action: string, fields: any, color: number) => - makeEmbed({ - title: `Slow Mode - ${action}`, - fields, - color, - }); +const modLogEmbed = (action: string, fields: any, color: number) => makeEmbed({ + title: `Slow Mode - ${action}`, + fields, + color, +}); -const slowModeEmbedField = ( - moderator: string, - channel: string, - duration: number, - autoDisable: string, -): EmbedField[] => [ +const slowModeEmbedField = (moderator: string, channel: string, duration: number, autoDisable: string): EmbedField[] => [ { inline: true, name: 'Channel', @@ -134,19 +120,17 @@ const slowModeEmbedField = ( }, ]; -const noChannelEmbed = (action: string, channelName: string) => - makeEmbed({ - title: `Slow Mode - ${action} - No ${channelName} channel`, - description: `The command was successful, but no message to ${channelName} was sent. Please check the channel still exists.`, - color: Colors.Yellow, - }); +const noChannelEmbed = (action:string, channelName: string) => makeEmbed({ + title: `Slow Mode - ${action} - No ${channelName} channel`, + description: `The command was successful, but no message to ${channelName} was sent. Please check the channel still exists.`, + color: Colors.Yellow, +}); -const successEmbed = (action: string, channel: string) => - makeEmbed({ - title: `Slow Mode - ${action} successful`, - description: `Slow mode for channel <#${channel}> has been ${action} successfully.`, - color: Colors.Green, - }); +const successEmbed = (action: string, channel: string) => makeEmbed({ + title: `Slow Mode - ${action} successful`, + description: `Slow mode for channel <#${channel}> has been ${action} successfully.`, + color: Colors.Green, +}); export default slashCommand(data, async ({ interaction }) => { const scheduler = getScheduler(); @@ -162,36 +146,14 @@ export default slashCommand(data, async ({ interaction }) => { const subcommandName = interaction.options.getSubcommand(); switch (subcommandName) { - case 'set': - await handleSetSlowmode( - interaction, - duration, - slowmodeChannel, - autoDisable, - modLogsChannel, - scheduler, - failedEmbed, - noChannelEmbed, - successEmbed, - modLogEmbed, - slowModeEmbedField, - ); - break; - case 'disable': - await handleDisableSlowmode( - interaction, - slowmodeChannel, - modLogsChannel, - scheduler, - failedEmbed, - noChannelEmbed, - successEmbed, - modLogEmbed, - slowModeEmbedField, - ); - break; + case 'set': + await handleSetSlowmode(interaction, duration, slowmodeChannel, autoDisable, modLogsChannel, scheduler, failedEmbed, noChannelEmbed, successEmbed, modLogEmbed, slowModeEmbedField); + break; + case 'disable': + await handleDisableSlowmode(interaction, slowmodeChannel, modLogsChannel, scheduler, failedEmbed, noChannelEmbed, successEmbed, modLogEmbed, slowModeEmbedField); + break; - default: - await interaction.reply({ content: 'Unknown subcommand', ephemeral: true }); + default: + await interaction.reply({ content: 'Unknown subcommand', ephemeral: true }); } }); diff --git a/src/commands/moderation/welcome.ts b/src/commands/moderation/welcome.ts index bb6889c1..2b1f160e 100644 --- a/src/commands/moderation/welcome.ts +++ b/src/commands/moderation/welcome.ts @@ -25,6 +25,7 @@ const WELCOME_EMBED = makeEmbed({ '', `Feel free to download, test, and share your feedback, or if you are interested in developing, assign your <#${constantsConfig.channels.ROLES}>, and get cracking!`, ]), + }); const SOCIAL_EMBED = makeEmbed({ @@ -49,8 +50,7 @@ const SUPPORT_EMBED = makeEmbed({ const IMPORTANT_INFO_EMBED = makeEmbed({ title: '<:Partnered:921520970123059231> FlyByWireSimulations | Important Info', - description: - 'By being a member of our Discord Server, you agree to the following, and failure to do so can result in removal from the server.', + description: 'By being a member of our Discord Server, you agree to the following, and failure to do so can result in removal from the server.', fields: [ { name: 'Appropriate Content', @@ -92,6 +92,7 @@ const HELP_EMBED = makeEmbed({ name: 'Flight School', value: `We've opened our <#${constantsConfig.channels.FLIGHT_SCHOOL}> channel for any questions you have pertaining to the operation of the A32NX in the simulator.`, }, + ], }); diff --git a/src/commands/moderation/whois.ts b/src/commands/moderation/whois.ts index 23a3fd5f..917cba5a 100644 --- a/src/commands/moderation/whois.ts +++ b/src/commands/moderation/whois.ts @@ -8,14 +8,12 @@ const data = slashCommandStructure({ type: ApplicationCommandType.ChatInput, default_member_permissions: constantsConfig.commandPermission.MANAGE_SERVER, //Overrides need to be added for admin and moderator roles dm_permission: false, - options: [ - { - name: 'tag_or_id', - description: "Provide a user's tag or id to get information about them.", - type: ApplicationCommandOptionType.User, - required: false, - }, - ], + options: [{ + name: 'tag_or_id', + description: 'Provide a user\'s tag or id to get information about them.', + type: ApplicationCommandOptionType.User, + required: false, + }], }); const beautifiedStatus: { [key: string]: string } = { @@ -74,11 +72,7 @@ export default slashCommand(data, async ({ interaction }) => { }, { name: 'Permissions', - value: targetMember.permissions - .toArray() - .join(', ') - .toLowerCase() - .replace(/_/g, ' ') + value: targetMember.permissions.toArray().join(', ').toLowerCase().replace(/_/g, ' ') .replace(/(^\w)|(\s+\w)/g, (char) => char.toUpperCase()), }, ], diff --git a/src/commands/utils/avatar.ts b/src/commands/utils/avatar.ts index 6c3f1bb6..941e37e4 100644 --- a/src/commands/utils/avatar.ts +++ b/src/commands/utils/avatar.ts @@ -3,16 +3,14 @@ import { slashCommand, slashCommandStructure, makeEmbed } from '../../lib'; const data = slashCommandStructure({ name: 'avatar', - description: "Shows the selected user's avatar", + description: 'Shows the selected user\'s avatar', type: ApplicationCommandType.ChatInput, - options: [ - { - name: 'tag_or_id', - description: 'Please provide a user tag or ID.', - type: ApplicationCommandOptionType.User, - required: false, - }, - ], + options: [{ + name: 'tag_or_id', + description: 'Please provide a user tag or ID.', + type: ApplicationCommandOptionType.User, + required: false, + }], }); export default slashCommand(data, async ({ interaction }) => { diff --git a/src/commands/utils/birthday/birthday.ts b/src/commands/utils/birthday/birthday.ts index 1efc77e7..71fab53f 100644 --- a/src/commands/utils/birthday/birthday.ts +++ b/src/commands/utils/birthday/birthday.ts @@ -84,17 +84,17 @@ export default slashCommand(data, async ({ interaction }) => { const subcommandName = interaction.options.getSubcommand(); switch (subcommandName) { - case 'set': - await handleSetBirthday(interaction); - break; - case 'remove': - await handleRemoveBirthday(interaction); - break; - case 'list': - await handleListBirthday(interaction); - break; + case 'set': + await handleSetBirthday(interaction); + break; + case 'remove': + await handleRemoveBirthday(interaction); + break; + case 'list': + await handleListBirthday(interaction); + break; - default: - await interaction.reply({ content: 'Unknown subcommand', ephemeral: true }); + default: + await interaction.reply({ content: 'Unknown subcommand', ephemeral: true }); } }); diff --git a/src/commands/utils/birthday/functions/listBirthday.ts b/src/commands/utils/birthday/functions/listBirthday.ts index 023fc671..82369cad 100644 --- a/src/commands/utils/birthday/functions/listBirthday.ts +++ b/src/commands/utils/birthday/functions/listBirthday.ts @@ -1,19 +1,18 @@ import { ChatInputCommandInteraction } from 'discord.js'; import { Birthday, Logger, makeEmbed } from '../../../../lib'; -const birthdayListEmbed = (fields: Array) => - makeEmbed({ - title: 'Birthday - Birthday List', - description: fields.length > 0 ? undefined : 'No birthdays set', - fields, - }); +const birthdayListEmbed = (fields: Array) => makeEmbed({ + title: 'Birthday - Birthday List', + description: fields.length > 0 ? undefined : 'No birthdays set', + fields, +}); export async function handleListBirthday(interaction: ChatInputCommandInteraction<'cached'>) { await interaction.deferReply(); try { const birthdays = await Birthday.find({}).sort({ day: 1 }); // Only day sort required, months are bucketized - const members = await interaction.guild.members.fetch(); + const members = await interaction.guild!.members.fetch(); const monthBuckets: Array> = [ ['January', []], @@ -31,12 +30,10 @@ export async function handleListBirthday(interaction: ChatInputCommandInteractio ]; for (const birthday of birthdays) { - const member = members.get(birthday.userID); + const member = members.get(birthday.userID!); if (member) { - monthBuckets[birthday.utcDatetime!.getUTCMonth()][1].push( - `${member.displayName} - ${birthday.day}/${birthday.month} (Z${birthday.timezone! < 0 ? '' : '+'}${birthday.timezone})`, - ); + monthBuckets[birthday.utcDatetime!.getUTCMonth()][1].push(`${member.displayName} - ${birthday.day}/${birthday.month} (Z${birthday.timezone! < 0 ? '' : '+'}${birthday.timezone})`); } } diff --git a/src/commands/utils/birthday/functions/removeBirthday.ts b/src/commands/utils/birthday/functions/removeBirthday.ts index a2d6d90b..49c4539e 100644 --- a/src/commands/utils/birthday/functions/removeBirthday.ts +++ b/src/commands/utils/birthday/functions/removeBirthday.ts @@ -1,18 +1,16 @@ import { ChatInputCommandInteraction, Colors, User } from 'discord.js'; import { Birthday, makeEmbed } from '../../../../lib'; -const noBirthdayEmbed = (discordUser: User) => - makeEmbed({ - title: 'Birthday remove failed', - description: `${discordUser} doesn't have a birthday set`, - color: Colors.Red, - }); +const noBirthdayEmbed = (discordUser: User) => makeEmbed({ + title: 'Birthday remove failed', + description: `${discordUser} doesn't have a birthday set`, + color: Colors.Red, +}); -const birthdayRemovedEmbed = (discordUser: User) => - makeEmbed({ - title: 'Birthday removed', - description: `${discordUser}'s birthday has been removed`, - }); +const birthdayRemovedEmbed = (discordUser: User) => makeEmbed({ + title: 'Birthday removed', + description: `${discordUser}'s birthday has been removed`, +}); export async function handleRemoveBirthday(interaction: ChatInputCommandInteraction<'cached'>) { const userID = interaction.user.id; diff --git a/src/commands/utils/birthday/functions/setBirthday.ts b/src/commands/utils/birthday/functions/setBirthday.ts index e55879db..67714cfb 100644 --- a/src/commands/utils/birthday/functions/setBirthday.ts +++ b/src/commands/utils/birthday/functions/setBirthday.ts @@ -31,11 +31,10 @@ const invalidDateEmbed = makeEmbed({ color: Colors.Red, }); -const birthdaySetEmbed = (discordUser: User, birthdayDay: number, birthdayMonth: number, birthdayTimezone: number) => - makeEmbed({ - title: 'Birthday - Birthday Set', - description: `${discordUser}'s birthday has been set to ${birthdayDay}/${birthdayMonth} and their timezone is UTC${birthdayTimezone < 0 ? '' : '+'}${birthdayTimezone}`, - }); +const birthdaySetEmbed = (discordUser: User, birthdayDay: number, birthdayMonth: number, birthdayTimezone: number) => makeEmbed({ + title: 'Birthday - Birthday Set', + description: `${discordUser}'s birthday has been set to ${birthdayDay}/${birthdayMonth} and their timezone is UTC${birthdayTimezone < 0 ? '' : '+'}${birthdayTimezone}`, +}); export async function handleSetBirthday(interaction: ChatInputCommandInteraction<'cached'>) { const selectedDay = interaction.options.getInteger('day')!; diff --git a/src/commands/utils/count.ts b/src/commands/utils/count.ts index 1f3b13f0..ad6bf7dd 100644 --- a/src/commands/utils/count.ts +++ b/src/commands/utils/count.ts @@ -17,7 +17,7 @@ const data = slashCommandStructure({ }); export default slashCommand(data, async ({ interaction }) => { - // check if user has the role +// check if user has the role const hasRole = interaction.member.roles.cache.has(constantsConfig.roles.BOT_DEVELOPER); if (!hasRole) { @@ -25,7 +25,7 @@ export default slashCommand(data, async ({ interaction }) => { return; } - const countThread = interaction.guild.channels.resolve(constantsConfig.threads.COUNT_THREAD); + const countThread = interaction.guild.channels.resolve(constantsConfig.threads.COUNT_THREAD) as TextChannel | null; if (!countThread) { await interaction.reply({ content: 'Count thread not found.', ephemeral: true }); diff --git a/src/commands/utils/docSearch.ts b/src/commands/utils/docSearch.ts index fc941422..4a4ee487 100644 --- a/src/commands/utils/docSearch.ts +++ b/src/commands/utils/docSearch.ts @@ -6,15 +6,13 @@ const data = slashCommandStructure({ name: 'doc-search', description: 'Searches the FlyByWire Documentation for a given query.', type: ApplicationCommandType.ChatInput, - options: [ - { - name: 'query', - description: 'The query to search for.', - type: ApplicationCommandOptionType.String, - max_length: 100, - required: true, - }, - ], + options: [{ + name: 'query', + description: 'The query to search for.', + type: ApplicationCommandOptionType.String, + max_length: 100, + required: true, + }], }); const DOCS_BASE_URL = 'https://docs.flybywiresim.com'; @@ -35,9 +33,7 @@ export default slashCommand(data, async ({ interaction }) => { color: Colors.Red, }); return interaction.reply({ embeds: [URLEmbed] }); - } catch (_) { - /**/ - } + } catch (_) { /**/ } const filter = new Filter(); if (filter.isProfane(searchWord)) { diff --git a/src/commands/utils/github/functions/githubPullRequest.ts b/src/commands/utils/github/functions/githubPullRequest.ts index f656d479..c656d566 100644 --- a/src/commands/utils/github/functions/githubPullRequest.ts +++ b/src/commands/utils/github/functions/githubPullRequest.ts @@ -35,9 +35,7 @@ export async function handleGithubPullRequest(interaction: ChatInputCommandInter } } else { try { - const response = await request('GET /repos/flybywiresim/a32nx/pulls/{pull_number}', { - pull_number: cleanedPrNumber, - }); + const response = await request('GET /repos/flybywiresim/a32nx/pulls/{pull_number}', { pull_number: cleanedPrNumber }); return interaction.reply(response.data.html_url); } catch { return interaction.reply({ embeds: [invalidEmbed] }); diff --git a/src/commands/utils/github/functions/handleGithubIssue.ts b/src/commands/utils/github/functions/handleGithubIssue.ts index 0611e36b..cb7864a4 100644 --- a/src/commands/utils/github/functions/handleGithubIssue.ts +++ b/src/commands/utils/github/functions/handleGithubIssue.ts @@ -35,9 +35,7 @@ export async function handleGithubIssue(interaction: ChatInputCommandInteraction } } else { try { - const response = await request('GET /repos/flybywiresim/a32nx/issues/{issue_number}', { - issue_number: cleanedIssueNumber, - }); + const response = await request('GET /repos/flybywiresim/a32nx/issues/{issue_number}', { issue_number: cleanedIssueNumber }); return interaction.reply(response.data.html_url); } catch { return interaction.reply({ embeds: [invalidEmbed] }); diff --git a/src/commands/utils/github/github.ts b/src/commands/utils/github/github.ts index 0de351c8..3cfec522 100644 --- a/src/commands/utils/github/github.ts +++ b/src/commands/utils/github/github.ts @@ -12,38 +12,36 @@ const data = slashCommandStructure({ name: 'pr', description: 'Retrieves the link of the provided GitHub pull request.', type: ApplicationCommandOptionType.Subcommand, - options: [ - { - name: 'pr_number', - description: 'Please provide the pull request number.', - type: ApplicationCommandOptionType.String, - required: true, - }, - { - name: 'repo', - description: 'Please provide the repo name.', - type: ApplicationCommandOptionType.String, - required: false, - }, + options: [{ + name: 'pr_number', + description: 'Please provide the pull request number.', + type: ApplicationCommandOptionType.String, + required: true, + }, + { + name: 'repo', + description: 'Please provide the repo name.', + type: ApplicationCommandOptionType.String, + required: false, + }, ], }, { name: 'issue', description: 'Retrieves the link of the provided GitHub issue.', type: ApplicationCommandOptionType.Subcommand, - options: [ - { - name: 'issue_number', - description: 'Please provide the issue number.', - type: ApplicationCommandOptionType.String, - required: true, - }, - { - name: 'repo', - description: 'Please provide the repo name.', - type: ApplicationCommandOptionType.String, - required: false, - }, + options: [{ + name: 'issue_number', + description: 'Please provide the issue number.', + type: ApplicationCommandOptionType.String, + required: true, + }, + { + name: 'repo', + description: 'Please provide the repo name.', + type: ApplicationCommandOptionType.String, + required: false, + }, ], }, ], @@ -53,14 +51,14 @@ export default slashCommand(data, async ({ interaction }) => { const subcommandName = interaction.options.getSubcommand(); switch (subcommandName) { - case 'pr': - await handleGithubPullRequest(interaction); - break; - case 'issue': - await handleGithubIssue(interaction); - break; + case 'pr': + await handleGithubPullRequest(interaction); + break; + case 'issue': + await handleGithubIssue(interaction); + break; - default: - await interaction.reply({ content: 'Unknown subcommand', ephemeral: true }); + default: + await interaction.reply({ content: 'Unknown subcommand', ephemeral: true }); } }); diff --git a/src/commands/utils/help.ts b/src/commands/utils/help.ts index 3c92ee1e..7702a60a 100644 --- a/src/commands/utils/help.ts +++ b/src/commands/utils/help.ts @@ -46,55 +46,52 @@ export default slashCommand(data, async ({ interaction }: { interaction: Command const totalPages = Math.ceil(sortedCommands.length / pageLimit); // Build the description with subcommands and subcommand groups - const description = currentCommands - .map((command) => { - let { description } = command; - - // Check if it's a context-specific message command - const isMessageCommand = command.type === ApplicationCommandType.Message; - - // Check if it's a context-specific user command - const isUserCommand = command.type === ApplicationCommandType.User; - - const subcommandList = command.options?.filter( - (option) => - option.type === ApplicationCommandOptionType.Subcommand || - option.type === ApplicationCommandOptionType.SubcommandGroup, - ); - - if (subcommandList && subcommandList.length > 0) { - const subcommandDescription = subcommandList - .map((subcommand) => { - if (subcommand.type === ApplicationCommandOptionType.Subcommand) { - return subcommand.name; + const description = currentCommands.map((command) => { + let { description } = command; + + // Check if it's a context-specific message command + const isMessageCommand = command.type === ApplicationCommandType.Message; + + // Check if it's a context-specific user command + const isUserCommand = command.type === ApplicationCommandType.User; + + const subcommandList = command.options?.filter( + (option) => option.type === ApplicationCommandOptionType.Subcommand + || option.type === ApplicationCommandOptionType.SubcommandGroup, + ); + + if (subcommandList && subcommandList.length > 0) { + const subcommandDescription = subcommandList + .map((subcommand) => { + if (subcommand.type === ApplicationCommandOptionType.Subcommand) { + return subcommand.name; + } + if (subcommand.type === ApplicationCommandOptionType.SubcommandGroup) { + const groupSubcommands = subcommand.options?.filter( + (sub) => sub.type === ApplicationCommandOptionType.Subcommand, + ); + if (groupSubcommands && groupSubcommands.length > 0) { + return `${subcommand.name} [${groupSubcommands + .map((sub) => sub.name) + .join(', ')}]`; } - if (subcommand.type === ApplicationCommandOptionType.SubcommandGroup) { - const groupSubcommands = subcommand.options?.filter( - (sub) => sub.type === ApplicationCommandOptionType.Subcommand, - ); - if (groupSubcommands && groupSubcommands.length > 0) { - return `${subcommand.name} [${groupSubcommands - .map((sub) => sub.name) - .join(', ')}]`; - } - return `${subcommand.name} [None]`; - } - return ''; - }) - .join(', '); // Use a comma to separate subcommands - description += `\n**Subcommands and Groups:** \n${subcommandDescription}`; - } - - // Append a label for context-specific message and user commands - if (isMessageCommand) { - description += '\n(Context Command - Message)'; - } else if (isUserCommand) { - description += '\n(Context Command - User)'; - } - - return `**${command.name}**: ${description}`; - }) - .join('\n\n'); + return `${subcommand.name} [None]`; + } + return ''; + }) + .join(', '); // Use a comma to separate subcommands + description += `\n**Subcommands and Groups:** \n${subcommandDescription}`; + } + + // Append a label for context-specific message and user commands + if (isMessageCommand) { + description += '\n(Context Command - Message)'; + } else if (isUserCommand) { + description += '\n(Context Command - User)'; + } + + return `**${command.name}**: ${description}`; + }).join('\n\n'); const embed = makeEmbed({ title: `Bot Commands - Page ${page + 1} of ${totalPages}`, diff --git a/src/commands/utils/locate/functions/filterSearchResults.ts b/src/commands/utils/locate/functions/filterSearchResults.ts index ceb1d4f6..c0779d4d 100644 --- a/src/commands/utils/locate/functions/filterSearchResults.ts +++ b/src/commands/utils/locate/functions/filterSearchResults.ts @@ -3,9 +3,7 @@ import { Panel } from '../panels/panel'; export const filterSearchResults = (query: string, source: Map) => { // Get any target that includes the query string. - const possibleTargets = Array.from(source.keys()).filter((current) => - current.toLowerCase().includes(query.toLowerCase()), - ); + const possibleTargets = Array.from(source.keys()).filter((current) => current.toLowerCase().includes(query.toLowerCase())); // Sort possible targets based on the length of the match. -> More equal characters between query and target = higher ranking possibleTargets.sort((a, b) => a.indexOf(query) - b.indexOf(query)); diff --git a/src/commands/utils/locate/functions/handleCommand.ts b/src/commands/utils/locate/functions/handleCommand.ts index 35ae8e24..9f339b6d 100644 --- a/src/commands/utils/locate/functions/handleCommand.ts +++ b/src/commands/utils/locate/functions/handleCommand.ts @@ -15,18 +15,17 @@ const invalidTargetEmbed = makeEmbed({ color: Colors.Red, }); -const locateEmbed = (panel: Panel) => - makeEmbed({ - title: panel.title, - url: panel.docsUrl, - description: makeLines([ - `Learn more about the ${panel.name} and the flight deck:`, - `* [${panel.name} Documentation](${panel.docsUrl})`, - `* [Flight Deck Overview](${panel.flightDeckUrl})`, - ]), - image: { url: panel.imageUrl }, - footer: { text: 'Tip: Click the image to view in full size' }, - }); +const locateEmbed = (panel: Panel) => makeEmbed({ + title: panel.title, + url: panel.docsUrl, + description: makeLines([ + `Learn more about the ${panel.name} and the flight deck:`, + `* [${panel.name} Documentation](${panel.docsUrl})`, + `* [Flight Deck Overview](${panel.flightDeckUrl})`, + ]), + image: { url: panel.imageUrl }, + footer: { text: 'Tip: Click the image to view in full size' }, +}); export async function handleCommand(interaction: ChatInputCommandInteraction<'cached'>, panelMap: Map) { const target = interaction.options.getString('target'); diff --git a/src/commands/utils/locate/locate.ts b/src/commands/utils/locate/locate.ts index a50b4838..13dd0f6e 100644 --- a/src/commands/utils/locate/locate.ts +++ b/src/commands/utils/locate/locate.ts @@ -68,38 +68,34 @@ const autocompleteCallback: AutocompleteCallback = ({ interaction }) => { let choices: ApplicationCommandOptionChoiceData[]; switch (subcommand) { - case 'a32nx': - choices = filterSearchResults(cleanTarget, a32nxPanelMap); - break; - /* case 'a380x': + case 'a32nx': + choices = filterSearchResults(cleanTarget, a32nxPanelMap); + break; + /* case 'a380x': choices = filterSearchResults(cleanTarget, a380xPanelMap); break; */ - default: - return interaction.respond([]); + default: + return interaction.respond([]); } return interaction.respond(choices); }; -export default slashCommand( - data, - async ({ interaction }) => { - await interaction.deferReply(); +export default slashCommand(data, async ({ interaction }) => { + await interaction.deferReply(); - const subcommand = interaction.options.getSubcommand(); + const subcommand = interaction.options.getSubcommand(); - switch (subcommand) { - case 'a32nx': - await handleCommand(interaction, a32nxPanelMap); - break; - /* case 'a380x': + switch (subcommand) { + case 'a32nx': + await handleCommand(interaction, a32nxPanelMap); + break; + /* case 'a380x': await handleCommand(interaction, a380xPanelMap); break; */ - default: - await interaction.editReply({ content: 'Unknown subcommand' }); - } - }, - autocompleteCallback, -); + default: + await interaction.editReply({ content: 'Unknown subcommand' }); + } +}, autocompleteCallback); diff --git a/src/commands/utils/locate/panels/a32nx/a32nx-panels.ts b/src/commands/utils/locate/panels/a32nx/a32nx-panels.ts index 91632077..51272118 100644 --- a/src/commands/utils/locate/panels/a32nx/a32nx-panels.ts +++ b/src/commands/utils/locate/panels/a32nx/a32nx-panels.ts @@ -1,73 +1,9 @@ import { Panel } from '../panel'; import { flyPad } from './flyPad'; -import { - accuPressPanel, - autobrakeAndGearPanel, - clockPanel, - dcdu, - ewd, - instrumentLightingPanel, - isis, - nd, - pfd, - sd, -} from './front-panel'; +import { accuPressPanel, autobrakeAndGearPanel, clockPanel, dcdu, ewd, instrumentLightingPanel, isis, nd, pfd, sd } from './front-panel'; import { efisPanel, fcuPanel, lightKnobsPanel, warningPanel } from './glareshield'; -import { - antiIcePanel, - adirsPanel, - apuPanel, - callsPanel, - cvrPanel, - emerElecPwrPanel, - evacPanel, - extLtPanel, - fltCtlPanel, - gpwsPanel, - intLtPanel, - oxyPanel, - paVideoPanel, - signsPanel, - wiperPanel, - cabinPressPanel, - airCondPanel, - elecPanel, - fuelPanel, - hydPanel, - firePanel, - engManStartPanel, - ventilationPanel, - cargoSmokePanel, - cargoVentPanel, - thirdACP, - readingLightsJumpSeats, - cockpitDoorIndicatorPanel, - eltPanel, - pedestalLightPanel, - emerCbPanel, - fmsLoadPanel, - maintenancePanel, -} from './overhead'; -import { - aidsDfdrPanel, - atcTcasPanel, - captPedestalLightingPanel, - cockpitDoorPanel, - console, - ecamControlPanel, - engPanel, - flaps, - gravityGearExtensionPanel, - mcdu, - parkBrkPanel, - printer, - rmpAcpPanel, - rudderTrim, - speedBrake, - switchingPanel, - thrLvrPitchTrim, - wxPanel, -} from './pedestal'; +import { antiIcePanel, adirsPanel, apuPanel, callsPanel, cvrPanel, emerElecPwrPanel, evacPanel, extLtPanel, fltCtlPanel, gpwsPanel, intLtPanel, oxyPanel, paVideoPanel, signsPanel, wiperPanel, cabinPressPanel, airCondPanel, elecPanel, fuelPanel, hydPanel, firePanel, engManStartPanel, ventilationPanel, cargoSmokePanel, cargoVentPanel, thirdACP, readingLightsJumpSeats, cockpitDoorIndicatorPanel, eltPanel, pedestalLightPanel, emerCbPanel, fmsLoadPanel, maintenancePanel } from './overhead'; +import { aidsDfdrPanel, atcTcasPanel, captPedestalLightingPanel, cockpitDoorPanel, console, ecamControlPanel, engPanel, flaps, gravityGearExtensionPanel, mcdu, parkBrkPanel, printer, rmpAcpPanel, rudderTrim, speedBrake, switchingPanel, thrLvrPitchTrim, wxPanel } from './pedestal'; import { rearBackCbPanel } from './rear-cb-panel'; export const a32nxPanels: Panel[] = [ diff --git a/src/commands/utils/locate/panels/a32nx/flyPad.ts b/src/commands/utils/locate/panels/a32nx/flyPad.ts index 0b8e7194..36e4dc0a 100644 --- a/src/commands/utils/locate/panels/a32nx/flyPad.ts +++ b/src/commands/utils/locate/panels/a32nx/flyPad.ts @@ -7,5 +7,9 @@ export const flyPad: Panel = { docsUrl: LOCATE_DOCS_BASE_URLS.a32nx.flypad, flightDeckUrl: LOCATE_DOCS_BASE_URLS.a32nx.flightdeck, imageUrl: `${LOCATE_IMAGE_BASE_URLS.a32nx.flypad}/efb_downscaled.gif`, - identifiers: ['flypad', 'efb', 'electronic-flight-bag'], + identifiers: [ + 'flypad', + 'efb', + 'electronic-flight-bag', + ], }; diff --git a/src/commands/utils/locate/panels/a32nx/front-panel.ts b/src/commands/utils/locate/panels/a32nx/front-panel.ts index 50c2e862..6a75d57b 100644 --- a/src/commands/utils/locate/panels/a32nx/front-panel.ts +++ b/src/commands/utils/locate/panels/a32nx/front-panel.ts @@ -51,7 +51,13 @@ export const nd: Panel = { docsUrl: `${FRONT_DOCS_BASE_URL}/nd`, flightDeckUrl: LOCATE_DOCS_BASE_URLS.a32nx.flightdeck, imageUrl: `${FRONT_IMAGE_BASE_URL}/nd.png`, - identifiers: ['nd', 'navigation-display', 'weather-radar', 'terrain-map', 'terr-on-nd-switch'], + identifiers: [ + 'nd', + 'navigation-display', + 'weather-radar', + 'terrain-map', + 'terr-on-nd-switch', + ], }; export const isis: Panel = { @@ -60,7 +66,11 @@ export const isis: Panel = { docsUrl: `${FRONT_DOCS_BASE_URL}/isis`, flightDeckUrl: LOCATE_DOCS_BASE_URLS.a32nx.flightdeck, imageUrl: `${FRONT_IMAGE_BASE_URL}/isis.png`, - identifiers: ['isis', 'integrated-standby-instrument-system', 'backup-pfd'], + identifiers: [ + 'isis', + 'integrated-standby-instrument-system', + 'backup-pfd', + ], }; export const dcdu: Panel = { @@ -69,7 +79,11 @@ export const dcdu: Panel = { docsUrl: `${FRONT_DOCS_BASE_URL}/dcdu`, flightDeckUrl: LOCATE_DOCS_BASE_URLS.a32nx.flightdeck, imageUrl: `${FRONT_IMAGE_BASE_URL}/dcdu.png`, - identifiers: ['dcdu', 'datalink-ctl-and-display-unit', 'cpdlc'], + identifiers: [ + 'dcdu', + 'datalink-ctl-and-display-unit', + 'cpdlc', + ], }; export const ewd: Panel = { @@ -78,7 +92,13 @@ export const ewd: Panel = { docsUrl: `${FRONT_DOCS_BASE_URL}/upper-ecam`, flightDeckUrl: LOCATE_DOCS_BASE_URLS.a32nx.flightdeck, imageUrl: `${FRONT_IMAGE_BASE_URL}/ewd.png`, - identifiers: ['ecam-upper', 'upper-ecam', 'ewd', 'engine-and-warning-display', 'n1-display'], + identifiers: [ + 'ecam-upper', + 'upper-ecam', + 'ewd', + 'engine-and-warning-display', + 'n1-display', + ], }; export const sd: Panel = { @@ -124,7 +144,10 @@ export const clockPanel: Panel = { docsUrl: `${FRONT_DOCS_BASE_URL}/clock`, flightDeckUrl: LOCATE_DOCS_BASE_URLS.a32nx.flightdeck, imageUrl: `${FRONT_IMAGE_BASE_URL}/clock.png`, - identifiers: ['clock', 'date'], + identifiers: [ + 'clock', + 'date', + ], }; export const accuPressPanel: Panel = { @@ -133,5 +156,9 @@ export const accuPressPanel: Panel = { docsUrl: `${FRONT_DOCS_BASE_URL}/accu`, flightDeckUrl: LOCATE_DOCS_BASE_URLS.a32nx.flightdeck, imageUrl: `${FRONT_IMAGE_BASE_URL}/accu_press.png`, - identifiers: ['accu-press', 'accumulator-pressure-indicator', 'brake-pressure-indicator'], + identifiers: [ + 'accu-press', + 'accumulator-pressure-indicator', + 'brake-pressure-indicator', + ], }; diff --git a/src/commands/utils/locate/panels/a32nx/glareshield.ts b/src/commands/utils/locate/panels/a32nx/glareshield.ts index c49ccad7..c7f999a5 100644 --- a/src/commands/utils/locate/panels/a32nx/glareshield.ts +++ b/src/commands/utils/locate/panels/a32nx/glareshield.ts @@ -93,5 +93,9 @@ export const lightKnobsPanel: Panel = { docsUrl: `${GLARESHIELD_DOCS_BASE_URL}/light-knobs/`, flightDeckUrl: LOCATE_DOCS_BASE_URLS.a32nx.flightdeck, imageUrl: `${GLARESHIELD_IMAGE_BASE_URL}/light_knobs.png`, - identifiers: ['table-light-knob', 'integral-glareshield-lighting-knob', 'fcu-brightness-knob'], + identifiers: [ + 'table-light-knob', + 'integral-glareshield-lighting-knob', + 'fcu-brightness-knob', + ], }; diff --git a/src/commands/utils/locate/panels/a32nx/overhead.ts b/src/commands/utils/locate/panels/a32nx/overhead.ts index 05d55d0c..bb3c89b0 100644 --- a/src/commands/utils/locate/panels/a32nx/overhead.ts +++ b/src/commands/utils/locate/panels/a32nx/overhead.ts @@ -32,7 +32,11 @@ export const callsPanel: Panel = { docsUrl: `${OVHD_DOCS_BASE_URL}/calls/`, flightDeckUrl: LOCATE_DOCS_BASE_URLS.a32nx.flightdeck, imageUrl: `${OVHD_IMAGE_BASE_URL}/calls.png`, - identifiers: ['calls-panel', 'call', 'calls'], + identifiers: [ + 'calls-panel', + 'call', + 'calls', + ], }; export const oxyPanel: Panel = { @@ -41,7 +45,13 @@ export const oxyPanel: Panel = { docsUrl: `${OVHD_DOCS_BASE_URL}/oxygen/`, flightDeckUrl: LOCATE_DOCS_BASE_URLS.a32nx.flightdeck, imageUrl: `${OVHD_IMAGE_BASE_URL}/oxygen.png`, - identifiers: ['oxy', 'oxygen-panel', 'oxygen', 'mask-man-on-switch', 'crew-supply-switch'], + identifiers: [ + 'oxy', + 'oxygen-panel', + 'oxygen', + 'mask-man-on-switch', + 'crew-supply-switch', + ], }; export const cvrPanel: Panel = { @@ -103,7 +113,14 @@ export const evacPanel: Panel = { docsUrl: `${OVHD_DOCS_BASE_URL}/evacuation/`, flightDeckUrl: LOCATE_DOCS_BASE_URLS.a32nx.flightdeck, imageUrl: `${OVHD_IMAGE_BASE_URL}/evac.png`, - identifiers: ['evac-panel', 'evac', 'evacuation', 'command-switch', 'horn-shut-off-button', 'capt-purs-switch'], + identifiers: [ + 'evac-panel', + 'evac', + 'evacuation', + 'command-switch', + 'horn-shut-off-button', + 'capt-purs-switch', + ], }; export const fltCtlPanel: Panel = { @@ -112,7 +129,14 @@ export const fltCtlPanel: Panel = { docsUrl: `${OVHD_DOCS_BASE_URL}/flight-control-computer/`, flightDeckUrl: LOCATE_DOCS_BASE_URLS.a32nx.flightdeck, imageUrl: `${OVHD_IMAGE_BASE_URL}/flt_ctl.png`, - identifiers: ['flight-controls', 'flight-control-panel', 'flt-ctl', 'elac', 'sec', 'fac'], + identifiers: [ + 'flight-controls', + 'flight-control-panel', + 'flt-ctl', + 'elac', + 'sec', + 'fac', + ], }; export const adirsPanel: Panel = { @@ -121,7 +145,14 @@ export const adirsPanel: Panel = { docsUrl: `${OVHD_DOCS_BASE_URL}/adirs/`, flightDeckUrl: LOCATE_DOCS_BASE_URLS.a32nx.flightdeck, imageUrl: `${OVHD_IMAGE_BASE_URL}/adirs.png`, - identifiers: ['adirs-panel', 'adirs', 'adiru', 'irs', 'adr', 'ir-selector'], + identifiers: [ + 'adirs-panel', + 'adirs', + 'adiru', + 'irs', + 'adr', + 'ir-selector', + ], }; export const paVideoPanel: Panel = { @@ -130,7 +161,13 @@ export const paVideoPanel: Panel = { docsUrl: `${OVHD_DOCS_BASE_URL}/pa-cockpit-video/`, flightDeckUrl: LOCATE_DOCS_BASE_URLS.a32nx.flightdeck, imageUrl: `${OVHD_IMAGE_BASE_URL}/pa_video.png`, - identifiers: ['pa-panel', 'video', 'cockpit-video-panel', 'cockpit-door-video', 'cockpit-door-video-switch'], + identifiers: [ + 'pa-panel', + 'video', + 'cockpit-video-panel', + 'cockpit-door-video', + 'cockpit-door-video-switch', + ], }; export const extLtPanel: Panel = { @@ -165,7 +202,13 @@ export const apuPanel: Panel = { docsUrl: `${OVHD_DOCS_BASE_URL}/apu/`, flightDeckUrl: LOCATE_DOCS_BASE_URLS.a32nx.flightdeck, imageUrl: `${OVHD_IMAGE_BASE_URL}/apu.png`, - identifiers: ['apu-panel', 'apu', 'auxiliary-power-unit', 'apu-master-switch', 'apu-start-button'], + identifiers: [ + 'apu-panel', + 'apu', + 'auxiliary-power-unit', + 'apu-master-switch', + 'apu-start-button', + ], }; export const signsPanel: Panel = { @@ -305,7 +348,15 @@ export const fuelPanel: Panel = { docsUrl: `${OVHD_DOCS_BASE_URL}/fuel/`, flightDeckUrl: LOCATE_DOCS_BASE_URLS.a32nx.flightdeck, imageUrl: `${OVHD_IMAGE_BASE_URL}/fuel.png`, - identifiers: ['fuel', 'fuel-panel', 'fuel-pumps', 'x-feed', 'cross-feed', 'wing-tanks', 'center-tanks'], + identifiers: [ + 'fuel', + 'fuel-panel', + 'fuel-pumps', + 'x-feed', + 'cross-feed', + 'wing-tanks', + 'center-tanks', + ], }; export const hydPanel: Panel = { @@ -335,7 +386,13 @@ export const firePanel: Panel = { docsUrl: `${OVHD_DOCS_BASE_URL}/fire/`, flightDeckUrl: LOCATE_DOCS_BASE_URLS.a32nx.flightdeck, imageUrl: `${OVHD_IMAGE_BASE_URL}/fire.png`, - identifiers: ['engine-fire-panel', 'fire', 'smoke', 'fire-agent', 'disch'], + identifiers: [ + 'engine-fire-panel', + 'fire', + 'smoke', + 'fire-agent', + 'disch', + ], }; export const engManStartPanel: Panel = { @@ -344,7 +401,11 @@ export const engManStartPanel: Panel = { docsUrl: `${OVHD_DOCS_BASE_URL}/eng-man/`, flightDeckUrl: LOCATE_DOCS_BASE_URLS.a32nx.flightdeck, imageUrl: `${OVHD_IMAGE_BASE_URL}/eng_n1.png`, - identifiers: ['eng-n1', 'manual-engine-start', 'eng-man-start-switch'], + identifiers: [ + 'eng-n1', + 'manual-engine-start', + 'eng-man-start-switch', + ], }; export const ventilationPanel: Panel = { @@ -353,7 +414,13 @@ export const ventilationPanel: Panel = { docsUrl: `${OVHD_DOCS_BASE_URL}/vent/`, flightDeckUrl: LOCATE_DOCS_BASE_URLS.a32nx.flightdeck, imageUrl: `${OVHD_IMAGE_BASE_URL}/ventilation.png`, - identifiers: ['vent', 'ventilation-panel', 'cabin-fans', 'blower-switch', 'extract-ventilation-switch'], + identifiers: [ + 'vent', + 'ventilation-panel', + 'cabin-fans', + 'blower-switch', + 'extract-ventilation-switch', + ], }; export const cargoSmokePanel: Panel = { @@ -362,7 +429,10 @@ export const cargoSmokePanel: Panel = { docsUrl: `${OVHD_DOCS_BASE_URL}/cargo-smoke/`, flightDeckUrl: LOCATE_DOCS_BASE_URLS.a32nx.flightdeck, imageUrl: `${OVHD_IMAGE_BASE_URL}/cargo_smoke.png`, - identifiers: ['cargo-fire', 'cargo-smoke-panel'], + identifiers: [ + 'cargo-fire', + 'cargo-smoke-panel', + ], }; export const cargoVentPanel: Panel = { @@ -371,7 +441,11 @@ export const cargoVentPanel: Panel = { docsUrl: `${OVHD_DOCS_BASE_URL}/cargo-vent/`, flightDeckUrl: LOCATE_DOCS_BASE_URLS.a32nx.flightdeck, imageUrl: `${OVHD_IMAGE_BASE_URL}/cargo_vent.png`, - identifiers: ['cargo-vent-panel', 'cargo-ventilation', 'aft-isol-valve-switch'], + identifiers: [ + 'cargo-vent-panel', + 'cargo-ventilation', + 'aft-isol-valve-switch', + ], }; export const thirdACP: Panel = { @@ -380,7 +454,11 @@ export const thirdACP: Panel = { docsUrl: `${OVHD_DOCS_BASE_URL}/3rd-acp/`, flightDeckUrl: LOCATE_DOCS_BASE_URLS.a32nx.flightdeck, imageUrl: `${OVHD_IMAGE_BASE_URL}/acp_3.png`, - identifiers: ['acp3', '3rd-acp', '3rd-audio-control-panel'], + identifiers: [ + 'acp3', + '3rd-acp', + '3rd-audio-control-panel', + ], }; export const readingLightsJumpSeats: Panel = { @@ -389,7 +467,10 @@ export const readingLightsJumpSeats: Panel = { docsUrl: `${AFT_OVHD_DOCS_BASE_URL}/reading-light/`, flightDeckUrl: LOCATE_DOCS_BASE_URLS.a32nx.flightdeck, imageUrl: `${AFT_OVHD_IMAGE_BASE_URL}/jump_seat_reading_lt.png`, - identifiers: ['reading-lights-jump-seat', 'jump-seat-reading-lights'], + identifiers: [ + 'reading-lights-jump-seat', + 'jump-seat-reading-lights', + ], }; export const cockpitDoorIndicatorPanel: Panel = { @@ -398,7 +479,10 @@ export const cockpitDoorIndicatorPanel: Panel = { docsUrl: `${AFT_OVHD_DOCS_BASE_URL}/cockpit-door/#description`, flightDeckUrl: LOCATE_DOCS_BASE_URLS.a32nx.flightdeck, imageUrl: `${AFT_OVHD_IMAGE_BASE_URL}/ckpt_door_cont.png`, - identifiers: ['cockpit-door-cont', 'cockpit-door-indicator-panel'], + identifiers: [ + 'cockpit-door-cont', + 'cockpit-door-indicator-panel', + ], }; export const eltPanel: Panel = { @@ -407,7 +491,11 @@ export const eltPanel: Panel = { docsUrl: `${AFT_OVHD_DOCS_BASE_URL}/elt/`, flightDeckUrl: LOCATE_DOCS_BASE_URLS.a32nx.flightdeck, imageUrl: `${AFT_OVHD_IMAGE_BASE_URL}/elt.png`, - identifiers: ['elt', 'elt-panel', 'emergency-locator-transmitter'], + identifiers: [ + 'elt', + 'elt-panel', + 'emergency-locator-transmitter', + ], }; export const pedestalLightPanel: Panel = { @@ -416,7 +504,11 @@ export const pedestalLightPanel: Panel = { docsUrl: `${AFT_OVHD_DOCS_BASE_URL}/pedestal-light/`, flightDeckUrl: LOCATE_DOCS_BASE_URLS.a32nx.flightdeck, imageUrl: `${AFT_OVHD_IMAGE_BASE_URL}/pedestal_light.png`, - identifiers: ['pedestal-light-panel', 'acp3-switching-selector', 'audio-control-panel-3-switching-selector'], + identifiers: [ + 'pedestal-light-panel', + 'acp3-switching-selector', + 'audio-control-panel-3-switching-selector', + ], }; export const emerCbPanel: Panel = { @@ -425,7 +517,10 @@ export const emerCbPanel: Panel = { docsUrl: `${AFT_OVHD_DOCS_BASE_URL}/circuit/`, flightDeckUrl: LOCATE_DOCS_BASE_URLS.a32nx.flightdeck, imageUrl: `${AFT_OVHD_IMAGE_BASE_URL}/emer_cb.png`, - identifiers: ['emer-cb', 'emergency-circuit-breaker-panel'], + identifiers: [ + 'emer-cb', + 'emergency-circuit-breaker-panel', + ], }; export const fmsLoadPanel: Panel = { @@ -434,7 +529,9 @@ export const fmsLoadPanel: Panel = { docsUrl: `${AFT_OVHD_DOCS_BASE_URL}/fms-load/`, flightDeckUrl: LOCATE_DOCS_BASE_URLS.a32nx.flightdeck, imageUrl: `${AFT_OVHD_IMAGE_BASE_URL}/fms_load.png`, - identifiers: ['fms-load-panel'], + identifiers: [ + 'fms-load-panel', + ], }; export const maintenancePanel: Panel = { diff --git a/src/commands/utils/locate/panels/a32nx/pedestal.ts b/src/commands/utils/locate/panels/a32nx/pedestal.ts index 81f3f862..d3beb6e3 100644 --- a/src/commands/utils/locate/panels/a32nx/pedestal.ts +++ b/src/commands/utils/locate/panels/a32nx/pedestal.ts @@ -27,7 +27,12 @@ export const mcdu: Panel = { docsUrl: `${PEDESTAL_DOCS_BASE_URL}/mcdu`, flightDeckUrl: LOCATE_DOCS_BASE_URLS.a32nx.flightdeck, imageUrl: `${PEDESTAL_IMAGE_BASE_URL}/mcdu.png`, - identifiers: ['fms', 'cdu', 'mcdu', 'fmgc'], + identifiers: [ + 'fms', + 'cdu', + 'mcdu', + 'fmgc', + ], }; export const rmpAcpPanel: Panel = { @@ -36,7 +41,13 @@ export const rmpAcpPanel: Panel = { docsUrl: `${PEDESTAL_DOCS_BASE_URL}/rmp`, flightDeckUrl: LOCATE_DOCS_BASE_URLS.a32nx.flightdeck, imageUrl: `${PEDESTAL_IMAGE_BASE_URL}/rmp_acp.png`, - identifiers: ['rmp', 'radio-management-panel', 'acp', 'audio-control-panel', 'atc-panel'], + identifiers: [ + 'rmp', + 'radio-management-panel', + 'acp', + 'audio-control-panel', + 'atc-panel', + ], }; export const captPedestalLightingPanel: Panel = { @@ -45,7 +56,9 @@ export const captPedestalLightingPanel: Panel = { docsUrl: `${PEDESTAL_DOCS_BASE_URL}/lighting-capt`, flightDeckUrl: LOCATE_DOCS_BASE_URLS.a32nx.flightdeck, imageUrl: `${PEDESTAL_IMAGE_BASE_URL}/capt_pedestal_lt.png`, - identifiers: ['captain-pedestal-lighting-panel'], + identifiers: [ + 'captain-pedestal-lighting-panel', + ], }; export const wxPanel: Panel = { @@ -54,7 +67,13 @@ export const wxPanel: Panel = { docsUrl: `${PEDESTAL_DOCS_BASE_URL}/radar`, flightDeckUrl: LOCATE_DOCS_BASE_URLS.a32nx.flightdeck, imageUrl: `${PEDESTAL_IMAGE_BASE_URL}/wx_radar.png`, - identifiers: ['wx', 'weather-radar', 'wx-radar', 'pws', 'predictive-windshear-systems'], + identifiers: [ + 'wx', + 'weather-radar', + 'wx-radar', + 'pws', + 'predictive-windshear-systems', + ], }; export const speedBrake: Panel = { @@ -63,7 +82,12 @@ export const speedBrake: Panel = { docsUrl: `${PEDESTAL_DOCS_BASE_URL}/speedbrake`, flightDeckUrl: LOCATE_DOCS_BASE_URLS.a32nx.flightdeck, imageUrl: `${PEDESTAL_IMAGE_BASE_URL}/spd_brk.png`, - identifiers: ['speed-brake', 'spd-brk', 'spoilers', 'gnd-sprls'], + identifiers: [ + 'speed-brake', + 'spd-brk', + 'spoilers', + 'gnd-sprls', + ], }; export const cockpitDoorPanel: Panel = { @@ -72,7 +96,12 @@ export const cockpitDoorPanel: Panel = { docsUrl: `${PEDESTAL_DOCS_BASE_URL}/cockpit-door`, flightDeckUrl: LOCATE_DOCS_BASE_URLS.a32nx.flightdeck, imageUrl: `${PEDESTAL_IMAGE_BASE_URL}/cockpit_door.png`, - identifiers: ['cockpit-door', 'cockpit-door-panel', 'cockpit-door-switch', 'cockpit-door-video-button'], + identifiers: [ + 'cockpit-door', + 'cockpit-door-panel', + 'cockpit-door-switch', + 'cockpit-door-video-button', + ], }; export const switchingPanel: Panel = { @@ -151,7 +180,9 @@ export const rudderTrim: Panel = { docsUrl: `${PEDESTAL_DOCS_BASE_URL}/rudder-trim`, flightDeckUrl: LOCATE_DOCS_BASE_URLS.a32nx.flightdeck, imageUrl: `${PEDESTAL_IMAGE_BASE_URL}/rudder_trim.png`, - identifiers: ['rudder-trim'], + identifiers: [ + 'rudder-trim', + ], }; export const parkBrkPanel: Panel = { @@ -160,7 +191,10 @@ export const parkBrkPanel: Panel = { docsUrl: `${PEDESTAL_DOCS_BASE_URL}/parking-brake`, flightDeckUrl: LOCATE_DOCS_BASE_URLS.a32nx.flightdeck, imageUrl: `${PEDESTAL_IMAGE_BASE_URL}/park_brk.png`, - identifiers: ['parking-brake', 'park-brk'], + identifiers: [ + 'parking-brake', + 'park-brk', + ], }; export const gravityGearExtensionPanel: Panel = { @@ -169,7 +203,9 @@ export const gravityGearExtensionPanel: Panel = { docsUrl: `${PEDESTAL_DOCS_BASE_URL}/gravity-gear-ext`, flightDeckUrl: LOCATE_DOCS_BASE_URLS.a32nx.flightdeck, imageUrl: `${PEDESTAL_IMAGE_BASE_URL}/gravity_gear_extn.png`, - identifiers: ['gravity-gear-extension'], + identifiers: [ + 'gravity-gear-extension', + ], }; export const aidsDfdrPanel: Panel = { @@ -178,7 +214,14 @@ export const aidsDfdrPanel: Panel = { docsUrl: `${PEDESTAL_DOCS_BASE_URL}/lighting-aids-dfdr`, flightDeckUrl: LOCATE_DOCS_BASE_URLS.a32nx.flightdeck, imageUrl: `${PEDESTAL_IMAGE_BASE_URL}/aids_dfdr.png`, - identifiers: ['aids', 'dfdr', 'ped-flood-lt-knob', 'pedestal-flood-light-knob', 'aids-button', 'dfdr-button'], + identifiers: [ + 'aids', + 'dfdr', + 'ped-flood-lt-knob', + 'pedestal-flood-light-knob', + 'aids-button', + 'dfdr-button', + ], }; export const atcTcasPanel: Panel = { @@ -187,7 +230,13 @@ export const atcTcasPanel: Panel = { docsUrl: `${PEDESTAL_DOCS_BASE_URL}/atc-tcas`, flightDeckUrl: LOCATE_DOCS_BASE_URLS.a32nx.flightdeck, imageUrl: `${PEDESTAL_IMAGE_BASE_URL}/atc_tcas.png`, - identifiers: ['xpdr', 'atc-tcas-panel', 'transponder', 'tcas', 'alt-rptg-switch'], + identifiers: [ + 'xpdr', + 'atc-tcas-panel', + 'transponder', + 'tcas', + 'alt-rptg-switch', + ], }; export const flaps: Panel = { @@ -196,7 +245,9 @@ export const flaps: Panel = { docsUrl: `${PEDESTAL_DOCS_BASE_URL}/flaps`, flightDeckUrl: LOCATE_DOCS_BASE_URLS.a32nx.flightdeck, imageUrl: `${PEDESTAL_IMAGE_BASE_URL}/flaps.png`, - identifiers: ['flaps'], + identifiers: [ + 'flaps', + ], }; export const printer: Panel = { @@ -205,5 +256,7 @@ export const printer: Panel = { docsUrl: `${PEDESTAL_DOCS_BASE_URL}/printer`, flightDeckUrl: LOCATE_DOCS_BASE_URLS.a32nx.flightdeck, imageUrl: `${PEDESTAL_IMAGE_BASE_URL}/printer.png`, - identifiers: ['printer'], + identifiers: [ + 'printer', + ], }; diff --git a/src/commands/utils/locate/panels/a32nx/rear-cb-panel.ts b/src/commands/utils/locate/panels/a32nx/rear-cb-panel.ts index 5a801244..87f6037f 100644 --- a/src/commands/utils/locate/panels/a32nx/rear-cb-panel.ts +++ b/src/commands/utils/locate/panels/a32nx/rear-cb-panel.ts @@ -7,5 +7,8 @@ export const rearBackCbPanel: Panel = { docsUrl: `${LOCATE_DOCS_BASE_URLS.a32nx.aftOverhead}/circuit/#rear-right-back-panel`, flightDeckUrl: LOCATE_DOCS_BASE_URLS.a32nx.flightdeck, imageUrl: `${LOCATE_IMAGE_BASE_URLS.a32nx.rearCb}/rear_right_back.jpg`, - identifiers: ['rear-back-circuit-breaker-panel', 'secondary-circuit-breaker-panel'], + identifiers: [ + 'rear-back-circuit-breaker-panel', + 'secondary-circuit-breaker-panel', + ], }; diff --git a/src/commands/utils/metar.ts b/src/commands/utils/metar.ts index 4a5ae8b3..dd688e48 100644 --- a/src/commands/utils/metar.ts +++ b/src/commands/utils/metar.ts @@ -6,16 +6,14 @@ const data = slashCommandStructure({ name: 'metar', description: 'Provides the METAR report of the requested airport', type: ApplicationCommandType.ChatInput, - options: [ - { - name: 'icao', - description: 'Provide an airport ICAO code.', - type: ApplicationCommandOptionType.String, - max_length: 4, - min_length: 4, - required: true, - }, - ], + options: [{ + name: 'icao', + description: 'Provide an airport ICAO code.', + type: ApplicationCommandOptionType.String, + max_length: 4, + min_length: 4, + required: true, + }], }); export default slashCommand(data, async ({ interaction }) => { @@ -38,7 +36,8 @@ export default slashCommand(data, async ({ interaction }) => { const metarReport: any = await fetch(`https://avwx.rest/api/metar/${icao}`, { method: 'GET', headers: { Authorization: metarToken }, - }).then((res) => res.json()); + }) + .then((res) => res.json()); if (metarReport.error) { const invalidEmbed = makeEmbed({ @@ -71,9 +70,7 @@ export default slashCommand(data, async ({ interaction }) => { inline: false, }, ], - footer: { - text: 'This METAR report may not accurately reflect the weather in the simulator. However, it will always be similar to the current conditions present in the sim.', - }, + footer: { text: 'This METAR report may not accurately reflect the weather in the simulator. However, it will always be similar to the current conditions present in the sim.' }, }); return interaction.editReply({ embeds: [metarEmbed] }); diff --git a/src/commands/utils/ping.ts b/src/commands/utils/ping.ts index 93c8f6a5..5d29b95b 100644 --- a/src/commands/utils/ping.ts +++ b/src/commands/utils/ping.ts @@ -5,15 +5,13 @@ const data = slashCommandStructure({ name: 'ping', description: 'Ping the bot for a response.', type: ApplicationCommandType.ChatInput, - options: [ - { - name: 'message', - description: 'Provide some text to send back.', - type: ApplicationCommandOptionType.String, - max_length: 100, - required: false, - }, - ], + options: [{ + name: 'message', + description: 'Provide some text to send back.', + type: ApplicationCommandOptionType.String, + max_length: 100, + required: false, + }], }); export default slashCommand(data, async ({ interaction }) => { diff --git a/src/commands/utils/reportedIssues.ts b/src/commands/utils/reportedIssues.ts index 0390431f..c00677e7 100644 --- a/src/commands/utils/reportedIssues.ts +++ b/src/commands/utils/reportedIssues.ts @@ -6,20 +6,17 @@ const data = slashCommandStructure({ name: 'reported-issues', description: 'Provides a link to the reported issues page within docs.', type: ApplicationCommandType.ChatInput, - options: [ - { - name: 'query', - description: 'Provide a query to search for.', - type: ApplicationCommandOptionType.String, - max_length: 100, - required: true, - }, - ], + options: [{ + name: 'query', + description: 'Provide a query to search for.', + type: ApplicationCommandOptionType.String, + max_length: 100, + required: true, + }], }); const FBW_DOCS_REPORTED_ISSUES_URL = 'https://docs.flybywiresim.com/fbw-a32nx/support/reported-issues/'; -const FBW_DOCS_AUTOPILOT_ISSUES_URL = - 'https://docs.flybywiresim.com/fbw-a32nx/feature-guides/autopilot-fbw/#typical-issues-and-how-to-solve-them'; +const FBW_DOCS_AUTOPILOT_ISSUES_URL = 'https://docs.flybywiresim.com/fbw-a32nx/feature-guides/autopilot-fbw/#typical-issues-and-how-to-solve-them'; const FBW_DOCS_SIMBRIDGE_ISSUES_URL = 'https://docs.flybywiresim.com/simbridge/troubleshooting/'; const genericReportedIssuesEmbed = makeEmbed({ @@ -27,13 +24,11 @@ const genericReportedIssuesEmbed = makeEmbed({ description: `I couldn't find a match foy your query. Please see [this link](${FBW_DOCS_REPORTED_ISSUES_URL}) for a current list of reported issues.`, }); -const issueInSubsectionEmbed = (fields: EmbedField[]) => - makeEmbed({ - title: 'FlyByWire A32NX | Reported Issues', - description: - "Your issue is in our reported issues list. Please try the possible solutions in the following link(s) and report back if they didn't help. Include all the steps you tried.", - fields, - }); +const issueInSubsectionEmbed = (fields: EmbedField[]) => makeEmbed({ + title: 'FlyByWire A32NX | Reported Issues', + description: 'Your issue is in our reported issues list. Please try the possible solutions in the following link(s) and report back if they didn\'t help. Include all the steps you tried.', + fields, +}); const subsectionLinkEmbedField = (id: string, title: string): EmbedField[] => [ { @@ -55,15 +50,12 @@ const simbridgeEmbed = makeEmbed({ const generalTroubleshootingEmbed = makeEmbed({ title: 'FlyByWire A32NX | Reported Issues', - description: - "Please try the general troubleshooting steps from our reported issues page and report back if they didn't help. Include all the steps you tried.", - fields: [ - { - inline: false, - name: 'General Troubleshooting Steps', - value: `[Link to reported issues section](${FBW_DOCS_REPORTED_ISSUES_URL}#general-troubleshooting-steps)`, - }, - ], + description: 'Please try the general troubleshooting steps from our reported issues page and report back if they didn\'t help. Include all the steps you tried.', + fields: [{ + inline: false, + name: 'General Troubleshooting Steps', + value: `[Link to reported issues section](${FBW_DOCS_REPORTED_ISSUES_URL}#general-troubleshooting-steps)`, + }], }); const tooManyResultsEmbed = makeEmbed({ @@ -110,9 +102,7 @@ export default slashCommand(data, async ({ interaction }) => { return interaction.reply({ embeds: [genericReportedIssuesEmbed] }); } - const fields = reportedIssues - .map((sectionElement: any) => subsectionLinkEmbedField(sectionElement.id, sectionElement.title)) - .flat(); + const fields = reportedIssues.map((sectionElement: any) => subsectionLinkEmbedField(sectionElement.id, sectionElement.title)).flat(); return interaction.reply({ embeds: [issueInSubsectionEmbed(fields)] }); } catch (error: any) { Logger.error(error); diff --git a/src/commands/utils/roleInfo.ts b/src/commands/utils/roleInfo.ts index 86c87e2a..8ba7233f 100644 --- a/src/commands/utils/roleInfo.ts +++ b/src/commands/utils/roleInfo.ts @@ -3,16 +3,14 @@ import { slashCommand, slashCommandStructure, makeEmbed } from '../../lib'; const data = slashCommandStructure({ name: 'role-info', - description: "Lists the given role's amount of members.", + description: 'Lists the given role\'s amount of members.', type: ApplicationCommandType.ChatInput, - options: [ - { - name: 'role', - description: 'Provide the role to get info about.', - type: ApplicationCommandOptionType.Role, - required: true, - }, - ], + options: [{ + name: 'role', + description: 'Provide the role to get info about.', + type: ApplicationCommandOptionType.Role, + required: true, + }], }); export default slashCommand(data, async ({ interaction }) => { diff --git a/src/commands/utils/searchFaq.ts b/src/commands/utils/searchFaq.ts index 29ebe50b..465a07c2 100644 --- a/src/commands/utils/searchFaq.ts +++ b/src/commands/utils/searchFaq.ts @@ -16,21 +16,20 @@ const data = slashCommandStructure({ ], }); -const noFaqsFoundEmbed = (searchTerm: string) => - makeEmbed({ - title: `No FAQs found - ${searchTerm}`, - description: 'No FAQs found matching your search term. Please try again or see the links below.', - fields: [ - { - name: '**FAQ Channel**', - value: `<#${constantsConfig.channels.FAQ}>`, - }, - { - name: '**Docs FAQ**', - value: 'https://docs.flybywiresim.com/fbw-a32nx/faq/', - }, - ], - }); +const noFaqsFoundEmbed = (searchTerm: string) => makeEmbed({ + title: `No FAQs found - ${searchTerm}`, + description: 'No FAQs found matching your search term. Please try again or see the links below.', + fields: [ + { + name: '**FAQ Channel**', + value: `<#${constantsConfig.channels.FAQ}>`, + }, + { + name: '**Docs FAQ**', + value: 'https://docs.flybywiresim.com/fbw-a32nx/faq/', + }, + ], +}); export default slashCommand(data, async ({ interaction }) => { const searchTerm = interaction.options.getString('search_term') ?? ''; diff --git a/src/commands/utils/simbriefData.ts b/src/commands/utils/simbriefData.ts index 50e456ce..26f81e69 100644 --- a/src/commands/utils/simbriefData.ts +++ b/src/commands/utils/simbriefData.ts @@ -11,15 +11,13 @@ const data = slashCommandStructure({ name: 'retrieve', description: 'Shows data for your last filed flight plan.', type: ApplicationCommandOptionType.Subcommand, - options: [ - { - name: 'pilot_id', - description: 'Please provide your pilot ID.', - type: ApplicationCommandOptionType.String, - max_length: 100, - required: true, - }, - ], + options: [{ + name: 'pilot_id', + description: 'Please provide your pilot ID.', + type: ApplicationCommandOptionType.String, + max_length: 100, + required: true, + }], }, { name: 'support-request', @@ -42,33 +40,31 @@ const simbriefdatarequestEmbed = makeEmbed({ ]), }); -const errorEmbed = (errorMessage: any) => - makeEmbed({ - title: 'SimBrief Error', - description: makeLines(['SimBrief data could not be read.', errorMessage]), - color: Colors.Red, - }); +const errorEmbed = (errorMessage: any) => makeEmbed({ + title: 'SimBrief Error', + description: makeLines(['SimBrief data could not be read.', errorMessage]), + color: Colors.Red, +}); + +const simbriefIdMismatchEmbed = (enteredId: any, flightplanId: any) => makeEmbed({ + title: 'SimBrief Data', + description: makeLines([ + `Entered pilotId ${enteredId} and returned pilotId ${flightplanId} don't match. The pilotId might be used as username by someone else.`, + ]), +}); -const simbriefIdMismatchEmbed = (enteredId: any, flightplanId: any) => - makeEmbed({ - title: 'SimBrief Data', - description: makeLines([ - `Entered pilotId ${enteredId} and returned pilotId ${flightplanId} don't match. The pilotId might be used as username by someone else.`, - ]), - }); +const simbriefEmbed = (flightplan: any) => makeEmbed({ + title: 'SimBrief Data', + description: makeLines([ + `**Generated at**: ${moment(flightplan.params.time_generated * 1000).format('DD.MM.YYYY, HH:mm:ss')}`, + `**AirFrame**: ${flightplan.aircraft.name} ${flightplan.aircraft.internal_id} ${(flightplan.aircraft.internal_id === FBW_AIRFRAME_ID) ? '(provided by FBW)' : ''}`, + `**AIRAC Cycle**: ${flightplan.params.airac}`, + `**Origin**: ${flightplan.origin.icao_code}`, + `**Destination**: ${flightplan.destination.icao_code}`, + `**Route**: ${flightplan.general.route}`, + ]), -const simbriefEmbed = (flightplan: any) => - makeEmbed({ - title: 'SimBrief Data', - description: makeLines([ - `**Generated at**: ${moment(flightplan.params.time_generated * 1000).format('DD.MM.YYYY, HH:mm:ss')}`, - `**AirFrame**: ${flightplan.aircraft.name} ${flightplan.aircraft.internal_id} ${flightplan.aircraft.internal_id === FBW_AIRFRAME_ID ? '(provided by FBW)' : ''}`, - `**AIRAC Cycle**: ${flightplan.params.airac}`, - `**Origin**: ${flightplan.origin.icao_code}`, - `**Destination**: ${flightplan.destination.icao_code}`, - `**Route**: ${flightplan.general.route}`, - ]), - }); +}); export default slashCommand(data, async ({ interaction }) => { if (interaction.options.getSubcommand() === 'support-request') { @@ -79,9 +75,7 @@ export default slashCommand(data, async ({ interaction }) => { const simbriefId = interaction.options.getString('pilot_id'); if (!simbriefId) return interaction.reply({ content: 'Invalid pilot ID!', ephemeral: true }); - const flightplan = await fetch( - `https://www.simbrief.com/api/xml.fetcher.php?json=1&userid=${simbriefId}&username=${simbriefId}`, - ).then((res) => res.json()); + const flightplan = await fetch(`https://www.simbrief.com/api/xml.fetcher.php?json=1&userid=${simbriefId}&username=${simbriefId}`).then((res) => res.json()); if (flightplan.fetch.status !== 'Success') { interaction.reply({ embeds: [errorEmbed(flightplan.fetch.status)], ephemeral: true }); diff --git a/src/commands/utils/station.ts b/src/commands/utils/station.ts index 70fa684d..8cde14a2 100644 --- a/src/commands/utils/station.ts +++ b/src/commands/utils/station.ts @@ -6,16 +6,14 @@ const data = slashCommandStructure({ name: 'station', description: 'Provides station information.', type: ApplicationCommandType.ChatInput, - options: [ - { - name: 'icao', - description: 'Provide an airport ICAO code.', - type: ApplicationCommandOptionType.String, - max_length: 4, - min_length: 4, - required: true, - }, - ], + options: [{ + name: 'icao', + description: 'Provide an airport ICAO code.', + type: ApplicationCommandOptionType.String, + max_length: 4, + min_length: 4, + required: true, + }], }); const noQueryEmbed = makeEmbed({ @@ -57,12 +55,9 @@ export default slashCommand(data, async ({ interaction }) => { return interaction.editReply({ embeds: [invalidEmbed] }); } - const runwayIdents = stationReport.runways.map( - (runways: any) => - `**${runways.ident1}/${runways.ident2}:** ` + - `${runways.length_ft} ft x ${runways.width_ft} ft / ` + - `${Math.round(runways.length_ft * 0.3048)} m x ${Math.round(runways.width_ft * 0.3048)} m`, - ); + const runwayIdents = stationReport.runways.map((runways: any) => `**${runways.ident1}/${runways.ident2}:** ` + + `${runways.length_ft} ft x ${runways.width_ft} ft / ` + + `${Math.round(runways.length_ft * 0.3048)} m x ${Math.round(runways.width_ft * 0.3048)} m`); const stationEmbed = makeEmbed({ title: `Station Info | ${stationReport.icao}`, diff --git a/src/commands/utils/taf.ts b/src/commands/utils/taf.ts index 78792ad3..dba64551 100644 --- a/src/commands/utils/taf.ts +++ b/src/commands/utils/taf.ts @@ -6,16 +6,14 @@ const data = slashCommandStructure({ name: 'taf', description: 'Provides the TAF report of the requested airport.', type: ApplicationCommandType.ChatInput, - options: [ - { - name: 'icao', - description: 'Provide an airport ICAO code.', - type: ApplicationCommandOptionType.String, - max_length: 4, - min_length: 4, - required: true, - }, - ], + options: [{ + name: 'icao', + description: 'Provide an airport ICAO code.', + type: ApplicationCommandOptionType.String, + max_length: 4, + min_length: 4, + required: true, + }], }); const noQueryEmbed = makeEmbed({ @@ -88,9 +86,7 @@ export default slashCommand(data, async ({ interaction }) => { inline: false, }, ], - footer: { - text: 'This TAF report is only a forecast, and may not accurately reflect weather in the simulator.', - }, + footer: { text: 'This TAF report is only a forecast, and may not accurately reflect weather in the simulator.' }, }); return interaction.editReply({ embeds: [tafEmbed] }); diff --git a/src/commands/utils/vatsim/functions/vatsimControllers.ts b/src/commands/utils/vatsim/functions/vatsimControllers.ts index 7604c455..08e5cd2b 100644 --- a/src/commands/utils/vatsim/functions/vatsimControllers.ts +++ b/src/commands/utils/vatsim/functions/vatsimControllers.ts @@ -1,21 +1,15 @@ import { ChatInputCommandInteraction, EmbedField } from 'discord.js'; import { makeEmbed } from '../../../../lib'; -const listEmbed = (type: string, fields: EmbedField[], totalCount: number, shownCount: number, callsign: string) => - makeEmbed({ - title: `VATSIM Data - ${callsign} - ${totalCount} ${type} online`, - description: `A list of ${shownCount} online ${type} matching ${callsign}.`, - fields, - }); +/* eslint-disable camelcase */ -const controllersListEmbedFields = ( - callsign: string, - frequency: string, - logon: string, - rating: string, - atis: string, - atisCode: string, -): EmbedField[] => { +const listEmbed = (type: string, fields: EmbedField[], totalCount: number, shownCount: number, callsign: string) => makeEmbed({ + title: `VATSIM Data - ${callsign} - ${totalCount} ${type} online`, + description: `A list of ${shownCount} online ${type} matching ${callsign}.`, + fields, +}); + +const controllersListEmbedFields = (callsign: string, frequency: string, logon: string, rating: string, atis: string, atisCode: string): EmbedField[] => { const fields = [ { name: 'Callsign', @@ -55,58 +49,38 @@ const controllersListEmbedFields = ( return fields; }; -const handleLocaleDateTimeString = (date: Date) => - date.toLocaleDateString('en-US', { - hour: 'numeric', - minute: 'numeric', - weekday: 'short', - month: 'short', - day: 'numeric', - }); +const handleLocaleDateTimeString = (date: Date) => date.toLocaleDateString('en-US', { + hour: 'numeric', + minute: 'numeric', + weekday: 'short', + month: 'short', + day: 'numeric', +}); -export async function handleVatsimControllers( - interaction: ChatInputCommandInteraction<'cached'>, - vatsimData: any, - callsignSearch: any, -) { - const vatsimAllControllers = vatsimData.controllers - ? vatsimData.controllers.filter((controller: { facility: number }) => controller.facility > 0) - : null; +export async function handleVatsimControllers(interaction: ChatInputCommandInteraction<'cached'>, vatsimData: any, callsignSearch: any) { + const vatsimAllControllers = vatsimData.controllers ? vatsimData.controllers.filter((controller: { facility: number; }) => controller.facility > 0) : null; const vatsimControllerRatings = vatsimData.ratings ? vatsimData.ratings : null; - const vatsimControllers = vatsimAllControllers - ? vatsimAllControllers.filter((controller: { callsign: string | string[] }) => - controller.callsign.includes(callsignSearch), - ) - : null; - const vatsimAtis = vatsimData.atis - ? vatsimData.atis.filter((atis: { callsign: string | string[] }) => atis.callsign.includes(callsignSearch)) - : null; + const vatsimControllers = vatsimAllControllers ? vatsimAllControllers.filter((controller: { callsign: string | string[]; }) => controller.callsign.includes(callsignSearch)) : null; + const vatsimAtis = vatsimData.atis ? vatsimData.atis.filter((atis: { callsign: string | string[]; }) => atis.callsign.includes(callsignSearch)) : null; const { keys }: ObjectConstructor = Object; - const fields: EmbedField[] = [ - ...vatsimControllers.sort((a: { facility: number }, b: { facility: number }) => b.facility - a.facility), - ...vatsimAtis, - ] + const fields: EmbedField[] = [...vatsimControllers.sort((a: { facility: number; }, b: { facility: number; }) => b.facility - a.facility), ...vatsimAtis] .map((vatsimController) => { const { callsign, frequency, logon_time, atis_code, text_atis, rating } = vatsimController; const logonTime = new Date(logon_time); const logonTimeString = handleLocaleDateTimeString(logonTime); - const ratingDetail = vatsimControllerRatings.filter((ratingInfo: { id: any }) => ratingInfo.id === rating); + const ratingDetail = vatsimControllerRatings.filter((ratingInfo: { id: any; }) => ratingInfo.id === rating); const { short, long } = ratingDetail[0]; const ratingText = `${short} - ${long}`; const atisText = text_atis ? text_atis.join('\n') : null; return controllersListEmbedFields(callsign, frequency, logonTimeString, ratingText, atisText, atis_code); - }) - .slice(0, 5) - .flat(); + }).slice(0, 5).flat(); const totalCount = keys(vatsimControllers).length + keys(vatsimAtis).length; const shownCount = totalCount < 5 ? totalCount : 5; - return interaction.reply({ - embeds: [listEmbed('Controllers & ATIS', fields, totalCount, shownCount, callsignSearch)], - }); + return interaction.reply({ embeds: [listEmbed('Controllers & ATIS', fields, totalCount, shownCount, callsignSearch)] }); } diff --git a/src/commands/utils/vatsim/functions/vatsimEvents.ts b/src/commands/utils/vatsim/functions/vatsimEvents.ts index 93453c12..468c8f83 100644 --- a/src/commands/utils/vatsim/functions/vatsimEvents.ts +++ b/src/commands/utils/vatsim/functions/vatsimEvents.ts @@ -3,18 +3,16 @@ import { Logger, makeEmbed } from '../../../../lib'; const BASE_VATSIM_URL = 'https://my.vatsim.net'; -const handleLocaleTimeString = (date: Date) => - date.toLocaleTimeString('en-US', { - hour: 'numeric', - minute: 'numeric', - }); +const handleLocaleTimeString = (date: Date) => date.toLocaleTimeString('en-US', { + hour: 'numeric', + minute: 'numeric', +}); -const handleLocaleDateString = (date: Date) => - date.toLocaleDateString('en-US', { - weekday: 'short', - month: 'short', - day: 'numeric', - }); +const handleLocaleDateString = (date: Date) => date.toLocaleDateString('en-US', { + weekday: 'short', + month: 'short', + day: 'numeric', +}); export async function handleVatsimEvents(interaction: ChatInputCommandInteraction<'cached'>) { await interaction.deferReply(); @@ -23,54 +21,52 @@ export async function handleVatsimEvents(interaction: ChatInputCommandInteractio const eventsList = await fetch(`${BASE_VATSIM_URL}/api/v1/events/all`) .then((res) => res.json()) .then((res) => res.data) - .then((res) => res.filter((event: { type: string }) => event.type === 'Event')) + .then((res) => res.filter((event: { type: string; }) => event.type === 'Event')) .then((res) => res.slice(0, 5)); - const fields: EmbedField[] = eventsList - .map((event: any) => { - const { name, organisers, end_time, start_time, link } = event; - const { division } = organisers[0]; - const startDate = new Date(start_time); - const endDate = new Date(end_time); - const startTime = handleLocaleTimeString(startDate); - const endTime = handleLocaleTimeString(endDate); - const startDateString = handleLocaleDateString(startDate); - const endDateString = handleLocaleDateString(endDate); + const fields: EmbedField[] = eventsList.map((event: any) => { + // eslint-disable-next-line camelcase + const { name, organisers, end_time, start_time, link } = event; + const { division } = organisers[0]; + const startDate = new Date(start_time); + const endDate = new Date(end_time); + const startTime = handleLocaleTimeString(startDate); + const endTime = handleLocaleTimeString(endDate); + const startDateString = handleLocaleDateString(startDate); + const endDateString = handleLocaleDateString(endDate); - return [ - { - name: 'Name', - value: name, - inline: false, - }, - { - name: 'Start Time/Date', - value: `${startTime}/${startDateString}`, - inline: true, - }, - { - name: 'End Time/Date', - value: `${endTime}/${endDateString}`, - inline: true, - }, - { - name: 'Division', - value: `${division}`, - inline: true, - }, - { - name: 'Link', - value: `${link}`, - inline: false, - }, - ]; - }) - .flat(); + return [ + { + name: 'Name', + value: name, + inline: false, + }, + { + name: 'Start Time/Date', + value: `${startTime}/${startDateString}`, + inline: true, + }, + { + name: 'End Time/Date', + value: `${endTime}/${endDateString}`, + inline: true, + }, + { + name: 'Division', + value: `${division}`, + inline: true, + }, + { + name: 'Link', + value: `${link}`, + inline: false, + }, + ]; + }).flat(); const eventsEmbed = makeEmbed({ title: 'VATSIM Events', - description: - 'A list of upcoming events on the VATSIM network. Find the full list [here.](https://my.vatsim.net/events)', + description: 'A list of upcoming events on the VATSIM network. Find the full list [here.](https://my.vatsim.net/events)', fields, }); diff --git a/src/commands/utils/vatsim/functions/vatsimObservers.ts b/src/commands/utils/vatsim/functions/vatsimObservers.ts index c3032ad6..48fd6ed1 100644 --- a/src/commands/utils/vatsim/functions/vatsimObservers.ts +++ b/src/commands/utils/vatsim/functions/vatsimObservers.ts @@ -1,12 +1,13 @@ import { ChatInputCommandInteraction, EmbedField } from 'discord.js'; import { makeEmbed } from '../../../../lib'; -const listEmbed = (type: string, fields: EmbedField[], totalCount: number, shownCount: number, callsign: string) => - makeEmbed({ - title: `VATSIM Data - ${callsign} - ${totalCount} ${type} online`, - description: `A list of ${shownCount} online ${type} matching ${callsign}.`, - fields, - }); +/* eslint-disable camelcase */ + +const listEmbed = (type: string, fields: EmbedField[], totalCount: number, shownCount: number, callsign: string) => makeEmbed({ + title: `VATSIM Data - ${callsign} - ${totalCount} ${type} online`, + description: `A list of ${shownCount} online ${type} matching ${callsign}.`, + fields, +}); const observersListEmbedFields = (callsign: string, logon: string, rating: string, atis: string): EmbedField[] => { const fields = [ @@ -38,49 +39,33 @@ const observersListEmbedFields = (callsign: string, logon: string, rating: strin return fields; }; -const handleLocaleDateTimeString = (date: Date) => - date.toLocaleDateString('en-US', { - hour: 'numeric', - minute: 'numeric', - weekday: 'short', - month: 'short', - day: 'numeric', - }); +const handleLocaleDateTimeString = (date: Date) => date.toLocaleDateString('en-US', { + hour: 'numeric', + minute: 'numeric', + weekday: 'short', + month: 'short', + day: 'numeric', +}); -export async function handleVatsimObservers( - interaction: ChatInputCommandInteraction<'cached'>, - vatsimData: any, - callsignSearch: any, -) { - const vatsimAllObservers = vatsimData.controllers - ? vatsimData.controllers.filter((controller: { facility: number }) => controller.facility <= 0) - : null; +export async function handleVatsimObservers(interaction: ChatInputCommandInteraction<'cached'>, vatsimData: any, callsignSearch: any) { + const vatsimAllObservers = vatsimData.controllers ? vatsimData.controllers.filter((controller: { facility: number; }) => controller.facility <= 0) : null; const vatsimControllerRatings = vatsimData.ratings ? vatsimData.ratings : null; - const vatsimObservers = vatsimAllObservers - ? vatsimAllObservers.filter((observer: { callsign: string | any[] }) => - observer.callsign.includes(callsignSearch), - ) - : null; + const vatsimObservers = vatsimAllObservers ? vatsimAllObservers.filter((observer: { callsign: string | any[]; }) => observer.callsign.includes(callsignSearch)) : null; const { keys }: ObjectConstructor = Object; - const fields: EmbedField[] = [ - ...vatsimObservers.sort((a: { rating: number }, b: { rating: number }) => b.rating - a.rating), - ] - .map((vatsimObserver) => { - const { callsign, logon_time, text_atis, rating } = vatsimObserver; - const logonTime = new Date(logon_time); - const logonTimeString = handleLocaleDateTimeString(logonTime); - const ratingDetail = vatsimControllerRatings.filter((ratingInfo: { id: any }) => ratingInfo.id === rating); - const { short, long } = ratingDetail[0]; - const ratingText = `${short} - ${long}`; - const atisText = text_atis ? text_atis.join('\n') : null; + const fields: EmbedField[] = [...vatsimObservers.sort((a: { rating: number; }, b: { rating: number; }) => b.rating - a.rating)].map((vatsimObserver) => { + const { callsign, logon_time, text_atis, rating } = vatsimObserver; + const logonTime = new Date(logon_time); + const logonTimeString = handleLocaleDateTimeString(logonTime); + const ratingDetail = vatsimControllerRatings.filter((ratingInfo: { id: any; }) => ratingInfo.id === rating); + const { short, long } = ratingDetail[0]; + const ratingText = `${short} - ${long}`; + const atisText = text_atis ? text_atis.join('\n') : null; - return observersListEmbedFields(callsign, logonTimeString, ratingText, atisText); - }) - .slice(0, 5) - .flat(); + return observersListEmbedFields(callsign, logonTimeString, ratingText, atisText); + }).slice(0, 5).flat(); const totalCount = keys(vatsimObservers).length; const shownCount = totalCount < 5 ? totalCount : 5; diff --git a/src/commands/utils/vatsim/functions/vatsimPilots.ts b/src/commands/utils/vatsim/functions/vatsimPilots.ts index 3198413d..e73c6300 100644 --- a/src/commands/utils/vatsim/functions/vatsimPilots.ts +++ b/src/commands/utils/vatsim/functions/vatsimPilots.ts @@ -1,12 +1,13 @@ import { ChatInputCommandInteraction, EmbedField } from 'discord.js'; import { makeEmbed } from '../../../../lib'; -const listEmbed = (type: string, fields: EmbedField[], totalCount: number, shownCount: number, callsign: string) => - makeEmbed({ - title: `VATSIM Data - ${callsign} - ${totalCount} ${type} online`, - description: `A list of ${shownCount} online ${type} matching ${callsign}.`, - fields, - }); +/* eslint-disable camelcase */ + +const listEmbed = (type: string, fields: EmbedField[], totalCount: number, shownCount: number, callsign: string) => makeEmbed({ + title: `VATSIM Data - ${callsign} - ${totalCount} ${type} online`, + description: `A list of ${shownCount} online ${type} matching ${callsign}.`, + fields, +}); const pilotsListEmbedFields = (callsign: string, rating: string, flightPlan: any) => { const fields = [ { @@ -40,35 +41,20 @@ const pilotsListEmbedFields = (callsign: string, rating: string, flightPlan: any return fields; }; -export async function handleVatsimPilots( - interaction: ChatInputCommandInteraction<'cached'>, - vatsimData: any, - callsignSearch: any, -) { +export async function handleVatsimPilots(interaction: ChatInputCommandInteraction<'cached'>, vatsimData: any, callsignSearch: any) { const vatsimPilotRatings = vatsimData.pilot_ratings ? vatsimData.pilot_ratings : null; - const vatsimPilots = vatsimData.pilots - ? vatsimData.pilots.filter((pilot: { callsign: (string | null)[] }) => pilot.callsign.includes(callsignSearch)) - : null; + const vatsimPilots = vatsimData.pilots ? vatsimData.pilots.filter((pilot: { callsign: (string | null)[]; }) => pilot.callsign.includes(callsignSearch)) : null; const { keys }: ObjectConstructor = Object; - const fields: EmbedField[] = [ - ...vatsimPilots.sort( - (a: { pilot_rating: number }, b: { pilot_rating: number }) => b.pilot_rating - a.pilot_rating, - ), - ] - .map((vatsimPilot) => { - const { callsign, pilot_rating, flight_plan } = vatsimPilot; - const ratingDetail = vatsimPilotRatings.filter( - (ratingInfo: { id: number }) => ratingInfo.id === pilot_rating, - ); - const { short_name, long_name } = ratingDetail[0]; - const ratingText = `${short_name} - ${long_name}`; + const fields: EmbedField[] = [...vatsimPilots.sort((a: { pilot_rating: number; }, b: { pilot_rating: number; }) => b.pilot_rating - a.pilot_rating)].map((vatsimPilot) => { + const { callsign, pilot_rating, flight_plan } = vatsimPilot; + const ratingDetail = vatsimPilotRatings.filter((ratingInfo: { id: number; }) => ratingInfo.id === pilot_rating); + const { short_name, long_name } = ratingDetail[0]; + const ratingText = `${short_name} - ${long_name}`; - return pilotsListEmbedFields(callsign, ratingText, flight_plan); - }) - .slice(0, 5) - .flat(); + return pilotsListEmbedFields(callsign, ratingText, flight_plan); + }).slice(0, 5).flat(); const totalCount = keys(vatsimPilots).length; const shownCount = totalCount < 5 ? totalCount : 5; diff --git a/src/commands/utils/vatsim/functions/vatsimStats.ts b/src/commands/utils/vatsim/functions/vatsimStats.ts index 19b065fe..a37c7c82 100644 --- a/src/commands/utils/vatsim/functions/vatsimStats.ts +++ b/src/commands/utils/vatsim/functions/vatsimStats.ts @@ -1,47 +1,36 @@ import { ChatInputCommandInteraction } from 'discord.js'; import { makeEmbed } from '../../../../lib'; -const statsEmbed = (pilots: string, controllers: string, atis: string, observers: string, callsign: any) => - makeEmbed({ - title: callsign ? `VATSIM Data | Statistics for callsign ${callsign}` : 'VATSIM Data | Statistics', - description: callsign - ? `An overview of the current active Pilots, Controllers, ATIS and Observers matching ${callsign}.` - : 'An overview of the current active Pilots, Controllers, ATIS and Observers.', - fields: [ - { - name: 'Pilots', - value: pilots, - inline: true, - }, - { - name: 'Controllers', - value: controllers, - inline: true, - }, - { - name: 'ATIS', - value: atis, - inline: true, - }, - { - name: 'Observers', - value: observers, - inline: true, - }, - ], - }); +const statsEmbed = (pilots: string, controllers: string, atis: string, observers: string, callsign: any) => makeEmbed({ + title: callsign ? `VATSIM Data | Statistics for callsign ${callsign}` : 'VATSIM Data | Statistics', + description: callsign ? `An overview of the current active Pilots, Controllers, ATIS and Observers matching ${callsign}.` : 'An overview of the current active Pilots, Controllers, ATIS and Observers.', + fields: [ + { + name: 'Pilots', + value: pilots, + inline: true, + }, + { + name: 'Controllers', + value: controllers, + inline: true, + }, + { + name: 'ATIS', + value: atis, + inline: true, + }, + { + name: 'Observers', + value: observers, + inline: true, + }, + ], +}); -export async function handleVatsimStats( - interaction: ChatInputCommandInteraction<'cached'>, - vatsimData: any, - callsignSearch: any, -) { - const vatsimAllControllers = vatsimData.controllers - ? vatsimData.controllers.filter((controller: { facility: number }) => controller.facility > 0) - : null; - const vatsimAllObservers = vatsimData.controllers - ? vatsimData.controllers.filter((controller: { facility: number }) => controller.facility <= 0) - : null; +export async function handleVatsimStats(interaction: ChatInputCommandInteraction<'cached'>, vatsimData: any, callsignSearch: any) { + const vatsimAllControllers = vatsimData.controllers ? vatsimData.controllers.filter((controller: { facility: number; }) => controller.facility > 0) : null; + const vatsimAllObservers = vatsimData.controllers ? vatsimData.controllers.filter((controller: { facility: number; }) => controller.facility <= 0) : null; if (!callsignSearch) { const vatsimPilotCount = vatsimData.pilots ? vatsimData.pilots.length : 0; @@ -49,35 +38,17 @@ export async function handleVatsimStats( const vatsimAtisCount = vatsimData.atis ? vatsimData.atis.length : 0; const vatsimObserverCount = vatsimAllObservers ? vatsimAllObservers.length : 0; - return interaction.reply({ - embeds: [statsEmbed(vatsimPilotCount, vatsimControllerCount, vatsimAtisCount, vatsimObserverCount, null)], - }); + return interaction.reply({ embeds: [statsEmbed(vatsimPilotCount, vatsimControllerCount, vatsimAtisCount, vatsimObserverCount, null)] }); } - const vatsimPilots = vatsimData.pilots - ? vatsimData.pilots.filter((pilot: { callsign: string | string[] }) => pilot.callsign.includes(callsignSearch)) - : null; - const vatsimControllers = vatsimAllControllers - ? vatsimAllControllers.filter((controller: { callsign: string | string[] }) => - controller.callsign.includes(callsignSearch), - ) - : null; - const vatsimAtis = vatsimData.atis - ? vatsimData.atis.filter((atis: { callsign: string | string[] }) => atis.callsign.includes(callsignSearch)) - : null; - const vatsimObservers = vatsimAllObservers - ? vatsimAllObservers.filter((observer: { callsign: string | string[] }) => - observer.callsign.includes(callsignSearch), - ) - : null; + const vatsimPilots = vatsimData.pilots ? vatsimData.pilots.filter((pilot: { callsign: string | string[]; }) => pilot.callsign.includes(callsignSearch)) : null; + const vatsimControllers = vatsimAllControllers ? vatsimAllControllers.filter((controller: { callsign: string | string[]; }) => controller.callsign.includes(callsignSearch)) : null; + const vatsimAtis = vatsimData.atis ? vatsimData.atis.filter((atis: { callsign: string | string[]; }) => atis.callsign.includes(callsignSearch)) : null; + const vatsimObservers = vatsimAllObservers ? vatsimAllObservers.filter((observer: { callsign: string | string[]; }) => observer.callsign.includes(callsignSearch)) : null; const vatsimPilotCount = vatsimPilots ? vatsimPilots.length : 0; const vatsimControllerCount = vatsimControllers ? vatsimControllers.length : 0; const vatsimAtisCount = vatsimAtis ? vatsimAtis.length : 0; const vatsimObserverCount = vatsimObservers ? vatsimObservers.length : 0; - return interaction.reply({ - embeds: [ - statsEmbed(vatsimPilotCount, vatsimControllerCount, vatsimAtisCount, vatsimObserverCount, callsignSearch), - ], - }); + return interaction.reply({ embeds: [statsEmbed(vatsimPilotCount, vatsimControllerCount, vatsimAtisCount, vatsimObserverCount, callsignSearch)] }); } diff --git a/src/commands/utils/vatsim/vatsim.ts b/src/commands/utils/vatsim/vatsim.ts index d159efc7..c1511937 100644 --- a/src/commands/utils/vatsim/vatsim.ts +++ b/src/commands/utils/vatsim/vatsim.ts @@ -78,12 +78,11 @@ const data = slashCommandStructure({ ], }); -const fetchErrorEmbed = (error: any) => - makeEmbed({ - title: 'VATSIM Data - Fetching data failure', - description: `Could not fetch the VATSIM data from the VATSIM API service: ${error}`, - color: Colors.Red, - }); +const fetchErrorEmbed = (error: any) => makeEmbed({ + title: 'VATSIM Data - Fetching data failure', + description: `Could not fetch the VATSIM data from the VATSIM API service: ${error}`, + color: Colors.Red, +}); export default slashCommand(data, async ({ interaction }) => { // Fetch VATSIM data @@ -113,10 +112,8 @@ export default slashCommand(data, async ({ interaction }) => { const regexMatches = callsign.match(regexCheck); if (!regexMatches || !regexMatches.groups || !regexMatches.groups.callsignSearch) { - return interaction.reply({ - content: 'You need to provide a valid callsign or part of a callsign to search for', - ephemeral: true, - }); + // eslint-disable-next-line consistent-return + return interaction.reply({ content: 'You need to provide a valid callsign or part of a callsign to search for', ephemeral: true }); } callsignSearch = regexMatches.groups.callsignSearch; @@ -127,23 +124,23 @@ export default slashCommand(data, async ({ interaction }) => { const subcommandName = interaction.options.getSubcommand(); switch (subcommandName) { - case 'stats': - await handleVatsimStats(interaction, vatsimData, callsignSearch); - break; - case 'controllers': - await handleVatsimControllers(interaction, vatsimData, callsignSearch); - break; - case 'pilots': - await handleVatsimPilots(interaction, vatsimData, callsignSearch); - break; - case 'observers': - await handleVatsimObservers(interaction, vatsimData, callsignSearch); - break; - case 'events': - await handleVatsimEvents(interaction); - break; + case 'stats': + await handleVatsimStats(interaction, vatsimData, callsignSearch); + break; + case 'controllers': + await handleVatsimControllers(interaction, vatsimData, callsignSearch); + break; + case 'pilots': + await handleVatsimPilots(interaction, vatsimData, callsignSearch); + break; + case 'observers': + await handleVatsimObservers(interaction, vatsimData, callsignSearch); + break; + case 'events': + await handleVatsimEvents(interaction); + break; - default: - await interaction.reply({ content: 'Unknown subcommand', ephemeral: true }); + default: + await interaction.reply({ content: 'Unknown subcommand', ephemeral: true }); } }); diff --git a/src/commands/utils/wolframAlpha.ts b/src/commands/utils/wolframAlpha.ts index 36b83e6a..71ed2744 100644 --- a/src/commands/utils/wolframAlpha.ts +++ b/src/commands/utils/wolframAlpha.ts @@ -5,14 +5,12 @@ const data = slashCommandStructure({ name: 'wolframalpha', description: 'Queries the Wolfram Alpha API.', type: ApplicationCommandType.ChatInput, - options: [ - { - name: 'query', - description: 'Please provide a query. For example: `.wa How much is 1 + 1?`.', - type: ApplicationCommandOptionType.String, - required: true, - }, - ], + options: [{ + name: 'query', + description: 'Please provide a query. For example: `.wa How much is 1 + 1?`.', + type: ApplicationCommandOptionType.String, + required: true, + }], }); const noQueryEmbed = makeEmbed({ @@ -52,7 +50,8 @@ export default slashCommand(data, async ({ interaction }) => { const searchParams = new URLSearchParams(params); try { - const response = await fetch(`${WOLFRAMALPHA_API_URL}${searchParams.toString()}`).then((res) => res.json()); + const response = await fetch(`${WOLFRAMALPHA_API_URL}${searchParams.toString()}`) + .then((res) => res.json()); if (response.error) { const errorEmbed = makeEmbed({ @@ -94,14 +93,18 @@ export default slashCommand(data, async ({ interaction }) => { } const noResultsEmbed = makeEmbed({ title: 'Wolfram Alpha Error | No Results', - description: makeLines(['No results were found for your query.']), + description: makeLines([ + 'No results were found for your query.', + ]), color: Colors.Red, }); return interaction.followUp({ embeds: [noResultsEmbed], ephemeral: true }); } const obscureQueryEmbed = makeEmbed({ title: 'Wolfram Alpha Error | Could not understand query', - description: makeLines(['Wolfram Alpha could not understand your query.']), + description: makeLines([ + 'Wolfram Alpha could not understand your query.', + ]), color: Colors.Red, }); return interaction.followUp({ embeds: [obscureQueryEmbed], ephemeral: true }); diff --git a/src/commands/utils/zulu.ts b/src/commands/utils/zulu.ts index 22557283..74575a05 100644 --- a/src/commands/utils/zulu.ts +++ b/src/commands/utils/zulu.ts @@ -6,14 +6,12 @@ const data = slashCommandStructure({ name: 'zulu', description: 'Get the current time at a given UTC-offset timezone.', type: ApplicationCommandType.ChatInput, - options: [ - { - name: 'offset', - description: 'Please provide a timezone within UTC-12 and UTC+14.', - type: ApplicationCommandOptionType.String, - required: false, - }, - ], + options: [{ + name: 'offset', + description: 'Please provide a timezone within UTC-12 and UTC+14.', + type: ApplicationCommandOptionType.String, + required: false, + }], }); const dateFormat = 'HH:mm (LT)'; @@ -25,10 +23,15 @@ export default slashCommand(data, async ({ interaction }) => { const numericOffset = parseInt(utcOffset); const sign = utcOffset.startsWith('-') ? '-' : '+'; - if (Number.isNaN(numericOffset) || numericOffset < -12 || numericOffset > 14) { + if (Number.isNaN(numericOffset) + || numericOffset < -12 + || numericOffset > 14) { const invalidEmbed = makeEmbed({ title: 'Zulu Error | Invalid Offset', - description: makeLines(['Please provide a timezone within UTC-12 and UTC+14.', 'For example: `/zulu -5`.']), + description: makeLines([ + 'Please provide a timezone within UTC-12 and UTC+14.', + 'For example: `/zulu -5`.', + ]), color: Colors.Red, }); return interaction.reply({ embeds: [invalidEmbed], ephemeral: true }); @@ -36,7 +39,5 @@ export default slashCommand(data, async ({ interaction }) => { const formattedOffset = `${sign}${Math.abs(numericOffset)}`; - return interaction.reply({ - content: `It is ${moment().utc().add(utcOffset, 'hours').format(dateFormat)} in that timezone (UTC${formattedOffset}).`, - }); + return interaction.reply({ content: `It is ${moment().utc().add(utcOffset, 'hours').format(dateFormat)} in that timezone (UTC${formattedOffset}).` }); }); diff --git a/src/events/buttonHandlers/buttonHandler.ts b/src/events/buttonHandlers/buttonHandler.ts index 65000dc9..c2cdac81 100644 --- a/src/events/buttonHandlers/buttonHandler.ts +++ b/src/events/buttonHandlers/buttonHandler.ts @@ -14,22 +14,18 @@ export default event(Events.InteractionCreate, async ({ log }, interaction) => { const [prefix, ...params] = interaction.customId.split('_'); switch (prefix) { - case 'roleAssignment': - const [roleID] = params; - await handleRoleAssignment(interaction, roleID); - log(`Button Handler: Role assignment button pressed by ${user.tag} (${user.id}). roleID: ${roleID}`); - break; - default: - if (buttonLabel) { - log( - `Button Handler: Custom ID not matched. Skipping...\nCustom ID: ${customId}, Label: ${buttonLabel}, User: ${user.tag}, User ID: ${user.id}`, - ); - } else { - log( - `Button Handler: Custom ID not matched. Skipping...\nCustom ID: ${customId}, Label: null, User: ${user.tag}, User ID: ${user.id}`, - ); - } - return; + case 'roleAssignment': + const [roleID] = params; + await handleRoleAssignment(interaction, roleID); + log(`Button Handler: Role assignment button pressed by ${user.tag} (${user.id}). roleID: ${roleID}`); + break; + default: + if (buttonLabel) { + log(`Button Handler: Custom ID not matched. Skipping...\nCustom ID: ${customId}, Label: ${buttonLabel}, User: ${user.tag}, User ID: ${user.id}`); + } else { + log(`Button Handler: Custom ID not matched. Skipping...\nCustom ID: ${customId}, Label: null, User: ${user.tag}, User ID: ${user.id}`); + } + return; } } catch (error) { log('Button Handler: Error handling button press', error); diff --git a/src/events/buttonHandlers/functions/handleRoleAssignment.ts b/src/events/buttonHandlers/functions/handleRoleAssignment.ts index 7d91d2e7..53233829 100644 --- a/src/events/buttonHandlers/functions/handleRoleAssignment.ts +++ b/src/events/buttonHandlers/functions/handleRoleAssignment.ts @@ -14,7 +14,7 @@ export async function handleRoleAssignment(interaction: ButtonInteraction, roleI if (!role) { Logger.error('Role Assignment: Role not found'); - interaction.editReply({ content: "I couldn't find that role" }); + interaction.editReply({ content: 'I couldn\'t find that role' }); return; } @@ -36,9 +36,6 @@ export async function handleRoleAssignment(interaction: ButtonInteraction, roleI } } catch (error) { Logger.error(error); - await interaction.editReply({ - content: - 'Something went wrong, this role may no longer exist. Please try again. The error message has been logged.', - }); + await interaction.editReply({ content: 'Something went wrong, this role may no longer exist. Please try again. The error message has been logged.' }); } } diff --git a/src/events/contextInteractionHandler.ts b/src/events/contextInteractionHandler.ts index 47728c45..d8afd555 100644 --- a/src/events/contextInteractionHandler.ts +++ b/src/events/contextInteractionHandler.ts @@ -1,7 +1,9 @@ import { Color, ContextMenuCommand, event, Events, makeEmbed, Reply } from '../lib'; import contextArray from '../commands/context'; -const contextMap = new Map(contextArray.map((c) => [c.meta.name, c])); +const contextMap = new Map( + contextArray.map((c) => [c.meta.name, c]), +); export default event(Events.InteractionCreate, async ({ log, client }, interaction) => { if (!interaction.isContextMenuCommand()) { @@ -9,7 +11,9 @@ export default event(Events.InteractionCreate, async ({ log, client }, interacti } if (!interaction.inCachedGuild()) { - await interaction.reply(Reply('This bot can only be used in a server!', Color.Error)); + await interaction.reply( + Reply('This bot can only be used in a server!', Color.Error), + ); return; } diff --git a/src/events/logging/detectBan.ts b/src/events/logging/detectBan.ts index 46e24ef1..d9ae940a 100644 --- a/src/events/logging/detectBan.ts +++ b/src/events/logging/detectBan.ts @@ -8,96 +8,93 @@ import { constantsConfig, event, Events, Infraction, Logger, makeEmbed, makeLine const MAX_RETRIES = 5; const SLEEP_TIMER = 0.5 * 1000; -const noLogEmbed = (user: User, guildName: string) => - makeEmbed({ - color: Colors.Red, - author: { - name: `[BANNED] ${user.tag}`, - iconURL: user.displayAvatarURL(), +const noLogEmbed = (user: User, guildName: string) => makeEmbed({ + color: Colors.Red, + author: { + name: `[BANNED] ${user.tag}`, + iconURL: user.displayAvatarURL(), + }, + description: makeLines([ + `${user.tag} was banned from ${guildName} but no audit log could be found.`, + '', + bold('NOTE - This was a non bot ban.'), + '', + `Please remember to send the user the reason they were banned and the ban appeal form - ${process.env.BAN_APPEAL_URL}`, + ]), + footer: { text: `User ID: ${user.id}` }, +}); + +const modLogEmbed = (user: User, executor: User, reason: string, formattedDate: string) => makeEmbed({ + color: Colors.Red, + author: { + name: `[BANNED] ${user.tag}`, + iconURL: user.displayAvatarURL(), + }, + description: makeLines([ + bold('NOTE - This was a non bot ban.'), + '', + `Please remember to send the user the reason they were banned and the ban appeal form - ${process.env.BAN_APPEAL_URL}`, + ]), + fields: [ + { + name: 'User', + value: `${user}`, + }, + { + name: 'Moderator', + value: `${executor}`, + }, + { + name: 'Reason', + value: reason || 'No reason provided', + }, + { + name: 'Days of messages deleted', + value: 'Unavailable with a non bot ban', + }, + { + name: 'Date', + value: formattedDate, + }, + ], + footer: { text: `User ID: ${user.id}` }, +}); + +const userBannedIncompleteEmbed = (user: User, formattedDate: string) => makeEmbed({ + color: Colors.Red, + author: { + name: `[BANNED] ${user.tag}`, + iconURL: user.displayAvatarURL(), + }, + description: makeLines([ + bold('NOTE - This was a non bot ban.'), + '', + `Please remember to send the user the reason they were banned and the ban appeal form - ${process.env.BAN_APPEAL_URL}`, + ]), + fields: [ + { + name: 'Member', + value: user.tag, + }, + { + name: 'Moderator', + value: 'Unavailable - Audit log incomplete', + }, + { + name: 'Reason', + value: 'Unavailable - Audit log incomplete', }, - description: makeLines([ - `${user.tag} was banned from ${guildName} but no audit log could be found.`, - '', - bold('NOTE - This was a non bot ban.'), - '', - `Please remember to send the user the reason they were banned and the ban appeal form - ${process.env.BAN_APPEAL_URL}`, - ]), - footer: { text: `User ID: ${user.id}` }, - }); - -const modLogEmbed = (user: User, executor: User, reason: string, formattedDate: string) => - makeEmbed({ - color: Colors.Red, - author: { - name: `[BANNED] ${user.tag}`, - iconURL: user.displayAvatarURL(), + { + name: 'Days of messages deleted', + value: 'Unavailable with a non bot ban', }, - description: makeLines([ - bold('NOTE - This was a non bot ban.'), - '', - `Please remember to send the user the reason they were banned and the ban appeal form - ${process.env.BAN_APPEAL_URL}`, - ]), - fields: [ - { - name: 'User', - value: `${user}`, - }, - { - name: 'Moderator', - value: `${executor}`, - }, - { - name: 'Reason', - value: reason || 'No reason provided', - }, - { - name: 'Days of messages deleted', - value: 'Unavailable with a non bot ban', - }, - { - name: 'Date', - value: formattedDate, - }, - ], - footer: { text: `User ID: ${user.id}` }, - }); - -const userBannedIncompleteEmbed = (user: User, formattedDate: string) => - makeEmbed({ - color: Colors.Red, - author: { - name: `[BANNED] ${user.tag}`, - iconURL: user.displayAvatarURL(), + { + name: 'Date', + value: formattedDate, }, - description: makeLines([ - bold('NOTE - This was a non bot ban.'), - '', - `Please remember to send the user the reason they were banned and the ban appeal form - ${process.env.BAN_APPEAL_URL}`, - ]), - fields: [ - { - name: 'Member', - value: user.tag, - }, - { - name: 'Moderator', - value: 'Unavailable - Audit log incomplete', - }, - { - name: 'Reason', - value: 'Unavailable - Audit log incomplete', - }, - { - name: 'Days of messages deleted', - value: 'Unavailable with a non bot ban', - }, - { - name: 'Date', - value: formattedDate, - }, - ], - footer: { text: `User ID: ${user.id}` }, - }); + ], + footer: { text: `User ID: ${user.id}` }, +}); const logFailed = makeEmbed({ title: 'Non Bot Ban - Failed to log', @@ -108,21 +105,23 @@ const logFailed = makeEmbed({ export default event(Events.GuildBanAdd, async (_, msg) => { Logger.debug('Starting Ban Handler'); - const guildBanAdd = msg; + const guildBanAdd = msg as GuildBan; if (guildBanAdd.guild === null) { // DMs return; } - const modLogsChannel = await guildBanAdd.guild.channels.resolve(constantsConfig.channels.MOD_LOGS); + const modLogsChannel = await guildBanAdd.guild.channels.resolve(constantsConfig.channels.MOD_LOGS) as TextChannel | null; if (!modLogsChannel) { // Exit as can't post return; } const currentDate = new Date(); - const formattedDate: string = moment(currentDate).utcOffset(0).format(); + const formattedDate: string = moment(currentDate) + .utcOffset(0) + .format(); let executor; let reason; @@ -131,9 +130,10 @@ export default event(Events.GuildBanAdd, async (_, msg) => { do { Logger.debug(`Ban Handler - Finding Audit Log entry retries left: ${retryCount}`); if (retryCount < MAX_RETRIES) { + // eslint-disable-next-line no-await-in-loop await new Promise((f) => setTimeout(f, SLEEP_TIMER)); } - + // eslint-disable-next-line no-await-in-loop const fetchedLogs = await guildBanAdd.guild.fetchAuditLogs({ limit: 1, type: AuditLogEvent.MemberBanAdd, @@ -144,7 +144,8 @@ export default event(Events.GuildBanAdd, async (_, msg) => { } retryCount--; - } while ((!target || target.id !== guildBanAdd.user.id) && retryCount > 0); + } + while ((!target || target.id !== guildBanAdd.user.id) && retryCount > 0); if (!target) { await modLogsChannel.send({ embeds: [noLogEmbed(guildBanAdd.user, guildBanAdd.guild.name)] }); @@ -155,10 +156,7 @@ export default event(Events.GuildBanAdd, async (_, msg) => { return; } if (executor && !constantsConfig.modLogExclude.includes(executor.id)) { - await modLogsChannel.send({ - content: executor.toString(), - embeds: [modLogEmbed(guildBanAdd.user, executor, reason as string, formattedDate)], - }); + await modLogsChannel.send({ content: executor.toString(), embeds: [modLogEmbed(guildBanAdd.user, executor, reason as string, formattedDate)] }); //Log to the DB Logger.info('Starting Infraction process'); diff --git a/src/events/logging/messageDelete.ts b/src/events/logging/messageDelete.ts index a02711c4..74215e10 100644 --- a/src/events/logging/messageDelete.ts +++ b/src/events/logging/messageDelete.ts @@ -7,12 +7,12 @@ const CONTENT_NOT_AVAIL = 'Unable to find content or embeds.'; export default event(Events.MessageDelete, async (_, msg) => { try { if (msg.guild === null || msg.author === null) { - // DMs + // DMs return; } if (msg.content === null || msg.content.trim() === '') { - // Old Message or empty content + // Old Message or empty content return; } @@ -22,8 +22,10 @@ export default event(Events.MessageDelete, async (_, msg) => { }); const deletionLog = fetchedLogs.entries.first(); const currentDate = new Date(); - const formattedDate: string = moment(currentDate).utcOffset(0).format('DD, MM, YYYY, HH:mm:ss'); - const userLogsChannel = msg.guild.channels.resolve(constantsConfig.channels.USER_LOGS); + const formattedDate: string = moment(currentDate) + .utcOffset(0) + .format('DD, MM, YYYY, HH:mm:ss'); + const userLogsChannel = msg.guild.channels.resolve(constantsConfig.channels.USER_LOGS) as TextChannel | null; const messageEmbeds = msg.embeds.length > 0 ? msg.embeds : []; const messageComponents = []; if (msg.content) { @@ -91,10 +93,7 @@ export default event(Events.MessageDelete, async (_, msg) => { }, { name: 'Deleted by', - value: - deletionLog && deletionLog.target.id === msg.author.id - ? `${deletionLog.executor}` - : 'No audit log was found, message was either deleted by author, or a bot', + value: (deletionLog && deletionLog.target.id === msg.author.id) ? `${deletionLog.executor}` : 'No audit log was found, message was either deleted by author, or a bot', inline: false, }, { @@ -106,7 +105,7 @@ export default event(Events.MessageDelete, async (_, msg) => { footer: { text: `User ID: ${msg.author.id}` }, }); - if (userLogsChannel && !constantsConfig.userLogExclude.includes(msg.author.id)) { + if (userLogsChannel && !constantsConfig.userLogExclude.includes(msg.author!.id)) { await userLogsChannel.send({ embeds: [messageDeleteEmbed] }); } } catch (error) { diff --git a/src/events/logging/messageUpdate.ts b/src/events/logging/messageUpdate.ts index 34d76b98..11d509a5 100644 --- a/src/events/logging/messageUpdate.ts +++ b/src/events/logging/messageUpdate.ts @@ -1,17 +1,17 @@ import { Colors, TextChannel } from 'discord.js'; import { constantsConfig, event, Events, imageBaseUrl, Logger, makeEmbed } from '../../lib'; -const FEATURE_NOT_AVAIL = "(can't show embeds or images)"; +const FEATURE_NOT_AVAIL = '(can\'t show embeds or images)'; export default event(Events.MessageUpdate, async (_, oldMessage, newMessage) => { try { if (oldMessage.guild === null || oldMessage.author === null || newMessage.author === null) { - // DMs + // DMs return; } if (oldMessage.content === null) { - // Old Message + // Old Message return; } @@ -20,7 +20,7 @@ export default event(Events.MessageUpdate, async (_, oldMessage, newMessage) => return; } - const userLogsChannel = oldMessage.guild.channels.resolve(constantsConfig.channels.USER_LOGS); + const userLogsChannel = oldMessage.guild.channels.resolve(constantsConfig.channels.USER_LOGS) as TextChannel | null; const MAX_MESSAGE_LENGTH = 1024; @@ -40,7 +40,7 @@ export default event(Events.MessageUpdate, async (_, oldMessage, newMessage) => editedMessageFieldTitle = 'Edited Message (truncated)'; } - if (userLogsChannel && !constantsConfig.userLogExclude.includes(oldMessage.author.id)) { + if (userLogsChannel && !constantsConfig.userLogExclude.includes(oldMessage.author!.id)) { const messageUpdateEmbed = makeEmbed({ color: Colors.Orange, thumbnail: { url: `${imageBaseUrl}/moderation/message_edited.png` }, @@ -51,16 +51,8 @@ export default event(Events.MessageUpdate, async (_, oldMessage, newMessage) => fields: [ { name: 'Author', value: `${oldMessage.author}`, inline: true }, { name: 'Channel', value: `${oldMessage.channel}`, inline: true }, - { - name: originalMessageFieldTitle, - value: oldMessageContent ? `\`\`\`${oldMessageContent}\`\`\`` : FEATURE_NOT_AVAIL, - inline: false, - }, - { - name: editedMessageFieldTitle, - value: newMessageContent ? `\`\`\`${newMessageContent}\`\`\`` : FEATURE_NOT_AVAIL, - inline: false, - }, + { name: originalMessageFieldTitle, value: oldMessageContent ? `\`\`\`${oldMessageContent}\`\`\`` : FEATURE_NOT_AVAIL, inline: false }, + { name: editedMessageFieldTitle, value: newMessageContent ? `\`\`\`${newMessageContent}\`\`\`` : FEATURE_NOT_AVAIL, inline: false }, ], footer: { text: `User ID: ${oldMessage.author.id}` }, }); diff --git a/src/events/logging/scamLogs.ts b/src/events/logging/scamLogs.ts index 625ee389..1b2cb265 100644 --- a/src/events/logging/scamLogs.ts +++ b/src/events/logging/scamLogs.ts @@ -1,16 +1,6 @@ import { codeBlock, Colors, DMChannel, TextChannel } from 'discord.js'; import mongoose from 'mongoose'; -import { - constantsConfig, - makeEmbed, - makeLines, - event, - Events, - getConn, - Infraction, - Logger, - imageBaseUrl, -} from '../../lib'; +import { constantsConfig, makeEmbed, makeLines, event, Events, getConn, Infraction, Logger, imageBaseUrl } from '../../lib'; const excludedRoles = [ constantsConfig.roles.ADMIN_TEAM, @@ -45,7 +35,7 @@ export default event(Events.MessageCreate, async ({ log }, msg) => { return; } - const scamReportLogs = msg.guild.channels.resolve(constantsConfig.channels.SCAM_REPORT_LOGS); + const scamReportLogs = msg.guild.channels.resolve(constantsConfig.channels.SCAM_REPORT_LOGS) as TextChannel | null; if (scamReportLogs && msg.content.toLowerCase().includes('@everyone') && !msg.author.bot) { const conn = getConn(); if (!conn && scamReportLogs) { @@ -153,9 +143,7 @@ export default event(Events.MessageCreate, async ({ log }, msg) => { } // Try and send a DM try { - await msg.author.send( - 'We have detected use of @everyone in one of our text channels. This function is in place to prevent discord scams and has resulted in an automatic timeout and notification of our moderation team. If this was done in error, our moderation team will reverse the timeout, however please refrain from using the @everyone ping in future.', - ); + await msg.author.send('We have detected use of @everyone in one of our text channels. This function is in place to prevent discord scams and has resulted in an automatic timeout and notification of our moderation team. If this was done in error, our moderation team will reverse the timeout, however please refrain from using the @everyone ping in future.'); } catch (e) { log(e); diff --git a/src/events/ready.ts b/src/events/ready.ts index 7b7a54fa..d907af85 100644 --- a/src/events/ready.ts +++ b/src/events/ready.ts @@ -1,6 +1,15 @@ import { ActivityType, TextChannel } from 'discord.js'; import moment from 'moment'; -import { constantsConfig, event, Events, connect, setupScheduler, Logger, imageBaseUrl, getScheduler } from '../lib'; +import { + constantsConfig, + event, + Events, + connect, + setupScheduler, + Logger, + imageBaseUrl, + getScheduler, +} from '../lib'; import { deployCommands } from '../scripts/deployCommands'; import commandArray from '../commands'; import contextArray from '../commands/context'; @@ -26,16 +35,16 @@ export default event(Events.ClientReady, async ({ log }, client) => { if (process.env.DEPLOY === 'true') { log('DEPLOY variable set to true, deploying commands and contexts.'); try { - await deployCommands(commandArray, contextArray).then(async (user) => { - const bot = `<@${user.id}>`; + await deployCommands(commandArray, contextArray) + .then(async (user) => { + const bot = `<@${user.id}>`; - const response = - process.env.NODE_ENV === 'production' + const response = process.env.NODE_ENV === 'production' ? `Deployed ${commandArray.length} commands and ${contextArray.length} contexts globally as ${bot}!` : `Deployed ${commandArray.length} commands and ${contextArray.length} contexts to \`<@${constantsConfig.guildId}>\` as ${bot}!`; - log(response); - }); + log(response); + }); } catch (error) { log('Failed to deploy commands:', error); } @@ -72,18 +81,14 @@ export default event(Events.ClientReady, async ({ log }, client) => { if (scheduler) { const heartbeatJobList = await scheduler.jobs({ name: 'sendHeartbeat' }); if (heartbeatJobList.length === 0) { - scheduler.every(`${process.env.HEARTBEAT_INTERVAL} seconds`, 'sendHeartbeat', { - interval: process.env.HEARTBEAT_INTERVAL, - }); + scheduler.every(`${process.env.HEARTBEAT_INTERVAL} seconds`, 'sendHeartbeat', { interval: process.env.HEARTBEAT_INTERVAL }); Logger.info(`Heartbeat job scheduled with interval ${process.env.HEARTBEAT_INTERVAL}`); } else { const heartbeatJob = heartbeatJobList[0]; const { interval } = heartbeatJob.attrs.data as { interval: string }; if (interval !== process.env.HEARTBEAT_INTERVAL) { await scheduler.cancel({ name: 'sendHeartbeat' }); - scheduler.every(`${process.env.HEARTBEAT_INTERVAL} seconds`, 'sendHeartbeat', { - interval: process.env.HEARTBEAT_INTERVAL, - }); + scheduler.every(`${process.env.HEARTBEAT_INTERVAL} seconds`, 'sendHeartbeat', { interval: process.env.HEARTBEAT_INTERVAL }); Logger.info(`Heartbeat job rescheduled with new interval ${process.env.HEARTBEAT_INTERVAL}`); } else { Logger.info('Heartbeat job already scheduled'); @@ -98,18 +103,14 @@ export default event(Events.ClientReady, async ({ log }, client) => { if (scheduler) { const birthdayJobList = await scheduler.jobs({ name: 'postBirthdays' }); if (birthdayJobList.length === 0) { - scheduler.every(`${process.env.BIRTHDAY_INTERVAL} seconds`, 'postBirthdays', { - interval: process.env.BIRTHDAY_INTERVAL, - }); + scheduler.every(`${process.env.BIRTHDAY_INTERVAL} seconds`, 'postBirthdays', { interval: process.env.BIRTHDAY_INTERVAL }); Logger.info(`Birthday job scheduled with interval ${process.env.BIRTHDAY_INTERVAL}`); } else { const birthdayJob = birthdayJobList[0]; const { interval } = birthdayJob.attrs.data as { interval: string }; if (interval !== process.env.BIRTHDAY_INTERVAL) { await scheduler.cancel({ name: 'postBirthdays' }); - scheduler.every(`${process.env.BIRTHDAY_INTERVAL} seconds`, 'postBirthdays', { - interval: process.env.BIRTHDAY_INTERVAL, - }); + scheduler.every(`${process.env.BIRTHDAY_INTERVAL} seconds`, 'postBirthdays', { interval: process.env.BIRTHDAY_INTERVAL }); Logger.info(`Birthday job rescheduled with new interval ${process.env.BIRTHDAY_INTERVAL}`); } else { Logger.info('Birthday job already scheduled'); @@ -122,7 +123,9 @@ export default event(Events.ClientReady, async ({ log }, client) => { const botDevChannel = client.channels.resolve(constantsConfig.channels.MOD_LOGS) as TextChannel; if (botDevChannel) { const currentDate = new Date(); - const formattedDate = moment(currentDate).utcOffset(0).format(); + const formattedDate = moment(currentDate) + .utcOffset(0) + .format(); // Include the database connection and scheduler status in the mod logs message. let logMessage = `<@&${constantsConfig.roles.BOT_DEVELOPER}>\n[${formattedDate}] - ${client.user?.username} has connected! - DB State: ${dbConnected ? 'Connected' : 'Disconnected'}`; diff --git a/src/events/slashCommandHandler.ts b/src/events/slashCommandHandler.ts index 513acbc3..0d6edaf0 100644 --- a/src/events/slashCommandHandler.ts +++ b/src/events/slashCommandHandler.ts @@ -1,6 +1,8 @@ import { Color, SlashCommand, event, Events, Reply, makeEmbed } from '../lib'; import commandArray from '../commands'; +/* eslint-disable no-underscore-dangle */ + const commandMap = new Map(); for (const cmd of commandArray) { @@ -13,12 +15,14 @@ export default event(Events.InteractionCreate, async ({ log, client }, interacti } if (!interaction.inCachedGuild()) { - await interaction.reply(Reply('This bot can only be used in a server!', Color.Error)); + await interaction.reply( + Reply('This bot can only be used in a server!', Color.Error), + ); return; } try { - const { commandName, options } = interaction as { + const { commandName, options } = interaction as{ commandName: any; options: any; }; diff --git a/src/lib/config.ts b/src/lib/config.ts index 8fb45900..7a9e9760 100644 --- a/src/lib/config.ts +++ b/src/lib/config.ts @@ -8,8 +8,8 @@ const imageBaseUrl = originalBaseUrl.endsWith('/') ? originalBaseUrl.slice(0, -1 export { imageBaseUrl }; interface roleAssignmentId { - group: string; - roles: { id: string; label: string }[]; + group: string, + roles: { id: string, label: string}[] } // Config constants that are directly used in code should be mandatory, @@ -19,62 +19,62 @@ interface roleAssignmentId { // not mandatory, as they can be dynamic. interface Config { aircraftTypeList: { - [x: string]: string; - }; + [x: string]: string, + }, channels: { - A32NX_SUPPORT: string; - FAQ: string; - FLIGHT_SCHOOL: string; - KNOWN_ISSUES: string; - MOD_ALERTS: string; - MOD_LOGS: string; - ROLES: string; - SCAM_REPORT_LOGS: string; - TEAM: string; - USER_LOGS: string; - VIDEOS: string; - [x: string]: string; - }; + A32NX_SUPPORT: string, + FAQ: string, + FLIGHT_SCHOOL: string, + KNOWN_ISSUES: string, + MOD_ALERTS: string, + MOD_LOGS: string, + ROLES: string, + SCAM_REPORT_LOGS: string, + TEAM: string, + USER_LOGS: string, + VIDEOS: string, + [x: string]: string, + }, colors: { - FBW_CYAN: string; - [x: string]: string; - }; + FBW_CYAN: string, + [x: string]: string, + }, commandPermission: { - MANAGE_SERVER: string; - [x: string]: string; - }; - guildId: string; - modLogExclude: string[]; - roleAssignmentIds: roleAssignmentId[]; + MANAGE_SERVER: string, + [x: string]: string, + }, + guildId: string, + modLogExclude: string[], + roleAssignmentIds: roleAssignmentId[], roleGroups: { - [x: string]: string[]; - }; + [x: string]: string[], + }, roles: { - ADMIN_TEAM: string; - BOT_DEVELOPER: string; - COMMUNITY_SUPPORT: string; - DEVELOPMENT_TEAM: string; - FBW_EMERITUS: string; - MEDIA_TEAM: string; - MODERATION_TEAM: string; - [x: string]: string; - }; + ADMIN_TEAM: string, + BOT_DEVELOPER: string, + COMMUNITY_SUPPORT: string, + DEVELOPMENT_TEAM: string, + FBW_EMERITUS: string, + MEDIA_TEAM: string, + MODERATION_TEAM: string, + [x: string]: string, + }, threads: { - BIRTHDAY_THREAD: string; - COUNT_THREAD: string; - [x: string]: string; - }; + BIRTHDAY_THREAD: string, + COUNT_THREAD: string, + [x: string]: string, + }, units: { - CELSIUS: string; - DEGREES: string; - [x: string]: string; - }; - userLogExclude: string[]; + CELSIUS: string, + DEGREES: string, + [x: string]: string, + }, + userLogExclude: string[], } let parsedConfig: Config; try { - parsedConfig = botConfig as unknown as Config; + parsedConfig = (botConfig as unknown as Config); if (!parsedConfig.commandPermission.MANAGE_SERVER) { // Making sure this is always set, even if an empty string is given parsedConfig.commandPermission.MANAGE_SERVER = '32'; diff --git a/src/lib/contextMenuCommand.ts b/src/lib/contextMenuCommand.ts index 6b1856bb..33051c80 100644 --- a/src/lib/contextMenuCommand.ts +++ b/src/lib/contextMenuCommand.ts @@ -2,8 +2,7 @@ import { Awaitable, Client, ContextMenuCommandBuilder, - RESTPostAPIApplicationCommandsJSONBody, - ContextMenuCommandInteraction, + RESTPostAPIApplicationCommandsJSONBody, ContextMenuCommandInteraction, } from 'discord.js'; import { LogMethods } from './index'; @@ -15,7 +14,9 @@ export interface ContextMenuCommandProps { export type ContextMenuCommandCallback = (props: ContextMenuCommandProps) => Awaitable; -export type ContextMenuCommandStructure = ContextMenuCommandBuilder | RESTPostAPIApplicationCommandsJSONBody; +export type ContextMenuCommandStructure = + | ContextMenuCommandBuilder + | RESTPostAPIApplicationCommandsJSONBody export interface ContextMenuCommand { meta: ContextMenuCommandStructure; @@ -26,9 +27,6 @@ export function contextMenuCommandStructure(data: RESTPostAPIApplicationCommands return data; } -export function contextMenuCommand( - meta: ContextMenuCommandStructure, - callback: ContextMenuCommandCallback, -): ContextMenuCommand { +export function contextMenuCommand(meta: ContextMenuCommandStructure, callback: ContextMenuCommandCallback): ContextMenuCommand { return { meta, callback }; } diff --git a/src/lib/durationInEnglish.ts b/src/lib/durationInEnglish.ts index fcade0af..1b15515a 100644 --- a/src/lib/durationInEnglish.ts +++ b/src/lib/durationInEnglish.ts @@ -3,12 +3,10 @@ export function durationInEnglish(milliseconds: any) { if (seconds < 60) { return `${Math.floor(seconds)} second${Math.floor(seconds) === 1 ? '' : 's'}`; - } - if (seconds < 3600) { + } if (seconds < 3600) { const minutes = seconds / 60; return `${Math.floor(minutes)} minute${Math.floor(minutes) === 1 ? '' : 's'}`; - } - if (seconds < 86400) { + } if (seconds < 86400) { const hours = seconds / 3600; return `${Math.floor(hours)} hour${Math.floor(hours) === 1 ? '' : 's'}`; } diff --git a/src/lib/embed.ts b/src/lib/embed.ts index e1d17a9d..5d3f3155 100644 --- a/src/lib/embed.ts +++ b/src/lib/embed.ts @@ -16,11 +16,11 @@ export function makeLines(lines: string[]): string { export const makeList = (lines: string[], type?: ListTypes): string => { switch (type) { - case 'bullet': - return lines.map((line) => `• ${line}`).join('\n'); - case 'ordered': - return lines.map((line, index) => `${index + 1}. ${line}`).join('\n'); - default: - return lines.map((line) => `- ${line}`).join('\n'); + case 'bullet': + return lines.map((line) => `• ${line}`).join('\n'); + case 'ordered': + return lines.map((line, index) => `${index + 1}. ${line}`).join('\n'); + default: + return lines.map((line) => `- ${line}`).join('\n'); } }; diff --git a/src/lib/events.ts b/src/lib/events.ts index b3240f29..cc3e23a4 100644 --- a/src/lib/events.ts +++ b/src/lib/events.ts @@ -11,7 +11,10 @@ export interface EventProps { log: LogMethods; } -export type EventCallback = (props: EventProps, ...args: ClientEvents[T]) => Awaitable; +export type EventCallback = ( + props: EventProps, + ...args: ClientEvents[T] +) => Awaitable; export interface Event { key: T; @@ -25,6 +28,7 @@ export function event(key: T, callback: EventCallback): export function registerEvents(client: Client, events: Event[]): void { for (const { key, callback } of events) { client.on(key, (...args) => { + // eslint-disable-next-line no-console const log = console.log.bind(Logger, `[Event: ${key}]`); try { diff --git a/src/lib/genericEmbedPagination.ts b/src/lib/genericEmbedPagination.ts index e3422c6d..e1024331 100644 --- a/src/lib/genericEmbedPagination.ts +++ b/src/lib/genericEmbedPagination.ts @@ -1,20 +1,6 @@ -import { - ActionRowBuilder, - ButtonBuilder, - ButtonInteraction, - ButtonStyle, - CommandInteraction, - ComponentType, - EmbedBuilder, - Interaction, - InteractionResponse, - Message, -} from 'discord.js'; +import { ActionRowBuilder, ButtonBuilder, ButtonInteraction, ButtonStyle, CommandInteraction, ComponentType, EmbedBuilder, Interaction, InteractionResponse, Message } from 'discord.js'; -export async function createPaginatedEmbedHandler( - initialInteraction: CommandInteraction, - embeds: EmbedBuilder[], -): Promise { +export async function createPaginatedEmbedHandler(initialInteraction: CommandInteraction, embeds: EmbedBuilder[]): Promise { let currentPage = 0; const nextButton = new ButtonBuilder() @@ -39,11 +25,7 @@ export async function createPaginatedEmbedHandler( } const filter = (buttonInteraction: Interaction) => initialInteraction.user.id === buttonInteraction.user.id; - const collector = message.createMessageComponentCollector({ - filter, - componentType: ComponentType.Button, - time: 120_000, - }); + const collector = message.createMessageComponentCollector({ filter, componentType: ComponentType.Button, time: 120_000 }); collector.on('collect', async (collectedInteraction: ButtonInteraction) => { await collectedInteraction.deferUpdate(); @@ -69,14 +51,7 @@ export async function createPaginatedEmbedHandler( function handleEmbedExpire() { const embed = embeds[currentPage]; - initialInteraction.editReply({ - embeds: [ - embed.setFooter({ - text: `${embed.data.footer ? `${embed.data.footer.text} - ` : ''}This embed has expired.`, - }), - ], - components: [], - }); + initialInteraction.editReply({ embeds: [embed.setFooter({ text: `${embed.data.footer ? `${embed.data.footer.text} - ` : ''}This embed has expired.` })], components: [] }); } function setButtonDisabledStates() { diff --git a/src/lib/infractionEmbedPagination.ts b/src/lib/infractionEmbedPagination.ts index 3c268884..a5150526 100644 --- a/src/lib/infractionEmbedPagination.ts +++ b/src/lib/infractionEmbedPagination.ts @@ -1,26 +1,6 @@ -import { - ActionRowBuilder, - ButtonBuilder, - ButtonStyle, - Interaction, - CommandInteraction, - ButtonInteraction, - EmbedBuilder, -} from 'discord.js'; - -export async function createPaginatedInfractionEmbedHandler( - initialInteraction: CommandInteraction, - user: string, - embeds: EmbedBuilder[], - infractionsLengths: { - warnsLength: string; - timeoutsLength: string; - scamLogsLength: string; - bansLength: string; - unbansLength: string; - notesLength: string; - }, -): Promise { +import { ActionRowBuilder, ButtonBuilder, ButtonStyle, Interaction, CommandInteraction, ButtonInteraction, EmbedBuilder } from 'discord.js'; + +export async function createPaginatedInfractionEmbedHandler(initialInteraction: CommandInteraction, user:string, embeds: EmbedBuilder[], infractionsLengths: { warnsLength: string; timeoutsLength: string; scamLogsLength: string; bansLength: string; unbansLength: string; notesLength: string; }): Promise { let currentPage = 0; const aboutButton = new ButtonBuilder() @@ -59,16 +39,8 @@ export async function createPaginatedInfractionEmbedHandler( .setStyle(ButtonStyle.Primary); const buttonRow1 = new ActionRowBuilder().addComponents(aboutButton, warnButton, timeoutButton); - const buttonRow2 = new ActionRowBuilder().addComponents( - scamLogButton, - banButton, - unbanButton, - noteButton, - ); - const message = await initialInteraction.followUp({ - embeds: [embeds[currentPage]], - components: [buttonRow1, buttonRow2], - }); + const buttonRow2 = new ActionRowBuilder().addComponents(scamLogButton, banButton, unbanButton, noteButton); + const message = await initialInteraction.followUp({ embeds: [embeds[currentPage]], components: [buttonRow1, buttonRow2] }); const filter = (interaction: Interaction) => interaction.user.id === user; const collector = message.createMessageComponentCollector({ filter, time: 120_000 }); @@ -113,13 +85,6 @@ export async function createPaginatedInfractionEmbedHandler( function handleEmbedExpire() { const embed = embeds[currentPage]; - initialInteraction.editReply({ - embeds: [ - embed.setFooter({ - text: `${embed.data.footer ? `${embed.data.footer.text} - ` : ''}This embed has expired.`, - }), - ], - components: [], - }); + initialInteraction.editReply({ embeds: [embed.setFooter({ text: `${embed.data.footer ? `${embed.data.footer.text} - ` : ''}This embed has expired.` })], components: [] }); } } diff --git a/src/lib/logger.ts b/src/lib/logger.ts index c8237154..d2f2e6f4 100644 --- a/src/lib/logger.ts +++ b/src/lib/logger.ts @@ -19,5 +19,7 @@ const format = () => { export const Logger = winston.createLogger({ level: level(), format: format(), - transports: [new winston.transports.Console()], + transports: [ + new winston.transports.Console(), + ], }); diff --git a/src/lib/replies.ts b/src/lib/replies.ts index e25d588f..472fcf34 100644 --- a/src/lib/replies.ts +++ b/src/lib/replies.ts @@ -11,17 +11,15 @@ export enum Color { export const EditReply = (msg: string, color: Color = Color.Info): InteractionEditReplyOptions => ({ content: undefined, - embeds: [ - { - description: msg, - color, - }, - ], + embeds: [{ + description: msg, + color, + }], components: [], files: [], }); export const Reply = (msg: string, color: Color = Color.Info): InteractionReplyOptions => ({ ephemeral: true, - ...(EditReply(msg, color) as InteractionReplyOptions), + ...EditReply(msg, color) as InteractionReplyOptions, }); diff --git a/src/lib/schedulerJobs/autoDisableSlowMode.ts b/src/lib/schedulerJobs/autoDisableSlowMode.ts index ac9e8e83..1684d5e2 100644 --- a/src/lib/schedulerJobs/autoDisableSlowMode.ts +++ b/src/lib/schedulerJobs/autoDisableSlowMode.ts @@ -3,19 +3,17 @@ import { ChannelType, TextChannel, Colors } from 'discord.js'; import { client } from '../../client'; import { constantsConfig, makeEmbed, Logger, getScheduler } from '../index'; -const failedEmbed = (action: string, channel: string) => - makeEmbed({ - title: `Slow Message - ${action} failed`, - description: `Failed to ${action} the slow mode for channel <#${channel}>.`, - color: Colors.Red, - }); +const failedEmbed = (action: string, channel: string) => makeEmbed({ + title: `Slow Message - ${action} failed`, + description: `Failed to ${action} the slow mode for channel <#${channel}>.`, + color: Colors.Red, +}); -const modLogEmbed = (action: string, fields: any, color: number) => - makeEmbed({ - title: `Slow Mode - ${action}`, - fields, - color, - }); +const modLogEmbed = (action: string, fields: any, color: number) => makeEmbed({ + title: `Slow Mode - ${action}`, + fields, + color, +}); export async function autoDisableSlowMode(job: Job) { const scheduler = getScheduler(); @@ -24,7 +22,7 @@ export async function autoDisableSlowMode(job: Job) { return; } // Needed because of https://github.com/agenda/agenda/issues/401 - + // eslint-disable-next-line no-underscore-dangle const matchingJobs = await scheduler.jobs({ _id: job.attrs._id }); if (matchingJobs.length !== 1) { Logger.debug('Job has been deleted already, skipping execution.'); @@ -33,12 +31,7 @@ export async function autoDisableSlowMode(job: Job) { const { channelId } = job.attrs.data as { channelId: string }; const modLogsChannel = client.channels.resolve(constantsConfig.channels.MOD_LOGS) as TextChannel | null; const slowmodeChannel = client.channels.resolve(channelId); - if ( - !slowmodeChannel || - [ChannelType.GuildText, ChannelType.GuildForum, ChannelType.PublicThread, ChannelType.PrivateThread].indexOf( - slowmodeChannel.type, - ) === -1 - ) { + if (!slowmodeChannel || [ChannelType.GuildText, ChannelType.GuildForum, ChannelType.PublicThread, ChannelType.PrivateThread].indexOf(slowmodeChannel.type) === -1) { Logger.error('Slow mode - Auto disable - Unable to disable for non-existing channel'); if (modLogsChannel) { await modLogsChannel.send({ embeds: [failedEmbed('Auto disable', channelId)] }); @@ -46,12 +39,7 @@ export async function autoDisableSlowMode(job: Job) { return; } try { - if ( - slowmodeChannel.type === ChannelType.GuildForum || - slowmodeChannel.type === ChannelType.GuildText || - slowmodeChannel.type === ChannelType.PrivateThread || - slowmodeChannel.type === ChannelType.PublicThread - ) { + if (slowmodeChannel.type === ChannelType.GuildForum || slowmodeChannel.type === ChannelType.GuildText || slowmodeChannel.type === ChannelType.PrivateThread || slowmodeChannel.type === ChannelType.PublicThread) { await slowmodeChannel.setRateLimitPerUser(0, 'Slow mode disabled through bot'); } await job.remove(); @@ -63,34 +51,29 @@ export async function autoDisableSlowMode(job: Job) { try { // @ts-ignore await modLogsChannel.send({ - embeds: [ - modLogEmbed( - 'Auto Disable', - [ - { - inline: true, - name: 'Channel', - value: `<#${channelId}>`, - }, - { - inline: true, - name: 'Slow mode limit', - value: 'Disabled', - }, - { - inline: true, - name: 'Auto disable timeout', - value: 'None', - }, - { - inline: true, - name: 'Moderator', - value: 'FBW Bot', - }, - ], - Colors.Green, - ), + embeds: [modLogEmbed('Auto Disable', [ + { + inline: true, + name: 'Channel', + value: `<#${channelId}>`, + }, + { + inline: true, + name: 'Slow mode limit', + value: 'Disabled', + }, + { + inline: true, + name: 'Auto disable timeout', + value: 'None', + }, + { + inline: true, + name: 'Moderator', + value: 'FBW Bot', + }, ], + Colors.Green)], }); } catch (err) { Logger.warn(`Failed to send Mod Log for auto disable of slow mode for channel <#${channelId}>: ${err}`); diff --git a/src/lib/schedulerJobs/postBirthdays.ts b/src/lib/schedulerJobs/postBirthdays.ts index 74ebb305..6b11f669 100644 --- a/src/lib/schedulerJobs/postBirthdays.ts +++ b/src/lib/schedulerJobs/postBirthdays.ts @@ -25,13 +25,14 @@ export async function postBirthdays(job: Job) { return; } + // eslint-disable-next-line no-underscore-dangle const matchingJobs = await scheduler.jobs({ _id: job.attrs._id }); if (matchingJobs.length !== 1) { Logger.debug('Job has been deleted already, skipping execution.'); return; } - const guild = client.guilds.resolve(constantsConfig.guildId); + const guild = client.guilds.resolve(constantsConfig.guildId) as Guild | null; if (!guild) { Logger.error('BirthdayHandler - Guild not found.'); return; @@ -46,7 +47,7 @@ export async function postBirthdays(job: Job) { // Get all threads (archived included) await channel.threads.fetch({ archived: {} }); - const thread = channel.threads.cache.find((t) => t.id === constantsConfig.threads.BIRTHDAY_THREAD); + const thread = channel.threads.cache.find((t) => t.id === constantsConfig.threads.BIRTHDAY_THREAD) as ThreadChannel | null; if (!thread) { Logger.error('Birthday handler - Thread not found'); return; @@ -84,7 +85,8 @@ export async function postBirthdays(job: Job) { for (const birthday of birthdays) { let user; try { - user = await guild.members.fetch(birthday.userID); + // eslint-disable-next-line no-await-in-loop + user = await guild.members.fetch(birthday.userID!); } catch (error) { Logger.error('BirthdayHandler - Failed to fetch user', error); } @@ -104,9 +106,7 @@ export async function postBirthdays(job: Job) { }); // Update birthday to next year - const nextBirthdayDatetime = new Date( - Date.UTC(currentDate.getUTCFullYear() + 1, birthday.month! - 1, birthday.day), - ); + const nextBirthdayDatetime = new Date(Date.UTC(currentDate.getUTCFullYear() + 1, birthday.month! - 1, birthday.day!)); nextBirthdayDatetime.setUTCHours(10 - birthday.timezone!); birthday.utcDatetime = nextBirthdayDatetime; try { diff --git a/src/lib/schedulerJobs/sendHeartbeat.ts b/src/lib/schedulerJobs/sendHeartbeat.ts index a5dbb3fb..8aa36286 100644 --- a/src/lib/schedulerJobs/sendHeartbeat.ts +++ b/src/lib/schedulerJobs/sendHeartbeat.ts @@ -9,7 +9,7 @@ export async function sendHeartbeat(job: Job) { } // Needed because of https://github.com/agenda/agenda/issues/401 - + // eslint-disable-next-line no-underscore-dangle const matchingJobs = await scheduler.jobs({ _id: job.attrs._id }); if (matchingJobs.length !== 1) { Logger.debug('Job has been deleted already, skipping execution.'); diff --git a/src/lib/slashCommand.ts b/src/lib/slashCommand.ts index a30019c7..9184c8f3 100644 --- a/src/lib/slashCommand.ts +++ b/src/lib/slashCommand.ts @@ -1,43 +1,34 @@ -import type { - Awaitable, - Client, - ChatInputCommandInteraction, - SlashCommandBuilder, - SlashCommandSubcommandsOnlyBuilder, - RESTPostAPIApplicationCommandsJSONBody, -} from 'discord.js'; +import type { Awaitable, Client, ChatInputCommandInteraction, SlashCommandBuilder, SlashCommandSubcommandsOnlyBuilder, RESTPostAPIApplicationCommandsJSONBody } from 'discord.js'; import { LogMethods, AutocompleteCallback } from './index'; /// Props that will be passed through the command callback. export interface SlashCommandProps { - interaction: ChatInputCommandInteraction<'cached'>; - client: Client; - log: LogMethods; + interaction: ChatInputCommandInteraction<'cached'>, + client: Client, + log: LogMethods, } export type SlashCommandCallback = (props: SlashCommandProps) => Awaitable; /// Command structure for slash commands -export type SlashCommandStructure = SlashCommandBuilder & { category?: string }; +export type SlashCommandStructure = + | SlashCommandBuilder & { category?: string } + | SlashCommandSubcommandsOnlyBuilder & { category?: string } + | Omit & { category?: string } + | RESTPostAPIApplicationCommandsJSONBody & { category?: string }; /// Internal structure that represents a command and its callback. export interface SlashCommand { - meta: SlashCommandStructure; - callback: SlashCommandCallback; - autocompleteCallback?: AutocompleteCallback; + meta: SlashCommandStructure, + callback: SlashCommandCallback, + autocompleteCallback?: AutocompleteCallback, } /// Function to provide data for slash commands -export function slashCommandStructure( - data: RESTPostAPIApplicationCommandsJSONBody & { category?: string }, -): SlashCommandStructure { +export function slashCommandStructure(data: RESTPostAPIApplicationCommandsJSONBody & { category?: string }): SlashCommandStructure { return data; } /// Creates command structure -export function slashCommand( - meta: SlashCommandStructure, - callback: SlashCommandCallback, - autocompleteCallback?: AutocompleteCallback, -): SlashCommand { +export function slashCommand(meta: SlashCommandStructure, callback: SlashCommandCallback, autocompleteCallback?: AutocompleteCallback): SlashCommand { return { meta, callback, autocompleteCallback }; } diff --git a/src/scripts/deployCommands.ts b/src/scripts/deployCommands.ts index 2de43807..d350c027 100644 --- a/src/scripts/deployCommands.ts +++ b/src/scripts/deployCommands.ts @@ -12,13 +12,15 @@ if (!process.env.BOT_SECRET) { const rest = new REST({ version: '10' }).setToken(process.env.BOT_SECRET); export async function deployCommands(commandArray: any[], contextArray: any[]) { - const body = [...commandArray.map((cmd) => cmd.meta), ...contextArray.map((ctx) => ctx.meta)]; - const currentUser = (await rest.get(Routes.user())) as APIUser; + const body = [ + ...commandArray.map((cmd) => cmd.meta), + ...contextArray.map((ctx) => ctx.meta), + ]; + const currentUser = await rest.get(Routes.user()) as APIUser; - const endpoint = - process.env.NODE_ENV === 'production' - ? Routes.applicationCommands(currentUser.id) - : Routes.applicationGuildCommands(currentUser.id, constantsConfig.guildId); + const endpoint = process.env.NODE_ENV === 'production' + ? Routes.applicationCommands(currentUser.id) + : Routes.applicationGuildCommands(currentUser.id, constantsConfig.guildId); await rest.put(endpoint, { body }); From 5e9da51442061f31823333e163853ad400ac87d3 Mon Sep 17 00:00:00 2001 From: ExampleWasTaken <58574351+ExampleWasTaken@users.noreply.github.com> Date: Mon, 17 Jun 2024 20:39:20 +0200 Subject: [PATCH 06/82] fix prettier --- src/client.ts | 9 +- src/commands/context/index.ts | 6 +- src/commands/context/message/reportMessage.ts | 119 ++++++----- src/commands/context/user/userInfo.ts | 6 +- src/commands/moderation/cacheUpdate.ts | 61 +++--- src/commands/moderation/clearMessages.ts | 37 +++- src/commands/moderation/commandTable.ts | 14 +- src/commands/moderation/deployCommands.ts | 43 ++-- src/commands/moderation/faq/faq.ts | 28 +-- .../moderation/faq/functions/addFaq.ts | 97 ++++----- .../moderation/faq/functions/faqPrintAll.ts | 3 +- .../moderation/faq/functions/listFaq.ts | 43 ++-- .../moderation/faq/functions/removeFaq.ts | 54 +++-- .../moderation/infractions/functions/ban.ts | 160 ++++++++------- .../functions/deleteInfractions.ts | 61 +++--- .../infractions/functions/listInfractions.ts | 119 ++++++----- .../infractions/functions/removeTimeout.ts | 80 ++++---- .../infractions/functions/timeout.ts | 189 ++++++++++-------- .../infractions/functions/unbanInfractions.ts | 78 ++++---- .../infractions/functions/userNote.ts | 70 +++---- .../moderation/infractions/functions/warn.ts | 139 ++++++------- .../moderation/infractions/infractions.ts | 54 ++--- src/commands/moderation/listRoleUsers.ts | 29 ++- src/commands/moderation/roleAssignment.ts | 10 +- src/commands/moderation/rules.ts | 6 +- .../moderation/slowmode/functions/disable.ts | 32 ++- .../moderation/slowmode/functions/set.ts | 39 +++- src/commands/moderation/slowmode/slowmode.ts | 98 ++++++--- src/commands/moderation/welcome.ts | 5 +- src/commands/moderation/whois.ts | 20 +- src/commands/utils/avatar.ts | 16 +- src/commands/utils/birthday/birthday.ts | 22 +- .../utils/birthday/functions/listBirthday.ts | 15 +- .../birthday/functions/removeBirthday.ts | 20 +- .../utils/birthday/functions/setBirthday.ts | 9 +- src/commands/utils/count.ts | 2 +- src/commands/utils/docSearch.ts | 20 +- .../github/functions/githubPullRequest.ts | 4 +- .../github/functions/handleGithubIssue.ts | 4 +- src/commands/utils/github/github.ts | 66 +++--- src/commands/utils/help.ts | 93 ++++----- .../locate/functions/filterSearchResults.ts | 4 +- .../utils/locate/functions/handleCommand.ts | 23 ++- src/commands/utils/locate/locate.ts | 40 ++-- .../utils/locate/panels/a32nx/a32nx-panels.ts | 70 ++++++- .../utils/locate/panels/a32nx/flyPad.ts | 6 +- .../utils/locate/panels/a32nx/front-panel.ts | 39 +--- .../utils/locate/panels/a32nx/glareshield.ts | 6 +- .../utils/locate/panels/a32nx/overhead.ts | 137 ++----------- .../utils/locate/panels/a32nx/pedestal.ts | 79 ++------ .../locate/panels/a32nx/rear-cb-panel.ts | 5 +- src/commands/utils/metar.ts | 25 ++- src/commands/utils/ping.ts | 16 +- src/commands/utils/reportedIssues.ts | 50 +++-- src/commands/utils/roleInfo.ts | 16 +- src/commands/utils/searchFaq.ts | 29 +-- src/commands/utils/simbriefData.ts | 68 ++++--- src/commands/utils/station.ts | 27 ++- src/commands/utils/taf.ts | 22 +- .../vatsim/functions/vatsimControllers.ts | 70 +++++-- .../utils/vatsim/functions/vatsimEvents.ts | 103 +++++----- .../utils/vatsim/functions/vatsimObservers.ts | 67 ++++--- .../utils/vatsim/functions/vatsimPilots.ts | 44 ++-- .../utils/vatsim/functions/vatsimStats.ts | 99 +++++---- src/commands/utils/vatsim/vatsim.ts | 50 ++--- src/commands/utils/wolframAlpha.ts | 25 +-- src/commands/utils/zulu.ts | 27 ++- src/events/buttonHandlers/buttonHandler.ts | 28 +-- .../functions/handleRoleAssignment.ts | 7 +- src/events/contextInteractionHandler.ts | 8 +- src/events/logging/detectBan.ts | 187 ++++++++--------- src/events/logging/messageDelete.ts | 13 +- src/events/logging/messageUpdate.ts | 22 +- src/events/logging/scamLogs.ts | 16 +- src/events/ready.ts | 43 ++-- src/events/slashCommandHandler.ts | 6 +- src/lib/config.ts | 94 ++++----- src/lib/contextMenuCommand.ts | 12 +- src/lib/durationInEnglish.ts | 6 +- src/lib/embed.ts | 12 +- src/lib/events.ts | 5 +- src/lib/genericEmbedPagination.ts | 33 ++- src/lib/infractionEmbedPagination.ts | 47 ++++- src/lib/logger.ts | 4 +- src/lib/replies.ts | 12 +- src/lib/schedulerJobs/autoDisableSlowMode.ts | 85 ++++---- src/lib/schedulerJobs/postBirthdays.ts | 8 +- src/lib/slashCommand.ts | 39 ++-- src/scripts/deployCommands.ts | 14 +- 89 files changed, 2093 insertions(+), 1735 deletions(-) diff --git a/src/client.ts b/src/client.ts index 3801d69a..b1177f80 100644 --- a/src/client.ts +++ b/src/client.ts @@ -26,11 +26,10 @@ export const client = new Client({ registerEvents(client, Events); -client.login(process.env.BOT_SECRET) - .catch((e) => { - Logger.error(e); - process.exit(1); - }); +client.login(process.env.BOT_SECRET).catch((e) => { + Logger.error(e); + process.exit(1); +}); const handleTermination = async () => { Logger.info('Terminating bot...'); diff --git a/src/commands/context/index.ts b/src/commands/context/index.ts index 1346d3e3..d3e875a0 100644 --- a/src/commands/context/index.ts +++ b/src/commands/context/index.ts @@ -3,10 +3,6 @@ import userInfo from './user/userInfo'; import reportMessage from './message/reportMessage'; import listInfractions from './user/listInfractions'; -const contextArray: ContextMenuCommand[] = [ - userInfo, - reportMessage, - listInfractions, -]; +const contextArray: ContextMenuCommand[] = [userInfo, reportMessage, listInfractions]; export default contextArray; diff --git a/src/commands/context/message/reportMessage.ts b/src/commands/context/message/reportMessage.ts index ef85cd0b..d0edead0 100644 --- a/src/commands/context/message/reportMessage.ts +++ b/src/commands/context/message/reportMessage.ts @@ -2,7 +2,8 @@ import { ActionRowBuilder, ApplicationCommandType, ContextMenuCommandInteraction, - ModalBuilder, TextChannel, + ModalBuilder, + TextChannel, TextInputBuilder, TextInputStyle, Colors, @@ -15,52 +16,57 @@ const data = contextMenuCommandStructure({ type: ApplicationCommandType.Message, }); -const reportedMessageEmbed = (targetMessage: any, interaction: ContextMenuCommandInteraction<'cached'>, messageContent: string, commentContent: string, formattedDate: string) => makeEmbed({ - author: { - name: `[REPORTED MESSAGE] ${targetMessage.author.tag}`, - iconURL: targetMessage.author.displayAvatarURL(), - }, - fields: [ - { - name: 'Reported by', - value: interaction.user.toString(), - inline: true, +const reportedMessageEmbed = ( + targetMessage: any, + interaction: ContextMenuCommandInteraction<'cached'>, + messageContent: string, + commentContent: string, + formattedDate: string, +) => + makeEmbed({ + author: { + name: `[REPORTED MESSAGE] ${targetMessage.author.tag}`, + iconURL: targetMessage.author.displayAvatarURL(), }, - { - name: 'Message Author', - value: targetMessage.author.toString(), - inline: true, - }, - { - name: 'Message Content', - value: messageContent, - inline: false, - }, - { - name: 'Link to Message', - value: targetMessage.url, - inline: false, - }, - { - name: 'Additional Comments', - value: commentContent, - inline: false, - }, - { - name: 'Reported at', - value: formattedDate, - inline: false, - }, - ], - color: Colors.Red, - footer: { text: `Reported Users ID: ${targetMessage.author.id}` }, -}); + fields: [ + { + name: 'Reported by', + value: interaction.user.toString(), + inline: true, + }, + { + name: 'Message Author', + value: targetMessage.author.toString(), + inline: true, + }, + { + name: 'Message Content', + value: messageContent, + inline: false, + }, + { + name: 'Link to Message', + value: targetMessage.url, + inline: false, + }, + { + name: 'Additional Comments', + value: commentContent, + inline: false, + }, + { + name: 'Reported at', + value: formattedDate, + inline: false, + }, + ], + color: Colors.Red, + footer: { text: `Reported Users ID: ${targetMessage.author.id}` }, + }); export default contextMenuCommand(data, async ({ interaction }) => { const currentDate = new Date(); - const formattedDate: string = moment(currentDate) - .utcOffset(0) - .format(); + const formattedDate: string = moment(currentDate).utcOffset(0).format(); const scamReportLogs = interaction.guild.channels.resolve(constantsConfig.channels.SCAM_REPORT_LOGS) as TextChannel; const modRoleId = constantsConfig.roles.MODERATION_TEAM; @@ -126,10 +132,8 @@ export default contextMenuCommand(data, async ({ interaction }) => { //Modal sent - const filter = (interaction: { - customId: string; - user: { id: any; }; - }) => interaction.customId === 'reportMessageModal' && interaction.user.id; + const filter = (interaction: { customId: string; user: { id: any } }) => + interaction.customId === 'reportMessageModal' && interaction.user.id; let commentContent = 'No additional comments provided.'; @@ -160,7 +164,10 @@ export default contextMenuCommand(data, async ({ interaction }) => { //Send a follow-up message to the user if they are part of the staff role group - if (constantsConfig.roleGroups.SUPPORT && constantsConfig.roleGroups.SUPPORT.some((role) => interaction.member.roles.cache.has(role))) { + if ( + constantsConfig.roleGroups.SUPPORT && + constantsConfig.roleGroups.SUPPORT.some((role) => interaction.member.roles.cache.has(role)) + ) { await interaction.followUp({ content: `Is your report urgent and requires immediate attention from the <@&${modRoleId}>? If so please click yes and I will ping the <@&${modRoleId}>. If not, click no.`, components: [ @@ -186,7 +193,7 @@ export default contextMenuCommand(data, async ({ interaction }) => { }); try { - // Handle the button interactions + // Handle the button interactions const modPingButtonInteraction = await interaction.channel.awaitMessageComponent({ filter: (i) => i.customId === 'pingModerationTeamYes' || i.customId === 'pingModerationTeamNo', time: 60000, @@ -231,7 +238,11 @@ export default contextMenuCommand(data, async ({ interaction }) => { content: 'Unable to find the mod alerts channel. Please contact a Moderator.', ephemeral: true, }); - await scamReportLogs.send({ embeds: [reportedMessageEmbed(targetMessage, interaction, messageContent, commentContent, formattedDate)] }); + await scamReportLogs.send({ + embeds: [ + reportedMessageEmbed(targetMessage, interaction, messageContent, commentContent, formattedDate), + ], + }); return; } @@ -286,7 +297,9 @@ export default contextMenuCommand(data, async ({ interaction }) => { content: `Your report has been submitted and shared in ${modAlertsChannel}.`, ephemeral: true, }); - await scamReportLogs.send({ content: `Reported message from ${interaction.user.toString()} has been shared in ${modAlertsChannel}.` }); + await scamReportLogs.send({ + content: `Reported message from ${interaction.user.toString()} has been shared in ${modAlertsChannel}.`, + }); } if (shareReportButtonInteraction.customId === 'shareReportNo') { @@ -303,5 +316,7 @@ export default contextMenuCommand(data, async ({ interaction }) => { }); } } - await scamReportLogs.send({ embeds: [reportedMessageEmbed(targetMessage, interaction, messageContent, commentContent, formattedDate)] }); + await scamReportLogs.send({ + embeds: [reportedMessageEmbed(targetMessage, interaction, messageContent, commentContent, formattedDate)], + }); }); diff --git a/src/commands/context/user/userInfo.ts b/src/commands/context/user/userInfo.ts index 0d25a548..d4e6c654 100644 --- a/src/commands/context/user/userInfo.ts +++ b/src/commands/context/user/userInfo.ts @@ -65,7 +65,11 @@ export default contextMenuCommand(data, async ({ interaction }) => { }, { name: 'Permissions', - value: targetMember.permissions.toArray().join(', ').toLowerCase().replace(/_/g, ' ') + value: targetMember.permissions + .toArray() + .join(', ') + .toLowerCase() + .replace(/_/g, ' ') .replace(/(^\w)|(\s+\w)/g, (char) => char.toUpperCase()), }, ], diff --git a/src/commands/moderation/cacheUpdate.ts b/src/commands/moderation/cacheUpdate.ts index f16c3d72..caab4f9b 100644 --- a/src/commands/moderation/cacheUpdate.ts +++ b/src/commands/moderation/cacheUpdate.ts @@ -31,19 +31,26 @@ const data = slashCommandStructure({ ], }); -const cacheUpdateEmbed = (action: string, fields: any, color: number) => makeEmbed({ - title: `Cache Update - ${action}`, - fields, - color, -}); +const cacheUpdateEmbed = (action: string, fields: any, color: number) => + makeEmbed({ + title: `Cache Update - ${action}`, + fields, + color, + }); -const noChannelEmbed = (action:string, channelName: string) => makeEmbed({ - title: `Sticky Message - ${action} - No ${channelName} channel`, - description: `The command was successful, but no message to ${channelName} was sent. Please check the channel still exists.`, - color: Colors.Yellow, -}); +const noChannelEmbed = (action: string, channelName: string) => + makeEmbed({ + title: `Sticky Message - ${action} - No ${channelName} channel`, + description: `The command was successful, but no message to ${channelName} was sent. Please check the channel still exists.`, + color: Colors.Yellow, + }); -const cacheUpdateEmbedField = (moderator: string, cacheType: string, cacheSize: string, duration: string): EmbedField[] => [ +const cacheUpdateEmbedField = ( + moderator: string, + cacheType: string, + cacheSize: string, + duration: string, +): EmbedField[] => [ { name: 'Type', value: cacheType, @@ -95,26 +102,34 @@ export default slashCommand(data, async ({ interaction }) => { if (cacheSize !== undefined) { await interaction.editReply({ - embeds: [cacheUpdateEmbed(interaction.options.getSubcommand(), - cacheUpdateEmbedField( - interaction.user.tag, + embeds: [ + cacheUpdateEmbed( interaction.options.getSubcommand(), - cacheSize.toString(), - duration, + cacheUpdateEmbedField( + interaction.user.tag, + interaction.options.getSubcommand(), + cacheSize.toString(), + duration, + ), + Colors.Green, ), - Colors.Green)], + ], }); try { await modLogsChannel.send({ - embeds: [cacheUpdateEmbed(interaction.options.getSubcommand(), - cacheUpdateEmbedField( - interaction.user.tag, + embeds: [ + cacheUpdateEmbed( interaction.options.getSubcommand(), - cacheSize.toString(), - duration, + cacheUpdateEmbedField( + interaction.user.tag, + interaction.options.getSubcommand(), + cacheSize.toString(), + duration, + ), + Colors.Green, ), - Colors.Green)], + ], }); } catch (error) { await interaction.followUp({ embeds: [noChannelEmbed(interaction.options.getSubcommand(), 'mod-log')] }); diff --git a/src/commands/moderation/clearMessages.ts b/src/commands/moderation/clearMessages.ts index f5b34eca..9b6c5e05 100644 --- a/src/commands/moderation/clearMessages.ts +++ b/src/commands/moderation/clearMessages.ts @@ -1,4 +1,13 @@ -import { ApplicationCommandOptionType, ApplicationCommandType, TextChannel, Colors, ActionRowBuilder, ButtonBuilder, ButtonStyle, Interaction } from 'discord.js'; +import { + ApplicationCommandOptionType, + ApplicationCommandType, + TextChannel, + Colors, + ActionRowBuilder, + ButtonBuilder, + ButtonStyle, + Interaction, +} from 'discord.js'; import { slashCommand, slashCommandStructure, makeEmbed, constantsConfig, Logger } from '../../lib'; const data = slashCommandStructure({ @@ -7,14 +16,16 @@ const data = slashCommandStructure({ type: ApplicationCommandType.ChatInput, default_member_permissions: constantsConfig.commandPermission.MANAGE_SERVER, //Overrides need to be added for admin and moderator roles dm_permission: false, - options: [{ - name: 'amount', - description: 'Number of messages to clear (1-100).', - type: ApplicationCommandOptionType.Integer, - required: true, - min_value: 1, - max_value: 100, - }], + options: [ + { + name: 'amount', + description: 'Number of messages to clear (1-100).', + type: ApplicationCommandOptionType.Integer, + required: true, + min_value: 1, + max_value: 100, + }, + ], }); export default slashCommand(data, async ({ interaction }) => { @@ -68,7 +79,9 @@ export default slashCommand(data, async ({ interaction }) => { timestamp: new Date(), }); - const modLogsChannel = interaction.guild.channels.resolve(constantsConfig.channels.MOD_LOGS) as TextChannel; + const modLogsChannel = interaction.guild.channels.resolve( + constantsConfig.channels.MOD_LOGS, + ) as TextChannel; const modLogEmbed = makeEmbed({ title: '🧹 Messages Cleared', description: 'Messages have been cleared.', @@ -98,7 +111,9 @@ export default slashCommand(data, async ({ interaction }) => { return interaction.editReply({ content: '', embeds: [replyEmbed], components: [] }); } catch (error) { Logger.error('Error clearing messages:', error); - return interaction.editReply({ content: 'There was an error trying to clear messages in this channel. The error has been logged.' }); + return interaction.editReply({ + content: 'There was an error trying to clear messages in this channel. The error has been logged.', + }); } } else { const canceledEmbed = makeEmbed({ diff --git a/src/commands/moderation/commandTable.ts b/src/commands/moderation/commandTable.ts index 8c98eb4c..66ee5f0f 100644 --- a/src/commands/moderation/commandTable.ts +++ b/src/commands/moderation/commandTable.ts @@ -42,7 +42,11 @@ export default slashCommand(data, async ({ interaction }: { interaction: Command // eslint-disable-next-line prefer-const let { name, description, type } = command; - const subcommandList = command.options?.filter((option) => option.type === ApplicationCommandOptionType.Subcommand || option.type === ApplicationCommandOptionType.SubcommandGroup); + const subcommandList = command.options?.filter( + (option) => + option.type === ApplicationCommandOptionType.Subcommand || + option.type === ApplicationCommandOptionType.SubcommandGroup, + ); let subcommandDescription = ''; @@ -53,11 +57,11 @@ export default slashCommand(data, async ({ interaction }: { interaction: Command return subcommand.name; } if (subcommand.type === ApplicationCommandOptionType.SubcommandGroup) { - const groupSubcommands = subcommand.options?.filter((sub) => sub.type === ApplicationCommandOptionType.Subcommand); + const groupSubcommands = subcommand.options?.filter( + (sub) => sub.type === ApplicationCommandOptionType.Subcommand, + ); if (groupSubcommands && groupSubcommands.length > 0) { - return `${subcommand.name} [${groupSubcommands - .map((sub) => sub.name) - .join(', ')}]`; + return `${subcommand.name} [${groupSubcommands.map((sub) => sub.name).join(', ')}]`; } return `${subcommand.name} [None]`; } diff --git a/src/commands/moderation/deployCommands.ts b/src/commands/moderation/deployCommands.ts index 45da2ba4..f7b59a8b 100644 --- a/src/commands/moderation/deployCommands.ts +++ b/src/commands/moderation/deployCommands.ts @@ -16,36 +16,37 @@ const data = slashCommandStructure({ export default slashCommand(data, async ({ interaction }) => { if (interaction.guild) { try { - await deployCommands(commandArray, contextArray) - .then(async (user) => { - const bot = `<@${user.id}>`; + await deployCommands(commandArray, contextArray).then(async (user) => { + const bot = `<@${user.id}>`; - const guildID = constantsConfig.guildId; - if (!guildID) { - await interaction.reply('guildId configuration constant is not defined.'); - return; - } + const guildID = constantsConfig.guildId; + if (!guildID) { + await interaction.reply('guildId configuration constant is not defined.'); + return; + } - const guildName = client.guilds.cache.get(guildID); + const guildName = client.guilds.cache.get(guildID); - let response; - //If the bot is deployed to a guild and can resolve the name, use the guild name in the response - if (guildName) { - response = process.env.NODE_ENV === 'production' + let response; + //If the bot is deployed to a guild and can resolve the name, use the guild name in the response + if (guildName) { + response = + process.env.NODE_ENV === 'production' ? `Deployed ${commandArray.length} commands and ${contextArray.length} contexts globally as ${bot}!` : `Deployed ${commandArray.length} commands and ${contextArray.length} contexts to \`${guildName}\` as ${bot}!`; - } else { + } else { //If the bot can't gather the guild name, use the ID in the response - response = process.env.NODE_ENV === 'production' + response = + process.env.NODE_ENV === 'production' ? `Deployed ${commandArray.length} commands and ${contextArray.length} contexts globally as ${bot}!` : `Deployed ${commandArray.length} commands and ${contextArray.length} contexts to \`<@${guildID}>\` as ${bot}!`; - } - Logger.info(response); - await interaction.reply({ - content: response, - ephemeral: true, - }); + } + Logger.info(response); + await interaction.reply({ + content: response, + ephemeral: true, }); + }); } catch (error) { await interaction.reply({ content: 'Failed to deploy commands!', diff --git a/src/commands/moderation/faq/faq.ts b/src/commands/moderation/faq/faq.ts index cccc208f..f003ddb1 100644 --- a/src/commands/moderation/faq/faq.ts +++ b/src/commands/moderation/faq/faq.ts @@ -63,20 +63,20 @@ export default slashCommand(data, async ({ interaction }) => { const modLogsChannel = interaction.guild.channels.resolve(constantsConfig.channels.MOD_LOGS) as TextChannel; switch (subcommandName) { - case 'add': - await handleAddFaq(interaction, modLogsChannel); - break; - case 'remove': - await handleRemoveFaq(interaction, faqID, modLogsChannel); - break; - case 'list': - await handleListFaq(interaction); - break; - case 'print-all': - await handlePrintAllFAQ(interaction); - break; + case 'add': + await handleAddFaq(interaction, modLogsChannel); + break; + case 'remove': + await handleRemoveFaq(interaction, faqID, modLogsChannel); + break; + case 'list': + await handleListFaq(interaction); + break; + case 'print-all': + await handlePrintAllFAQ(interaction); + break; - default: - await interaction.reply({ content: 'Unknown subcommand', ephemeral: true }); + default: + await interaction.reply({ content: 'Unknown subcommand', ephemeral: true }); } }); diff --git a/src/commands/moderation/faq/functions/addFaq.ts b/src/commands/moderation/faq/functions/addFaq.ts index 72fa12ec..d2fbb510 100644 --- a/src/commands/moderation/faq/functions/addFaq.ts +++ b/src/commands/moderation/faq/functions/addFaq.ts @@ -10,25 +10,26 @@ import { } from 'discord.js'; import { Logger, makeEmbed, FAQ } from '../../../../lib'; -const faqAddedEmbed = (discordUser: User, question: string, answer: string) => makeEmbed({ - author: { - name: `[FAQ Added] ${discordUser.tag}`, - iconURL: discordUser.displayAvatarURL(), - }, - fields: [ - { - inline: false, - name: 'Question', - value: question, +const faqAddedEmbed = (discordUser: User, question: string, answer: string) => + makeEmbed({ + author: { + name: `[FAQ Added] ${discordUser.tag}`, + iconURL: discordUser.displayAvatarURL(), }, - { - inline: false, - name: 'Answer', - value: answer, - }, - ], - color: Colors.Green, -}); + fields: [ + { + inline: false, + name: 'Question', + value: question, + }, + { + inline: false, + name: 'Answer', + value: answer, + }, + ], + color: Colors.Green, + }); export async function handleAddFaq(interaction: ChatInputCommandInteraction<'cached'>, modLogsChannel: TextChannel) { const modal = new ModalBuilder({ @@ -36,27 +37,23 @@ export async function handleAddFaq(interaction: ChatInputCommandInteraction<'cac title: 'Add an FAQ entry', }); - const faqTitleInput = new TextInputBuilder( - { - customId: 'faqTitleInput', - label: 'Title', - placeholder: 'Please enter the title of the FAQ.', - style: TextInputStyle.Short, - maxLength: 500, - required: true, - }, - ); - - const faqAnswerInput = new TextInputBuilder( - { - customId: 'faqAnswerInput', - label: 'Answer', - placeholder: 'If you wish to mention a role or channel use <@&*ID*> or <#*ID*> respectively.', - style: TextInputStyle.Paragraph, - maxLength: 1000, - required: true, - }, - ); + const faqTitleInput = new TextInputBuilder({ + customId: 'faqTitleInput', + label: 'Title', + placeholder: 'Please enter the title of the FAQ.', + style: TextInputStyle.Short, + maxLength: 500, + required: true, + }); + + const faqAnswerInput = new TextInputBuilder({ + customId: 'faqAnswerInput', + label: 'Answer', + placeholder: 'If you wish to mention a role or channel use <@&*ID*> or <#*ID*> respectively.', + style: TextInputStyle.Paragraph, + maxLength: 1000, + required: true, + }); const titleActionRow = new ActionRowBuilder().addComponents(faqTitleInput); const answerActionRow = new ActionRowBuilder().addComponents(faqAnswerInput); @@ -67,10 +64,8 @@ export async function handleAddFaq(interaction: ChatInputCommandInteraction<'cac //Modal sent - const filter = (interaction: { - customId: string; - user: { id: any; }; - }) => interaction.customId === 'faqAddModal' && interaction.user.id; + const filter = (interaction: { customId: string; user: { id: any } }) => + interaction.customId === 'faqAddModal' && interaction.user.id; try { //Await a modal response @@ -101,7 +96,10 @@ export async function handleAddFaq(interaction: ChatInputCommandInteraction<'cac dateSet: currentDate, }); } else { - await interaction.followUp({ content: 'FAQ with this title already exists. Please choose another title', ephemeral: true }); + await interaction.followUp({ + content: 'FAQ with this title already exists. Please choose another title', + ephemeral: true, + }); return; } @@ -109,7 +107,10 @@ export async function handleAddFaq(interaction: ChatInputCommandInteraction<'cac await faqData.save(); } catch (error) { Logger.error(error); - await interaction.followUp({ content: 'Could not add FAQ, error has been logged, please notify the bot team.', ephemeral: true }); + await interaction.followUp({ + content: 'Could not add FAQ, error has been logged, please notify the bot team.', + ephemeral: true, + }); return; } @@ -117,7 +118,11 @@ export async function handleAddFaq(interaction: ChatInputCommandInteraction<'cac await modLogsChannel.send({ embeds: [faqAddedEmbed(discordUser, faqTitle, faqAnswer)] }); } catch (error) { Logger.error(error); - await interaction.followUp({ content: 'FAQ added successfully, but could not send mod log, error has been logged, please notify the bot team.', ephemeral: true }); + await interaction.followUp({ + content: + 'FAQ added successfully, but could not send mod log, error has been logged, please notify the bot team.', + ephemeral: true, + }); return; } diff --git a/src/commands/moderation/faq/functions/faqPrintAll.ts b/src/commands/moderation/faq/functions/faqPrintAll.ts index e9f573ea..15421ed7 100644 --- a/src/commands/moderation/faq/functions/faqPrintAll.ts +++ b/src/commands/moderation/faq/functions/faqPrintAll.ts @@ -34,7 +34,8 @@ export async function handlePrintAllFAQ(interaction: ChatInputCommandInteraction if (faqs.length === 0) { return interaction.followUp('No FAQs found.'); - } if (interaction.channel) { + } + if (interaction.channel) { await interaction.channel.send({ files: [FLIGHT_DECK_IMAGE_URL] }); // Divide the FAQs into sets of 5 diff --git a/src/commands/moderation/faq/functions/listFaq.ts b/src/commands/moderation/faq/functions/listFaq.ts index 965d87dd..d0b651f7 100644 --- a/src/commands/moderation/faq/functions/listFaq.ts +++ b/src/commands/moderation/faq/functions/listFaq.ts @@ -2,10 +2,11 @@ import { ChatInputCommandInteraction } from 'discord.js'; import moment from 'moment/moment'; import { Logger, makeEmbed, FAQ, createPaginatedEmbedHandler } from '../../../../lib'; -const faqListEmbed = (faqFields: { name: string; value: string; }[], currentPage: number, totalPages: number) => makeEmbed({ - title: `FAQ List (Page ${currentPage} of ${totalPages})`, - fields: faqFields, -}); +const faqListEmbed = (faqFields: { name: string; value: string }[], currentPage: number, totalPages: number) => + makeEmbed({ + title: `FAQ List (Page ${currentPage} of ${totalPages})`, + fields: faqFields, + }); export async function handleListFaq(interaction: ChatInputCommandInteraction<'cached'>) { try { @@ -20,16 +21,19 @@ export async function handleListFaq(interaction: ChatInputCommandInteraction<'ca const embeds = []; let currentPage = 1; let faqsAddedToPage = 0; - const faqFields: { name: string; value: string; }[] = []; + const faqFields: { name: string; value: string }[] = []; - const moderatorPromises = faqs.map((currentFaq) => interaction.client.users.fetch(currentFaq.moderatorID!) - // Added for better readability - // eslint-disable-next-line arrow-body-style - .catch(() => { - return new Promise((resolve) => { - resolve(`I can't find the moderator, here is the stored ID: ${currentFaq.moderatorID}`); - }); - })); + const moderatorPromises = faqs.map((currentFaq) => + interaction.client.users + .fetch(currentFaq.moderatorID!) + // Added for better readability + // eslint-disable-next-line arrow-body-style + .catch(() => { + return new Promise((resolve) => { + resolve(`I can't find the moderator, here is the stored ID: ${currentFaq.moderatorID}`); + }); + }), + ); const moderatorUsers = await Promise.all(moderatorPromises); for (let i = 0; i < faqs.length; i++) { @@ -39,10 +43,10 @@ export async function handleListFaq(interaction: ChatInputCommandInteraction<'ca { name: `**Title:** ${faqs[i].faqTitle}`, value: - `**Answer:** ${faqs[i].faqAnswer}\n` - + `**Moderator:** ${moderatorUsers[i]}\n` - + `**Date Set:** ${formattedDate}\n` - + `**FAQ ID:** ${faqs[i].id}\n`, + `**Answer:** ${faqs[i].faqAnswer}\n` + + `**Moderator:** ${moderatorUsers[i]}\n` + + `**Date Set:** ${formattedDate}\n` + + `**FAQ ID:** ${faqs[i].id}\n`, }, { name: '', @@ -71,6 +75,9 @@ export async function handleListFaq(interaction: ChatInputCommandInteraction<'ca await createPaginatedEmbedHandler(interaction, embeds); } catch (error) { Logger.error(error); - await interaction.reply({ content: 'Could not list FAQs, error has been logged, please notify the bot team.', ephemeral: true }); + await interaction.reply({ + content: 'Could not list FAQs, error has been logged, please notify the bot team.', + ephemeral: true, + }); } } diff --git a/src/commands/moderation/faq/functions/removeFaq.ts b/src/commands/moderation/faq/functions/removeFaq.ts index 80fb2937..30b508fc 100644 --- a/src/commands/moderation/faq/functions/removeFaq.ts +++ b/src/commands/moderation/faq/functions/removeFaq.ts @@ -1,27 +1,32 @@ import { ChatInputCommandInteraction, Colors, TextChannel, User } from 'discord.js'; import { Logger, makeEmbed, FAQ } from '../../../../lib'; -const faqRemovedEmbed = (discordUser: User, faqQuestion: string, faqAnswer: string) => makeEmbed({ - author: { - name: `[FAQ Removed] ${discordUser.tag}`, - iconURL: discordUser.displayAvatarURL(), - }, - fields: [ - { - inline: false, - name: 'Question', - value: faqQuestion, +const faqRemovedEmbed = (discordUser: User, faqQuestion: string, faqAnswer: string) => + makeEmbed({ + author: { + name: `[FAQ Removed] ${discordUser.tag}`, + iconURL: discordUser.displayAvatarURL(), }, - { - inline: false, - name: 'Answer', - value: faqAnswer, - }, - ], - color: Colors.Red, -}); + fields: [ + { + inline: false, + name: 'Question', + value: faqQuestion, + }, + { + inline: false, + name: 'Answer', + value: faqAnswer, + }, + ], + color: Colors.Red, + }); -export async function handleRemoveFaq(interaction: ChatInputCommandInteraction<'cached'>, faqID: string, modLogsChannel: TextChannel) { +export async function handleRemoveFaq( + interaction: ChatInputCommandInteraction<'cached'>, + faqID: string, + modLogsChannel: TextChannel, +) { const discordUser = interaction.user; const faqEntry = await FAQ.findOne({ _id: faqID }); @@ -38,7 +43,10 @@ export async function handleRemoveFaq(interaction: ChatInputCommandInteraction<' await faqEntry.deleteOne(); } catch (error) { Logger.error(error); - await interaction.reply({ content: 'Could not remove FAQ, error has been logged, please notify the bot team.', ephemeral: true }); + await interaction.reply({ + content: 'Could not remove FAQ, error has been logged, please notify the bot team.', + ephemeral: true, + }); return; } @@ -46,7 +54,11 @@ export async function handleRemoveFaq(interaction: ChatInputCommandInteraction<' await modLogsChannel.send({ embeds: [faqRemovedEmbed(discordUser, faqTitle, faqAnswer)] }); } catch (error) { Logger.error(error); - await interaction.reply({ content: 'FAQ removed successfully, but could not send mod log, error has been logged, please notify the bot team.', ephemeral: true }); + await interaction.reply({ + content: + 'FAQ removed successfully, but could not send mod log, error has been logged, please notify the bot team.', + ephemeral: true, + }); return; } diff --git a/src/commands/moderation/infractions/functions/ban.ts b/src/commands/moderation/infractions/functions/ban.ts index e141df53..40c2eed6 100644 --- a/src/commands/moderation/infractions/functions/ban.ts +++ b/src/commands/moderation/infractions/functions/ban.ts @@ -11,82 +11,94 @@ const noConnEmbed = makeEmbed({ const moderatableFailEmbed = makeEmbed({ color: Colors.Red, - description: 'You can\'t ban a moderator!', + description: "You can't ban a moderator!", }); -const failedBanEmbed = (discordUser: User) => makeEmbed({ - title: 'Ban - Failed', - description: `Failed to Ban ${discordUser.toString()}`, - color: Colors.Red, -}); - -const DMEmbed = (moderator: User, banReason: string, guild: Guild) => makeEmbed({ - title: `You have been banned from ${guild.name}`, - description: 'This ban is also logged against your record.', - fields: [ - { - inline: true, - name: 'Moderator', - value: moderator.toString(), - }, - { - inline: false, - name: 'Reason', - value: banReason, - }, - { - inline: false, - name: 'Appeal', - value: `If you would like to appeal your ban, please fill out [this form.](${process.env.BAN_APPEAL_URL})`, +const failedBanEmbed = (discordUser: User) => + makeEmbed({ + title: 'Ban - Failed', + description: `Failed to Ban ${discordUser.toString()}`, + color: Colors.Red, + }); + +const DMEmbed = (moderator: User, banReason: string, guild: Guild) => + makeEmbed({ + title: `You have been banned from ${guild.name}`, + description: 'This ban is also logged against your record.', + fields: [ + { + inline: true, + name: 'Moderator', + value: moderator.toString(), + }, + { + inline: false, + name: 'Reason', + value: banReason, + }, + { + inline: false, + name: 'Appeal', + value: `If you would like to appeal your ban, please fill out [this form.](${process.env.BAN_APPEAL_URL})`, + }, + ], + }); + +const banEmbed = (discordUser: User) => + makeEmbed({ + title: `${discordUser.tag} was banned successfully`, + color: Colors.Green, + }); + +const DMFailed = (discordUser: User) => + makeEmbed({ + title: 'Ban - DM not sent', + description: `DM was not sent to ${discordUser.toString()}, they either have DMs closed or share no mutual servers with the bot.`, + color: Colors.Red, + }); + +const modLogEmbed = ( + moderator: User, + discordUser: User, + banReason: string, + daysDeletedNumber: number, + formattedDate: string, +) => + makeEmbed({ + author: { + name: `[BANNED] ${discordUser.tag}`, + iconURL: discordUser.displayAvatarURL(), }, - ], -}); - -const banEmbed = (discordUser: User) => makeEmbed({ - title: `${discordUser.tag} was banned successfully`, - color: Colors.Green, -}); - -const DMFailed = (discordUser: User) => makeEmbed({ - title: 'Ban - DM not sent', - description: `DM was not sent to ${discordUser.toString()}, they either have DMs closed or share no mutual servers with the bot.`, - color: Colors.Red, -}); - -const modLogEmbed = (moderator: User, discordUser: User, banReason: string, daysDeletedNumber: number, formattedDate: string) => makeEmbed({ - author: { - name: `[BANNED] ${discordUser.tag}`, - iconURL: discordUser.displayAvatarURL(), - }, - fields: [ - { - name: 'User', - value: discordUser.toString(), - }, - { - name: 'Moderator', - value: `${moderator}`, - }, - { - name: 'Reason', - value: `\u200B${banReason}`, - }, - { - name: 'Days of messages deleted', - value: daysDeletedNumber.toString(), - }, - { - name: 'Date', - value: formattedDate, - }, - ], - footer: { text: `User ID: ${discordUser.id}` }, - color: Colors.Red, -}); + fields: [ + { + name: 'User', + value: discordUser.toString(), + }, + { + name: 'Moderator', + value: `${moderator}`, + }, + { + name: 'Reason', + value: `\u200B${banReason}`, + }, + { + name: 'Days of messages deleted', + value: daysDeletedNumber.toString(), + }, + { + name: 'Date', + value: formattedDate, + }, + ], + footer: { text: `User ID: ${discordUser.id}` }, + color: Colors.Red, + }); const noModLogs = makeEmbed({ title: 'Ban - No Mod Log', - description: 'I can\'t find the mod logs channel. I will still try to ban the user. Please check the channel still exists.', + description: + "I can't find the mod logs channel. I will still try to ban the user. Please check the channel still exists.", color: Colors.Red, }); @@ -112,9 +124,7 @@ export async function handleBanInfraction(interaction: ChatInputCommandInteracti const discordUser = await interaction.guild.members.fetch(userID); const moderator = interaction.user; const currentDate = new Date(); - const formattedDate: string = moment(currentDate) - .utcOffset(0) - .format(); + const formattedDate: string = moment(currentDate).utcOffset(0).format(); const modLogsChannel = interaction.guild.channels.resolve(constantsConfig.channels.MOD_LOGS) as TextChannel; //Check if the user is a moderator @@ -145,7 +155,9 @@ export async function handleBanInfraction(interaction: ChatInputCommandInteracti try { await interaction.guild.members.ban(discordUser, { deleteMessageDays: daysDeletedNumber, reason: banReason }); if (modLogsChannel) { - await modLogsChannel.send({ embeds: [modLogEmbed(moderator, discordUser.user, banReason, daysDeletedNumber, formattedDate)] }); + await modLogsChannel.send({ + embeds: [modLogEmbed(moderator, discordUser.user, banReason, daysDeletedNumber, formattedDate)], + }); } await interaction.followUp({ embeds: [banEmbed(discordUser.user)], ephemeral: true }); } catch (error) { diff --git a/src/commands/moderation/infractions/functions/deleteInfractions.ts b/src/commands/moderation/infractions/functions/deleteInfractions.ts index d2bd7539..388d237b 100644 --- a/src/commands/moderation/infractions/functions/deleteInfractions.ts +++ b/src/commands/moderation/infractions/functions/deleteInfractions.ts @@ -31,35 +31,36 @@ const errorEmbed = makeEmbed({ color: Colors.Red, }); -const modLogEmbed = (moderator: string, discordUser: User, infractionType: string, infractionReason: string) => makeEmbed({ - author: { - name: `[INFRACTION DELETE] ${discordUser.tag}`, - iconURL: discordUser.displayAvatarURL(), - }, - fields: [ - { - inline: false, - name: 'Deleted by:', - value: moderator, +const modLogEmbed = (moderator: string, discordUser: User, infractionType: string, infractionReason: string) => + makeEmbed({ + author: { + name: `[INFRACTION DELETE] ${discordUser.tag}`, + iconURL: discordUser.displayAvatarURL(), }, - { - inline: false, - name: 'Infraction user:', - value: discordUser.toString(), - }, - { - inline: false, - name: 'Infraction type:', - value: infractionType, - }, - { - inline: false, - name: 'Reason', - value: infractionReason, - }, - ], - color: Colors.Green, -}); + fields: [ + { + inline: false, + name: 'Deleted by:', + value: moderator, + }, + { + inline: false, + name: 'Infraction user:', + value: discordUser.toString(), + }, + { + inline: false, + name: 'Infraction type:', + value: infractionType, + }, + { + inline: false, + name: 'Reason', + value: infractionReason, + }, + ], + color: Colors.Green, + }); export async function handleDeleteInfraction(interaction: ChatInputCommandInteraction<'cached'>) { const conn = getConn(); @@ -105,7 +106,9 @@ export async function handleDeleteInfraction(interaction: ChatInputCommandIntera const modLogsChannel = interaction.guild.channels.resolve(constantsConfig.channels.MOD_LOGS) as TextChannel; if (modLogsChannel) { - await modLogsChannel.send({ embeds: [modLogEmbed(interaction.user.toString(), discordUser, infractionType, infractionReason)] }); + await modLogsChannel.send({ + embeds: [modLogEmbed(interaction.user.toString(), discordUser, infractionType, infractionReason)], + }); } } catch (error) { await interaction.reply({ embeds: [errorEmbed], ephemeral: true }); diff --git a/src/commands/moderation/infractions/functions/listInfractions.ts b/src/commands/moderation/infractions/functions/listInfractions.ts index 52820386..37d6b784 100644 --- a/src/commands/moderation/infractions/functions/listInfractions.ts +++ b/src/commands/moderation/infractions/functions/listInfractions.ts @@ -8,7 +8,11 @@ const noConnEmbed = makeEmbed({ color: Colors.Red, }); -export async function handleListInfraction(interaction: CommandInteraction, userID: string | undefined, ephemeral = false) { +export async function handleListInfraction( + interaction: CommandInteraction, + userID: string | undefined, + ephemeral = false, +) { const conn = getConn(); if (!conn) { @@ -63,7 +67,8 @@ export async function handleListInfraction(interaction: CommandInteraction, user notesLength: userNotes.length.toString(), }; - type InfractionArray = typeof warnInfractions + type InfractionArray = + | typeof warnInfractions | typeof timeoutInfractions | typeof scamLogInfractions | typeof banInfractions @@ -71,14 +76,17 @@ export async function handleListInfraction(interaction: CommandInteraction, user | typeof userNotes; const fetchModerators = (infractions: InfractionArray) => { - const moderatorPromises = infractions.map((infraction) => interaction.client.users.fetch(infraction.moderatorID!) - // Disabled for readability - // eslint-disable-next-line arrow-body-style - .catch(() => { - return new Promise((resolve) => { - resolve(`I can't find the moderator, here is the stored ID: ${infraction.moderatorID}`); - }); - })); + const moderatorPromises = infractions.map((infraction) => + interaction.client.users + .fetch(infraction.moderatorID!) + // Disabled for readability + // eslint-disable-next-line arrow-body-style + .catch(() => { + return new Promise((resolve) => { + resolve(`I can't find the moderator, here is the stored ID: ${infraction.moderatorID}`); + }); + }), + ); return Promise.all(moderatorPromises); }; @@ -88,19 +96,17 @@ export async function handleListInfraction(interaction: CommandInteraction, user const warnModeratorUsers = await fetchModerators(warnInfractions); for (let i = 0; i < warnInfractions.length; i++) { - const formattedDate: string = moment(warnInfractions[i].date) - .utcOffset(0) - .format(); + const formattedDate: string = moment(warnInfractions[i].date).utcOffset(0).format(); warnFields.push( { name: `Warn #${i + 1}`, value: - `**Type:** ${warnInfractions[i].infractionType}\n` - + `**Moderator:** ${warnModeratorUsers[i]}\n` - + `**Reason:** ${warnInfractions[i].reason}\n` - + `**Date:** ${formattedDate}\n` - + `**Infraction ID:** ${warnInfractions[i].infractionID}`, + `**Type:** ${warnInfractions[i].infractionType}\n` + + `**Moderator:** ${warnModeratorUsers[i]}\n` + + `**Reason:** ${warnInfractions[i].reason}\n` + + `**Date:** ${formattedDate}\n` + + `**Infraction ID:** ${warnInfractions[i].infractionID}`, }, { name: '', @@ -124,20 +130,18 @@ export async function handleListInfraction(interaction: CommandInteraction, user const timeoutModeratorUsers = await fetchModerators(timeoutInfractions); for (let i = 0; i < timeoutInfractions.length; i++) { - const formattedDate: string = moment(timeoutInfractions[i].date) - .utcOffset(0) - .format(); + const formattedDate: string = moment(timeoutInfractions[i].date).utcOffset(0).format(); timeoutFields.push( { name: `Timeout #${i + 1}`, value: - `**Type:** ${timeoutInfractions[i].infractionType}\n` - + `**Moderator:** ${timeoutModeratorUsers[i]}\n` - + `**Reason:** ${timeoutInfractions[i].reason}\n` - + `**Duration:** ${timeoutInfractions[i].duration !== undefined ? timeoutInfractions[i].duration : 'No duration specified, this user was timed out before the bot upgrade!'}\n` - + `**Date:** ${formattedDate}\n` - + `**Infraction ID:** ${timeoutInfractions[i].infractionID}`, + `**Type:** ${timeoutInfractions[i].infractionType}\n` + + `**Moderator:** ${timeoutModeratorUsers[i]}\n` + + `**Reason:** ${timeoutInfractions[i].reason}\n` + + `**Duration:** ${timeoutInfractions[i].duration !== undefined ? timeoutInfractions[i].duration : 'No duration specified, this user was timed out before the bot upgrade!'}\n` + + `**Date:** ${formattedDate}\n` + + `**Infraction ID:** ${timeoutInfractions[i].infractionID}`, }, { name: '', @@ -161,19 +165,17 @@ export async function handleListInfraction(interaction: CommandInteraction, user const scamLogModerators = await fetchModerators(scamLogInfractions); for (let i = 0; i < scamLogInfractions.length; i++) { - const formattedDate: string = moment(scamLogInfractions[i].date) - .utcOffset(0) - .format(); + const formattedDate: string = moment(scamLogInfractions[i].date).utcOffset(0).format(); scamLogFields.push( { name: `Scam Log #${i + 1}`, value: - `**Type:** ${scamLogInfractions[i].infractionType}\n` - + `**Moderator:** ${scamLogModerators[i]}\n` - + `**Message Content:** ${scamLogInfractions[i].reason}\n` - + `**Date:** ${formattedDate}\n` - + `**Infraction ID:** ${scamLogInfractions[i].infractionID}`, + `**Type:** ${scamLogInfractions[i].infractionType}\n` + + `**Moderator:** ${scamLogModerators[i]}\n` + + `**Message Content:** ${scamLogInfractions[i].reason}\n` + + `**Date:** ${formattedDate}\n` + + `**Infraction ID:** ${scamLogInfractions[i].infractionID}`, }, { name: '', @@ -197,19 +199,17 @@ export async function handleListInfraction(interaction: CommandInteraction, user const banModerators = await fetchModerators(banInfractions); for (let i = 0; i < banInfractions.length; i++) { - const formattedDate: string = moment(banInfractions[i].date) - .utcOffset(0) - .format(); + const formattedDate: string = moment(banInfractions[i].date).utcOffset(0).format(); banFields.push( { name: `Ban #${i + 1}`, value: - `**Type:** ${banInfractions[i].infractionType}\n` - + `**Moderator:** ${banModerators[i]}\n` - + `**Reason:** ${banInfractions[i].reason}\n` - + `**Date:** ${formattedDate}\n` - + `**Infraction ID:** ${banInfractions[i].infractionID}`, + `**Type:** ${banInfractions[i].infractionType}\n` + + `**Moderator:** ${banModerators[i]}\n` + + `**Reason:** ${banInfractions[i].reason}\n` + + `**Date:** ${formattedDate}\n` + + `**Infraction ID:** ${banInfractions[i].infractionID}`, }, { name: '', @@ -232,19 +232,17 @@ export async function handleListInfraction(interaction: CommandInteraction, user const unbanFields: { name: string; value: string }[] = []; const unbanModerators = await fetchModerators(unbanInfractions); for (let i = 0; i < unbanInfractions.length; i++) { - const formattedDate: string = moment(unbanInfractions[i].date) - .utcOffset(0) - .format(); + const formattedDate: string = moment(unbanInfractions[i].date).utcOffset(0).format(); unbanFields.push( { name: `Unban #${i + 1}`, value: - `**Type:** ${unbanInfractions[i].infractionType}\n` - + `**Moderator:** ${unbanModerators[i]}\n` - + `**Reason:** ${unbanInfractions[i].reason}\n` - + `**Date:** ${formattedDate}\n` - + `**Infraction ID:** ${unbanInfractions[i].infractionID}`, + `**Type:** ${unbanInfractions[i].infractionType}\n` + + `**Moderator:** ${unbanModerators[i]}\n` + + `**Reason:** ${unbanInfractions[i].reason}\n` + + `**Date:** ${formattedDate}\n` + + `**Infraction ID:** ${unbanInfractions[i].infractionID}`, }, { name: '', @@ -268,19 +266,17 @@ export async function handleListInfraction(interaction: CommandInteraction, user const userNodeModerators = await fetchModerators(userNotes); for (let i = 0; i < userNotes.length; i++) { - const formattedDate: string = moment(userNotes[i].date) - .utcOffset(0) - .format(); + const formattedDate: string = moment(userNotes[i].date).utcOffset(0).format(); noteFields.push( { name: `Note #${i + 1}`, value: - `**Type:** ${userNotes[i].infractionType}\n` - + `**Moderator:** ${userNodeModerators[i]}\n` - + `**Note:** ${userNotes[i].reason}\n` - + `**Date:** ${formattedDate}\n` - + `**Infraction ID:** ${userNotes[i].infractionID}`, + `**Type:** ${userNotes[i].infractionType}\n` + + `**Moderator:** ${userNodeModerators[i]}\n` + + `**Note:** ${userNotes[i].reason}\n` + + `**Date:** ${formattedDate}\n` + + `**Infraction ID:** ${userNotes[i].infractionID}`, }, { name: '', @@ -305,7 +301,7 @@ export async function handleListInfraction(interaction: CommandInteraction, user name: `${discordUser.tag}'s Infractions`, iconURL: avatarURL || undefined, }, - description: 'Click the buttons below to view the user\'s infractions in detail.', + description: "Click the buttons below to view the user's infractions in detail.", fields: [ { name: 'UserID', @@ -362,7 +358,8 @@ export async function handleListInfraction(interaction: CommandInteraction, user const userNotFound = makeEmbed({ color: Colors.Red, title: 'User not found', - description: 'An error occurred while fetching user information, please check the userID. If the ID is correct, this user may not exist on Discord anymore - If you need to view their infractions anyway one of the bot team can search the DB manually.', + description: + 'An error occurred while fetching user information, please check the userID. If the ID is correct, this user may not exist on Discord anymore - If you need to view their infractions anyway one of the bot team can search the DB manually.', }); await interaction.followUp({ embeds: [userNotFound], ephemeral }); diff --git a/src/commands/moderation/infractions/functions/removeTimeout.ts b/src/commands/moderation/infractions/functions/removeTimeout.ts index 211778a9..9c1e7c0f 100644 --- a/src/commands/moderation/infractions/functions/removeTimeout.ts +++ b/src/commands/moderation/infractions/functions/removeTimeout.ts @@ -2,48 +2,52 @@ import { ChatInputCommandInteraction, Colors, TextChannel, User } from 'discord. import moment from 'moment'; import { constantsConfig, Logger, makeEmbed } from '../../../../lib'; -const notTimedOutEmbed = (discordUser: User) => makeEmbed({ - title: 'Remove Timeout - Failed', - description: `${discordUser.toString()} is not currently timed out.`, - color: Colors.Red, -}); +const notTimedOutEmbed = (discordUser: User) => + makeEmbed({ + title: 'Remove Timeout - Failed', + description: `${discordUser.toString()} is not currently timed out.`, + color: Colors.Red, + }); -const failedRemoveTimeoutEmbed = (discordUser: User) => makeEmbed({ - title: 'Remove Timeout - Failed', - description: `Failed to remove timeout for ${discordUser.toString()}`, - color: Colors.Red, -}); +const failedRemoveTimeoutEmbed = (discordUser: User) => + makeEmbed({ + title: 'Remove Timeout - Failed', + description: `Failed to remove timeout for ${discordUser.toString()}`, + color: Colors.Red, + }); -const modLogEmbed = (moderator: User, discordUser: User, date: string) => makeEmbed({ - author: { - name: `[TIMEOUT REMOVED] ${discordUser.tag}`, - iconURL: discordUser.displayAvatarURL(), - }, - fields: [ - { - inline: true, - name: 'Moderator', - value: moderator.toString(), +const modLogEmbed = (moderator: User, discordUser: User, date: string) => + makeEmbed({ + author: { + name: `[TIMEOUT REMOVED] ${discordUser.tag}`, + iconURL: discordUser.displayAvatarURL(), }, - { - inline: true, - name: 'User', - value: discordUser.toString(), - }, - { - inline: false, - name: 'Date', - value: date, - }, - ], - footer: { text: `User ID: ${discordUser.id}` }, - color: Colors.Green, -}); + fields: [ + { + inline: true, + name: 'Moderator', + value: moderator.toString(), + }, + { + inline: true, + name: 'User', + value: discordUser.toString(), + }, + { + inline: false, + name: 'Date', + value: date, + }, + ], + footer: { text: `User ID: ${discordUser.id}` }, + color: Colors.Green, + }); -const timeoutRemovedEmbed = (discordUser: User) => makeEmbed({ - title: `${discordUser.tag} was successfully removed from timeout`, - color: Colors.Green, -}); +const timeoutRemovedEmbed = (discordUser: User) => + makeEmbed({ + title: `${discordUser.tag} was successfully removed from timeout`, + color: Colors.Green, + }); const noModLogs = makeEmbed({ title: 'Remove Timeout - No Mod Log', diff --git a/src/commands/moderation/infractions/functions/timeout.ts b/src/commands/moderation/infractions/functions/timeout.ts index 54af02b6..264647a0 100644 --- a/src/commands/moderation/infractions/functions/timeout.ts +++ b/src/commands/moderation/infractions/functions/timeout.ts @@ -9,80 +9,87 @@ const noConnEmbed = makeEmbed({ color: Colors.Red, }); -const failedTimeoutEmbed = (discordUser: User, error: any) => makeEmbed({ - title: 'Timeout - Failed', - description: makeLines([ - `Failed to timeout ${discordUser.toString()}`, - '', - error, - ]), - color: Colors.Red, -}); - -const DMEmbed = (moderator: User, timeoutDuration: string, reason: string, guild: Guild, timedOutUntil: Date) => makeEmbed({ - title: `You have been timed out in ${guild.name}`, - description: 'This timeout is also logged against your record.', - fields: [ - { - inline: true, - name: 'Duration', - value: durationInEnglish(timeoutDuration), +const failedTimeoutEmbed = (discordUser: User, error: any) => + makeEmbed({ + title: 'Timeout - Failed', + description: makeLines([`Failed to timeout ${discordUser.toString()}`, '', error]), + color: Colors.Red, + }); + +const DMEmbed = (moderator: User, timeoutDuration: string, reason: string, guild: Guild, timedOutUntil: Date) => + makeEmbed({ + title: `You have been timed out in ${guild.name}`, + description: 'This timeout is also logged against your record.', + fields: [ + { + inline: true, + name: 'Duration', + value: durationInEnglish(timeoutDuration), + }, + { + inline: true, + name: 'Moderator', + value: moderator.toString(), + }, + { + inline: false, + name: 'Reason', + value: reason, + }, + ], + footer: { text: `Your timeout will be lifted on ${timedOutUntil.toUTCString()}` }, + }); + +const timeoutEmbed = (discordUser: User) => + makeEmbed({ + title: `${discordUser.tag} was timed out successfully`, + color: Colors.Green, + }); + +const DMFailed = (discordUser: User) => + makeEmbed({ + title: 'Timeout - DM not sent', + description: `DM was not sent to ${discordUser.toString()}, they either have DMs closed or share no mutual servers with the bot.`, + color: Colors.Red, + }); + +const modLogEmbed = ( + moderator: User, + discordUser: User, + timeoutReason: string, + timeoutDuration: string, + formattedDate: string, +) => + makeEmbed({ + author: { + name: `[TIMED OUT] ${discordUser.tag}`, + iconURL: discordUser.displayAvatarURL(), }, - { - inline: true, - name: 'Moderator', - value: moderator.toString(), - }, - { - inline: false, - name: 'Reason', - value: reason, - }, - ], - footer: { text: `Your timeout will be lifted on ${timedOutUntil.toUTCString()}` }, -}); - -const timeoutEmbed = (discordUser: User) => makeEmbed({ - title: `${discordUser.tag} was timed out successfully`, - color: Colors.Green, -}); - -const DMFailed = (discordUser: User) => makeEmbed({ - title: 'Timeout - DM not sent', - description: `DM was not sent to ${discordUser.toString()}, they either have DMs closed or share no mutual servers with the bot.`, - color: Colors.Red, -}); - -const modLogEmbed = (moderator: User, discordUser: User, timeoutReason: string, timeoutDuration: string, formattedDate: string) => makeEmbed({ - author: { - name: `[TIMED OUT] ${discordUser.tag}`, - iconURL: discordUser.displayAvatarURL(), - }, - fields: [ - { - name: 'User', - value: discordUser.toString(), - }, - { - name: 'Moderator', - value: `${moderator}`, - }, - { - name: 'Reason', - value: `\u200B${timeoutReason}`, - }, - { - name: 'Duration', - value: durationInEnglish(timeoutDuration), - }, - { - name: 'Date', - value: formattedDate, - }, - ], - footer: { text: `User ID: ${discordUser.id}` }, - color: Colors.Red, -}); + fields: [ + { + name: 'User', + value: discordUser.toString(), + }, + { + name: 'Moderator', + value: `${moderator}`, + }, + { + name: 'Reason', + value: `\u200B${timeoutReason}`, + }, + { + name: 'Duration', + value: durationInEnglish(timeoutDuration), + }, + { + name: 'Date', + value: formattedDate, + }, + ], + footer: { text: `User ID: ${discordUser.id}` }, + color: Colors.Red, + }); const noModLogs = makeEmbed({ title: 'Timeout - No Mod Log', @@ -96,11 +103,12 @@ const logFailed = makeEmbed({ color: Colors.Red, }); -const communicationNotDisabledEmbed = (discordUser: User) => makeEmbed({ - title: 'Timeout - Communication not disabled', - description: `Bot has not detected that ${discordUser.toString()} was successfully timed out. Timeout may have failed.`, - color: Colors.Red, -}); +const communicationNotDisabledEmbed = (discordUser: User) => + makeEmbed({ + title: 'Timeout - Communication not disabled', + description: `Bot has not detected that ${discordUser.toString()} was successfully timed out. Timeout may have failed.`, + color: Colors.Red, + }); export async function handleTimeoutInfraction(interaction: ChatInputCommandInteraction<'cached'>) { await interaction.deferReply({ ephemeral: true }); @@ -119,9 +127,7 @@ export async function handleTimeoutInfraction(interaction: ChatInputCommandInter const discordUser = await interaction.guild.members.fetch(userID); const moderator = interaction.user; const currentDate = new Date(); - const formattedDate: string = moment(currentDate) - .utcOffset(0) - .format(); + const formattedDate: string = moment(currentDate).utcOffset(0).format(); const modLogsChannel = interaction.guild.channels.resolve(constantsConfig.channels.MOD_LOGS) as TextChannel; //Try to timeout the user @@ -134,11 +140,22 @@ export async function handleTimeoutInfraction(interaction: ChatInputCommandInter return; } - if (discordUser.isCommunicationDisabled()) { //Timeout was successful + if (discordUser.isCommunicationDisabled()) { + //Timeout was successful await interaction.editReply({ embeds: [timeoutEmbed(discordUser.user)] }); //Try and send a Dm to the user try { - await discordUser.send({ embeds: [DMEmbed(moderator, timeoutDuration.toString(), timeoutReason, interaction.guild, discordUser.communicationDisabledUntil)] }); + await discordUser.send({ + embeds: [ + DMEmbed( + moderator, + timeoutDuration.toString(), + timeoutReason, + interaction.guild, + discordUser.communicationDisabledUntil, + ), + ], + }); } catch { if (modLogsChannel) { await interaction.followUp({ embeds: [DMFailed(discordUser.user)], ephemeral: true }); @@ -146,7 +163,11 @@ export async function handleTimeoutInfraction(interaction: ChatInputCommandInter } //Send a mod log to the mod logs channel try { - await modLogsChannel.send({ embeds: [modLogEmbed(moderator, discordUser.user, timeoutReason, timeoutDuration.toString(), formattedDate)] }); + await modLogsChannel.send({ + embeds: [ + modLogEmbed(moderator, discordUser.user, timeoutReason, timeoutDuration.toString(), formattedDate), + ], + }); } catch { await interaction.followUp({ embeds: [noModLogs], ephemeral: true }); return; diff --git a/src/commands/moderation/infractions/functions/unbanInfractions.ts b/src/commands/moderation/infractions/functions/unbanInfractions.ts index 48894f24..964566e1 100644 --- a/src/commands/moderation/infractions/functions/unbanInfractions.ts +++ b/src/commands/moderation/infractions/functions/unbanInfractions.ts @@ -9,44 +9,48 @@ const noConnEmbed = makeEmbed({ color: Colors.Red, }); -const failedUnbanEmbed = (userID: string) => makeEmbed({ - title: 'Unban - Failed', - description: `Failed to Unban ${userID}, this user may not be banned.`, - color: Colors.Red, -}); - -const unbanEmbed = (userID: string) => makeEmbed({ - title: `${userID} was unbanned successfully`, - color: Colors.Green, -}); - -const modLogEmbed = (moderator: User, userID: string, banReason: string, formattedDate: string) => makeEmbed({ - author: { name: `[UNBANNED] ${userID}` }, - fields: [ - { - name: 'User', - value: userID, - }, - { - name: 'Moderator', - value: `${moderator}`, - }, - { - name: 'Reason', - value: `\u200B${banReason}`, - }, - { - name: 'Date', - value: formattedDate, - }, - ], - footer: { text: `User ID: ${userID}` }, - color: Colors.Red, -}); +const failedUnbanEmbed = (userID: string) => + makeEmbed({ + title: 'Unban - Failed', + description: `Failed to Unban ${userID}, this user may not be banned.`, + color: Colors.Red, + }); + +const unbanEmbed = (userID: string) => + makeEmbed({ + title: `${userID} was unbanned successfully`, + color: Colors.Green, + }); + +const modLogEmbed = (moderator: User, userID: string, banReason: string, formattedDate: string) => + makeEmbed({ + author: { name: `[UNBANNED] ${userID}` }, + fields: [ + { + name: 'User', + value: userID, + }, + { + name: 'Moderator', + value: `${moderator}`, + }, + { + name: 'Reason', + value: `\u200B${banReason}`, + }, + { + name: 'Date', + value: formattedDate, + }, + ], + footer: { text: `User ID: ${userID}` }, + color: Colors.Red, + }); const noModLogs = makeEmbed({ title: 'Unban - No Mod Log', - description: 'I can\'t find the mod logs channel. I will still try to unban the user. Please check the channel still exists.', + description: + "I can't find the mod logs channel. I will still try to unban the user. Please check the channel still exists.", color: Colors.Red, }); @@ -72,9 +76,7 @@ export async function handleUnbanInfraction(interaction: ChatInputCommandInterac const moderator = interaction.user; const currentDate = new Date(); - const formattedDate: string = moment(currentDate) - .utcOffset(0) - .format(); + const formattedDate: string = moment(currentDate).utcOffset(0).format(); const modLogsChannel = interaction.guild.channels.resolve(constantsConfig.channels.MOD_LOGS) as TextChannel; //Check if the mod logs channel exists diff --git a/src/commands/moderation/infractions/functions/userNote.ts b/src/commands/moderation/infractions/functions/userNote.ts index 30d58cad..4e2ef024 100644 --- a/src/commands/moderation/infractions/functions/userNote.ts +++ b/src/commands/moderation/infractions/functions/userNote.ts @@ -15,41 +15,43 @@ const noteFailed = makeEmbed({ color: Colors.Red, }); -const modLogEmbed = (formattedDate: any, moderator: User, discordUser: User, note: string) => makeEmbed({ - author: { - name: `[NOTE] ${discordUser.tag}`, - iconURL: discordUser.displayAvatarURL(), - }, - fields: [ - { - inline: false, - name: 'User', - value: discordUser.toString(), +const modLogEmbed = (formattedDate: any, moderator: User, discordUser: User, note: string) => + makeEmbed({ + author: { + name: `[NOTE] ${discordUser.tag}`, + iconURL: discordUser.displayAvatarURL(), }, - { - inline: false, - name: 'Moderator', - value: moderator.toString(), - }, - { - inline: false, - name: 'Note', - value: note, - }, - { - inline: false, - name: 'Date', - value: formattedDate, - }, - ], - footer: { text: `User ID: ${discordUser.id}` }, - color: Colors.Red, -}); - -const noteEmbed = (user: User) => makeEmbed({ - title: `Note for ${user.tag} has been added successfully`, - color: Colors.Green, -}); + fields: [ + { + inline: false, + name: 'User', + value: discordUser.toString(), + }, + { + inline: false, + name: 'Moderator', + value: moderator.toString(), + }, + { + inline: false, + name: 'Note', + value: note, + }, + { + inline: false, + name: 'Date', + value: formattedDate, + }, + ], + footer: { text: `User ID: ${discordUser.id}` }, + color: Colors.Red, + }); + +const noteEmbed = (user: User) => + makeEmbed({ + title: `Note for ${user.tag} has been added successfully`, + color: Colors.Green, + }); const noModLogs = makeEmbed({ title: 'Note - No Mod Log', diff --git a/src/commands/moderation/infractions/functions/warn.ts b/src/commands/moderation/infractions/functions/warn.ts index 120e89f8..62a76dac 100644 --- a/src/commands/moderation/infractions/functions/warn.ts +++ b/src/commands/moderation/infractions/functions/warn.ts @@ -9,74 +9,79 @@ const noConnEmbed = makeEmbed({ color: Colors.Red, }); -const warnFailed = (discordUser: User) => makeEmbed({ - title: 'Warn - Failed', - description: `Failed to warn ${discordUser.toString()}, doc not saved to mongoDB`, - color: Colors.Red, -}); - -const dmEmbed = (guild: Guild, formattedDate: any, moderator: User, reason: string) => makeEmbed({ - title: `You have been warned in ${guild.name}`, - fields: [ - { - inline: false, - name: 'Moderator', - value: moderator.toString(), - }, - { - inline: false, - name: 'Reason', - value: reason, - }, - { - inline: false, - name: 'Date', - value: formattedDate, - }, - ], -}); - -const noDM = (discordUser: User) => makeEmbed({ - title: 'Warn - DM not sent', - description: `DM was not sent to ${discordUser.toString()}, they either have DMs closed or share no mutual servers with the bot.`, - color: Colors.Red, -}); - -const modLogEmbed = (formattedDate: any, moderator: User, discordUser: User, reason: string) => makeEmbed({ - author: { - name: `[WARNED] ${discordUser.tag}`, - iconURL: discordUser.displayAvatarURL(), - }, - fields: [ - { - inline: false, - name: 'User', - value: discordUser.toString(), - }, - { - inline: false, - name: 'Moderator', - value: moderator.toString(), - }, - { - inline: false, - name: 'Reason', - value: reason, - }, - { - inline: false, - name: 'Date', - value: formattedDate, +const warnFailed = (discordUser: User) => + makeEmbed({ + title: 'Warn - Failed', + description: `Failed to warn ${discordUser.toString()}, doc not saved to mongoDB`, + color: Colors.Red, + }); + +const dmEmbed = (guild: Guild, formattedDate: any, moderator: User, reason: string) => + makeEmbed({ + title: `You have been warned in ${guild.name}`, + fields: [ + { + inline: false, + name: 'Moderator', + value: moderator.toString(), + }, + { + inline: false, + name: 'Reason', + value: reason, + }, + { + inline: false, + name: 'Date', + value: formattedDate, + }, + ], + }); + +const noDM = (discordUser: User) => + makeEmbed({ + title: 'Warn - DM not sent', + description: `DM was not sent to ${discordUser.toString()}, they either have DMs closed or share no mutual servers with the bot.`, + color: Colors.Red, + }); + +const modLogEmbed = (formattedDate: any, moderator: User, discordUser: User, reason: string) => + makeEmbed({ + author: { + name: `[WARNED] ${discordUser.tag}`, + iconURL: discordUser.displayAvatarURL(), }, - ], - footer: { text: `User ID: ${discordUser.id}` }, - color: Colors.Red, -}); - -const warnEmbed = (discordUser: User) => makeEmbed({ - title: `${discordUser.tag} was warned successfully`, - color: Colors.Green, -}); + fields: [ + { + inline: false, + name: 'User', + value: discordUser.toString(), + }, + { + inline: false, + name: 'Moderator', + value: moderator.toString(), + }, + { + inline: false, + name: 'Reason', + value: reason, + }, + { + inline: false, + name: 'Date', + value: formattedDate, + }, + ], + footer: { text: `User ID: ${discordUser.id}` }, + color: Colors.Red, + }); + +const warnEmbed = (discordUser: User) => + makeEmbed({ + title: `${discordUser.tag} was warned successfully`, + color: Colors.Green, + }); const noModLogs = makeEmbed({ title: 'Warn - No Mod Log', diff --git a/src/commands/moderation/infractions/infractions.ts b/src/commands/moderation/infractions/infractions.ts index 4da67f02..7aa8e177 100644 --- a/src/commands/moderation/infractions/infractions.ts +++ b/src/commands/moderation/infractions/infractions.ts @@ -197,33 +197,33 @@ export default slashCommand(data, async ({ interaction }) => { const subcommandName = interaction.options.getSubcommand(); switch (subcommandName) { - case 'list': - const userID = interaction.options.getUser('tag_or_id')?.id; - await handleListInfraction(interaction, userID, false); - break; - case 'delete': - await handleDeleteInfraction(interaction); - break; - case 'note': - await handleUserNoteInfraction(interaction); - break; - case 'warn': - await handleWarnInfraction(interaction); - break; - case 'timeout': - await handleTimeoutInfraction(interaction); - break; - case 'remove-timeout': - await handleRemoveTimeoutInfraction(interaction); - break; - case 'ban': - await handleBanInfraction(interaction); - break; - case 'unban': - await handleUnbanInfraction(interaction); - break; + case 'list': + const userID = interaction.options.getUser('tag_or_id')?.id; + await handleListInfraction(interaction, userID, false); + break; + case 'delete': + await handleDeleteInfraction(interaction); + break; + case 'note': + await handleUserNoteInfraction(interaction); + break; + case 'warn': + await handleWarnInfraction(interaction); + break; + case 'timeout': + await handleTimeoutInfraction(interaction); + break; + case 'remove-timeout': + await handleRemoveTimeoutInfraction(interaction); + break; + case 'ban': + await handleBanInfraction(interaction); + break; + case 'unban': + await handleUnbanInfraction(interaction); + break; - default: - await interaction.reply({ content: 'Unknown subcommand', ephemeral: true }); + default: + await interaction.reply({ content: 'Unknown subcommand', ephemeral: true }); } }); diff --git a/src/commands/moderation/listRoleUsers.ts b/src/commands/moderation/listRoleUsers.ts index 8702463d..1da6ed73 100644 --- a/src/commands/moderation/listRoleUsers.ts +++ b/src/commands/moderation/listRoleUsers.ts @@ -1,5 +1,12 @@ import { ApplicationCommandOptionType, ApplicationCommandType } from 'discord.js'; -import { constantsConfig, Logger, makeEmbed, createPaginatedEmbedHandler, slashCommand, slashCommandStructure } from '../../lib'; +import { + constantsConfig, + Logger, + makeEmbed, + createPaginatedEmbedHandler, + slashCommand, + slashCommandStructure, +} from '../../lib'; const data = slashCommandStructure({ name: 'list-role-users', @@ -41,10 +48,12 @@ export default slashCommand(data, async ({ interaction }) => { membersAddedToPage++; if (membersAddedToPage >= pageLimit) { - embeds.push(makeEmbed({ - title: `Role Users | ${role.name} - Page ${currentPage + 1} of ${totalPages}`, - description, - })); + embeds.push( + makeEmbed({ + title: `Role Users | ${role.name} - Page ${currentPage + 1} of ${totalPages}`, + description, + }), + ); description = ''; membersAddedToPage = 0; currentPage++; @@ -52,10 +61,12 @@ export default slashCommand(data, async ({ interaction }) => { } if (description.trim() !== '') { - embeds.push(makeEmbed({ - title: `Role Users | ${role.name} - Page ${currentPage + 1} of ${totalPages}`, - description, - })); + embeds.push( + makeEmbed({ + title: `Role Users | ${role.name} - Page ${currentPage + 1} of ${totalPages}`, + description, + }), + ); } if (embeds.length === 0) { diff --git a/src/commands/moderation/roleAssignment.ts b/src/commands/moderation/roleAssignment.ts index 0ad0c832..f5eb2b7f 100644 --- a/src/commands/moderation/roleAssignment.ts +++ b/src/commands/moderation/roleAssignment.ts @@ -1,9 +1,4 @@ -import { - ActionRowBuilder, - ApplicationCommandType, - ButtonBuilder, - ButtonStyle, -} from 'discord.js'; +import { ActionRowBuilder, ApplicationCommandType, ButtonBuilder, ButtonStyle } from 'discord.js'; import { constantsConfig, makeEmbed, slashCommand, slashCommandStructure } from '../../lib'; const data = slashCommandStructure({ @@ -16,7 +11,8 @@ const data = slashCommandStructure({ const interestedInEmbed = makeEmbed({ title: 'Role Assignment', - description: 'Please react below to set your role according to your skill set. If you do not have the skills in any of the available roles, please do not react as this will not benefit the development of the addon.', + description: + 'Please react below to set your role according to your skill set. If you do not have the skills in any of the available roles, please do not react as this will not benefit the development of the addon.', }); const mediaAnnouncementsEmbed = makeEmbed({ diff --git a/src/commands/moderation/rules.ts b/src/commands/moderation/rules.ts index c0c83960..7cfdd839 100644 --- a/src/commands/moderation/rules.ts +++ b/src/commands/moderation/rules.ts @@ -49,7 +49,7 @@ const DISCUSSION_EMBED = makeEmbed({ '- Use of slurs or any form of bigotry is not tolerated', '- No inappropriate, NSFW or NSFL content like (but not limited to) nudity, pornography, gore, ...', '- No general spam', - '- Do not send multiple unsolicited DM\'s', + "- Do not send multiple unsolicited DM's", '- No troll or insensitive messaging, including insensitive inside jokes', '- Inappropriate/offensive profile information/picture will not be tolerated', '- Certain topics like politics, religion and other sensitive subjects will only be tolerated if a careful and respectful conversation is held', @@ -67,7 +67,9 @@ const ROLE_EMBED = makeEmbed({ export default slashCommand(data, async ({ interaction }) => { if (interaction.channel) { - await interaction.channel.send({ embeds: [RULES_EMBED, FAQ_EMBED, POLICIES_EMBED, DISCUSSION_EMBED, ROLE_EMBED] }); + await interaction.channel.send({ + embeds: [RULES_EMBED, FAQ_EMBED, POLICIES_EMBED, DISCUSSION_EMBED, ROLE_EMBED], + }); } else { await interaction.reply({ content: 'This command can only be used in a server.', ephemeral: true }); } diff --git a/src/commands/moderation/slowmode/functions/disable.ts b/src/commands/moderation/slowmode/functions/disable.ts index 2f5dd384..f9f3fb30 100644 --- a/src/commands/moderation/slowmode/functions/disable.ts +++ b/src/commands/moderation/slowmode/functions/disable.ts @@ -1,9 +1,24 @@ import { ChannelType, ChatInputCommandInteraction, Colors } from 'discord.js'; import { Logger } from '../../../../lib'; -export async function handleDisableSlowmode(interaction: ChatInputCommandInteraction<'cached'>, slowmodeChannel: any, modLogsChannel: any, scheduler: any, failedEmbed: any, noChannelEmbed: any, successEmbed: any, modLogEmbed: any, slowModeEmbedField: any) { +export async function handleDisableSlowmode( + interaction: ChatInputCommandInteraction<'cached'>, + slowmodeChannel: any, + modLogsChannel: any, + scheduler: any, + failedEmbed: any, + noChannelEmbed: any, + successEmbed: any, + modLogEmbed: any, + slowModeEmbedField: any, +) { try { - if (slowmodeChannel.type === ChannelType.GuildForum || slowmodeChannel.type === ChannelType.GuildText || slowmodeChannel.type === ChannelType.PrivateThread || slowmodeChannel.type === ChannelType.PublicThread) { + if ( + slowmodeChannel.type === ChannelType.GuildForum || + slowmodeChannel.type === ChannelType.GuildText || + slowmodeChannel.type === ChannelType.PrivateThread || + slowmodeChannel.type === ChannelType.PublicThread + ) { await slowmodeChannel.setRateLimitPerUser(0, 'Slow mode disabled through bot'); if (scheduler) { await scheduler.cancel({ name: 'autoDisableSlowMode', data: { channelId: slowmodeChannel.id } }); @@ -17,14 +32,13 @@ export async function handleDisableSlowmode(interaction: ChatInputCommandInterac try { await modLogsChannel.send({ - embeds: [modLogEmbed('disabled', - slowModeEmbedField( - interaction.user.toString(), - slowmodeChannel.id, - 0, - 0, + embeds: [ + modLogEmbed( + 'disabled', + slowModeEmbedField(interaction.user.toString(), slowmodeChannel.id, 0, 0), + Colors.Green, ), - Colors.Green)], + ], }); } catch { await interaction.reply({ embeds: [noChannelEmbed('Disable', 'Mod Log')] }); diff --git a/src/commands/moderation/slowmode/functions/set.ts b/src/commands/moderation/slowmode/functions/set.ts index 857d504b..e31199f7 100644 --- a/src/commands/moderation/slowmode/functions/set.ts +++ b/src/commands/moderation/slowmode/functions/set.ts @@ -1,8 +1,25 @@ import { ChannelType, ChatInputCommandInteraction, Colors } from 'discord.js'; -export async function handleSetSlowmode(interaction: ChatInputCommandInteraction<'cached'>, duration: number, slowmodeChannel: any, autoDisable: any, modLogsChannel: any, scheduler: any, failedEmbed: any, noChannelEmbed: any, successEmbed: any, modLogEmbed: any, slowModeEmbedField: any) { +export async function handleSetSlowmode( + interaction: ChatInputCommandInteraction<'cached'>, + duration: number, + slowmodeChannel: any, + autoDisable: any, + modLogsChannel: any, + scheduler: any, + failedEmbed: any, + noChannelEmbed: any, + successEmbed: any, + modLogEmbed: any, + slowModeEmbedField: any, +) { try { - if (slowmodeChannel.type === ChannelType.GuildForum || slowmodeChannel.type === ChannelType.GuildText || slowmodeChannel.type === ChannelType.PrivateThread || slowmodeChannel.type === ChannelType.PublicThread) { + if ( + slowmodeChannel.type === ChannelType.GuildForum || + slowmodeChannel.type === ChannelType.GuildText || + slowmodeChannel.type === ChannelType.PrivateThread || + slowmodeChannel.type === ChannelType.PublicThread + ) { await slowmodeChannel.setRateLimitPerUser(duration / 1000, 'Slow mode enabled through bot'); if (scheduler) { await scheduler.cancel({ name: 'autoDisableSlowMode', data: { channelId: slowmodeChannel.id } }); @@ -19,14 +36,18 @@ export async function handleSetSlowmode(interaction: ChatInputCommandInteraction try { await modLogsChannel.send({ - embeds: [modLogEmbed('Set', - slowModeEmbedField( - interaction.user.toString(), - slowmodeChannel.id, - duration, - autoDisable && scheduler ? autoDisable.toString() : 0, + embeds: [ + modLogEmbed( + 'Set', + slowModeEmbedField( + interaction.user.toString(), + slowmodeChannel.id, + duration, + autoDisable && scheduler ? autoDisable.toString() : 0, + ), + Colors.Green, ), - Colors.Green)], + ], }); } catch { await interaction.reply({ embeds: [noChannelEmbed('set', 'mod logs')], ephemeral: true }); diff --git a/src/commands/moderation/slowmode/slowmode.ts b/src/commands/moderation/slowmode/slowmode.ts index f192e5c0..85522a0b 100644 --- a/src/commands/moderation/slowmode/slowmode.ts +++ b/src/commands/moderation/slowmode/slowmode.ts @@ -1,5 +1,12 @@ import { ApplicationCommandOptionType, ApplicationCommandType, Colors, EmbedField, TextChannel } from 'discord.js'; -import { constantsConfig, slashCommand, slashCommandStructure, makeEmbed, durationInEnglish, getScheduler } from '../../../lib'; +import { + constantsConfig, + slashCommand, + slashCommandStructure, + makeEmbed, + durationInEnglish, + getScheduler, +} from '../../../lib'; import { handleSetSlowmode } from './functions/set'; import { handleDisableSlowmode } from './functions/disable'; @@ -85,19 +92,26 @@ const noSchedulerEmbed = makeEmbed({ color: Colors.Red, }); -const failedEmbed = (action: string, channel: string) => makeEmbed({ - title: `Slow Mode - ${action} failed`, - description: `Failed to ${action} the slow mode for channel <@${channel}>.`, - color: Colors.Red, -}); +const failedEmbed = (action: string, channel: string) => + makeEmbed({ + title: `Slow Mode - ${action} failed`, + description: `Failed to ${action} the slow mode for channel <@${channel}>.`, + color: Colors.Red, + }); -const modLogEmbed = (action: string, fields: any, color: number) => makeEmbed({ - title: `Slow Mode - ${action}`, - fields, - color, -}); +const modLogEmbed = (action: string, fields: any, color: number) => + makeEmbed({ + title: `Slow Mode - ${action}`, + fields, + color, + }); -const slowModeEmbedField = (moderator: string, channel: string, duration: number, autoDisable: string): EmbedField[] => [ +const slowModeEmbedField = ( + moderator: string, + channel: string, + duration: number, + autoDisable: string, +): EmbedField[] => [ { inline: true, name: 'Channel', @@ -120,17 +134,19 @@ const slowModeEmbedField = (moderator: string, channel: string, duration: number }, ]; -const noChannelEmbed = (action:string, channelName: string) => makeEmbed({ - title: `Slow Mode - ${action} - No ${channelName} channel`, - description: `The command was successful, but no message to ${channelName} was sent. Please check the channel still exists.`, - color: Colors.Yellow, -}); +const noChannelEmbed = (action: string, channelName: string) => + makeEmbed({ + title: `Slow Mode - ${action} - No ${channelName} channel`, + description: `The command was successful, but no message to ${channelName} was sent. Please check the channel still exists.`, + color: Colors.Yellow, + }); -const successEmbed = (action: string, channel: string) => makeEmbed({ - title: `Slow Mode - ${action} successful`, - description: `Slow mode for channel <#${channel}> has been ${action} successfully.`, - color: Colors.Green, -}); +const successEmbed = (action: string, channel: string) => + makeEmbed({ + title: `Slow Mode - ${action} successful`, + description: `Slow mode for channel <#${channel}> has been ${action} successfully.`, + color: Colors.Green, + }); export default slashCommand(data, async ({ interaction }) => { const scheduler = getScheduler(); @@ -146,14 +162,36 @@ export default slashCommand(data, async ({ interaction }) => { const subcommandName = interaction.options.getSubcommand(); switch (subcommandName) { - case 'set': - await handleSetSlowmode(interaction, duration, slowmodeChannel, autoDisable, modLogsChannel, scheduler, failedEmbed, noChannelEmbed, successEmbed, modLogEmbed, slowModeEmbedField); - break; - case 'disable': - await handleDisableSlowmode(interaction, slowmodeChannel, modLogsChannel, scheduler, failedEmbed, noChannelEmbed, successEmbed, modLogEmbed, slowModeEmbedField); - break; + case 'set': + await handleSetSlowmode( + interaction, + duration, + slowmodeChannel, + autoDisable, + modLogsChannel, + scheduler, + failedEmbed, + noChannelEmbed, + successEmbed, + modLogEmbed, + slowModeEmbedField, + ); + break; + case 'disable': + await handleDisableSlowmode( + interaction, + slowmodeChannel, + modLogsChannel, + scheduler, + failedEmbed, + noChannelEmbed, + successEmbed, + modLogEmbed, + slowModeEmbedField, + ); + break; - default: - await interaction.reply({ content: 'Unknown subcommand', ephemeral: true }); + default: + await interaction.reply({ content: 'Unknown subcommand', ephemeral: true }); } }); diff --git a/src/commands/moderation/welcome.ts b/src/commands/moderation/welcome.ts index 2b1f160e..bb6889c1 100644 --- a/src/commands/moderation/welcome.ts +++ b/src/commands/moderation/welcome.ts @@ -25,7 +25,6 @@ const WELCOME_EMBED = makeEmbed({ '', `Feel free to download, test, and share your feedback, or if you are interested in developing, assign your <#${constantsConfig.channels.ROLES}>, and get cracking!`, ]), - }); const SOCIAL_EMBED = makeEmbed({ @@ -50,7 +49,8 @@ const SUPPORT_EMBED = makeEmbed({ const IMPORTANT_INFO_EMBED = makeEmbed({ title: '<:Partnered:921520970123059231> FlyByWireSimulations | Important Info', - description: 'By being a member of our Discord Server, you agree to the following, and failure to do so can result in removal from the server.', + description: + 'By being a member of our Discord Server, you agree to the following, and failure to do so can result in removal from the server.', fields: [ { name: 'Appropriate Content', @@ -92,7 +92,6 @@ const HELP_EMBED = makeEmbed({ name: 'Flight School', value: `We've opened our <#${constantsConfig.channels.FLIGHT_SCHOOL}> channel for any questions you have pertaining to the operation of the A32NX in the simulator.`, }, - ], }); diff --git a/src/commands/moderation/whois.ts b/src/commands/moderation/whois.ts index 917cba5a..23a3fd5f 100644 --- a/src/commands/moderation/whois.ts +++ b/src/commands/moderation/whois.ts @@ -8,12 +8,14 @@ const data = slashCommandStructure({ type: ApplicationCommandType.ChatInput, default_member_permissions: constantsConfig.commandPermission.MANAGE_SERVER, //Overrides need to be added for admin and moderator roles dm_permission: false, - options: [{ - name: 'tag_or_id', - description: 'Provide a user\'s tag or id to get information about them.', - type: ApplicationCommandOptionType.User, - required: false, - }], + options: [ + { + name: 'tag_or_id', + description: "Provide a user's tag or id to get information about them.", + type: ApplicationCommandOptionType.User, + required: false, + }, + ], }); const beautifiedStatus: { [key: string]: string } = { @@ -72,7 +74,11 @@ export default slashCommand(data, async ({ interaction }) => { }, { name: 'Permissions', - value: targetMember.permissions.toArray().join(', ').toLowerCase().replace(/_/g, ' ') + value: targetMember.permissions + .toArray() + .join(', ') + .toLowerCase() + .replace(/_/g, ' ') .replace(/(^\w)|(\s+\w)/g, (char) => char.toUpperCase()), }, ], diff --git a/src/commands/utils/avatar.ts b/src/commands/utils/avatar.ts index 941e37e4..6c3f1bb6 100644 --- a/src/commands/utils/avatar.ts +++ b/src/commands/utils/avatar.ts @@ -3,14 +3,16 @@ import { slashCommand, slashCommandStructure, makeEmbed } from '../../lib'; const data = slashCommandStructure({ name: 'avatar', - description: 'Shows the selected user\'s avatar', + description: "Shows the selected user's avatar", type: ApplicationCommandType.ChatInput, - options: [{ - name: 'tag_or_id', - description: 'Please provide a user tag or ID.', - type: ApplicationCommandOptionType.User, - required: false, - }], + options: [ + { + name: 'tag_or_id', + description: 'Please provide a user tag or ID.', + type: ApplicationCommandOptionType.User, + required: false, + }, + ], }); export default slashCommand(data, async ({ interaction }) => { diff --git a/src/commands/utils/birthday/birthday.ts b/src/commands/utils/birthday/birthday.ts index 71fab53f..1efc77e7 100644 --- a/src/commands/utils/birthday/birthday.ts +++ b/src/commands/utils/birthday/birthday.ts @@ -84,17 +84,17 @@ export default slashCommand(data, async ({ interaction }) => { const subcommandName = interaction.options.getSubcommand(); switch (subcommandName) { - case 'set': - await handleSetBirthday(interaction); - break; - case 'remove': - await handleRemoveBirthday(interaction); - break; - case 'list': - await handleListBirthday(interaction); - break; + case 'set': + await handleSetBirthday(interaction); + break; + case 'remove': + await handleRemoveBirthday(interaction); + break; + case 'list': + await handleListBirthday(interaction); + break; - default: - await interaction.reply({ content: 'Unknown subcommand', ephemeral: true }); + default: + await interaction.reply({ content: 'Unknown subcommand', ephemeral: true }); } }); diff --git a/src/commands/utils/birthday/functions/listBirthday.ts b/src/commands/utils/birthday/functions/listBirthday.ts index 82369cad..9dfe9359 100644 --- a/src/commands/utils/birthday/functions/listBirthday.ts +++ b/src/commands/utils/birthday/functions/listBirthday.ts @@ -1,11 +1,12 @@ import { ChatInputCommandInteraction } from 'discord.js'; import { Birthday, Logger, makeEmbed } from '../../../../lib'; -const birthdayListEmbed = (fields: Array) => makeEmbed({ - title: 'Birthday - Birthday List', - description: fields.length > 0 ? undefined : 'No birthdays set', - fields, -}); +const birthdayListEmbed = (fields: Array) => + makeEmbed({ + title: 'Birthday - Birthday List', + description: fields.length > 0 ? undefined : 'No birthdays set', + fields, + }); export async function handleListBirthday(interaction: ChatInputCommandInteraction<'cached'>) { await interaction.deferReply(); @@ -33,7 +34,9 @@ export async function handleListBirthday(interaction: ChatInputCommandInteractio const member = members.get(birthday.userID!); if (member) { - monthBuckets[birthday.utcDatetime!.getUTCMonth()][1].push(`${member.displayName} - ${birthday.day}/${birthday.month} (Z${birthday.timezone! < 0 ? '' : '+'}${birthday.timezone})`); + monthBuckets[birthday.utcDatetime!.getUTCMonth()][1].push( + `${member.displayName} - ${birthday.day}/${birthday.month} (Z${birthday.timezone! < 0 ? '' : '+'}${birthday.timezone})`, + ); } } diff --git a/src/commands/utils/birthday/functions/removeBirthday.ts b/src/commands/utils/birthday/functions/removeBirthday.ts index 49c4539e..a2d6d90b 100644 --- a/src/commands/utils/birthday/functions/removeBirthday.ts +++ b/src/commands/utils/birthday/functions/removeBirthday.ts @@ -1,16 +1,18 @@ import { ChatInputCommandInteraction, Colors, User } from 'discord.js'; import { Birthday, makeEmbed } from '../../../../lib'; -const noBirthdayEmbed = (discordUser: User) => makeEmbed({ - title: 'Birthday remove failed', - description: `${discordUser} doesn't have a birthday set`, - color: Colors.Red, -}); +const noBirthdayEmbed = (discordUser: User) => + makeEmbed({ + title: 'Birthday remove failed', + description: `${discordUser} doesn't have a birthday set`, + color: Colors.Red, + }); -const birthdayRemovedEmbed = (discordUser: User) => makeEmbed({ - title: 'Birthday removed', - description: `${discordUser}'s birthday has been removed`, -}); +const birthdayRemovedEmbed = (discordUser: User) => + makeEmbed({ + title: 'Birthday removed', + description: `${discordUser}'s birthday has been removed`, + }); export async function handleRemoveBirthday(interaction: ChatInputCommandInteraction<'cached'>) { const userID = interaction.user.id; diff --git a/src/commands/utils/birthday/functions/setBirthday.ts b/src/commands/utils/birthday/functions/setBirthday.ts index 67714cfb..e55879db 100644 --- a/src/commands/utils/birthday/functions/setBirthday.ts +++ b/src/commands/utils/birthday/functions/setBirthday.ts @@ -31,10 +31,11 @@ const invalidDateEmbed = makeEmbed({ color: Colors.Red, }); -const birthdaySetEmbed = (discordUser: User, birthdayDay: number, birthdayMonth: number, birthdayTimezone: number) => makeEmbed({ - title: 'Birthday - Birthday Set', - description: `${discordUser}'s birthday has been set to ${birthdayDay}/${birthdayMonth} and their timezone is UTC${birthdayTimezone < 0 ? '' : '+'}${birthdayTimezone}`, -}); +const birthdaySetEmbed = (discordUser: User, birthdayDay: number, birthdayMonth: number, birthdayTimezone: number) => + makeEmbed({ + title: 'Birthday - Birthday Set', + description: `${discordUser}'s birthday has been set to ${birthdayDay}/${birthdayMonth} and their timezone is UTC${birthdayTimezone < 0 ? '' : '+'}${birthdayTimezone}`, + }); export async function handleSetBirthday(interaction: ChatInputCommandInteraction<'cached'>) { const selectedDay = interaction.options.getInteger('day')!; diff --git a/src/commands/utils/count.ts b/src/commands/utils/count.ts index ad6bf7dd..0ca98801 100644 --- a/src/commands/utils/count.ts +++ b/src/commands/utils/count.ts @@ -17,7 +17,7 @@ const data = slashCommandStructure({ }); export default slashCommand(data, async ({ interaction }) => { -// check if user has the role + // check if user has the role const hasRole = interaction.member.roles.cache.has(constantsConfig.roles.BOT_DEVELOPER); if (!hasRole) { diff --git a/src/commands/utils/docSearch.ts b/src/commands/utils/docSearch.ts index 4a4ee487..fc941422 100644 --- a/src/commands/utils/docSearch.ts +++ b/src/commands/utils/docSearch.ts @@ -6,13 +6,15 @@ const data = slashCommandStructure({ name: 'doc-search', description: 'Searches the FlyByWire Documentation for a given query.', type: ApplicationCommandType.ChatInput, - options: [{ - name: 'query', - description: 'The query to search for.', - type: ApplicationCommandOptionType.String, - max_length: 100, - required: true, - }], + options: [ + { + name: 'query', + description: 'The query to search for.', + type: ApplicationCommandOptionType.String, + max_length: 100, + required: true, + }, + ], }); const DOCS_BASE_URL = 'https://docs.flybywiresim.com'; @@ -33,7 +35,9 @@ export default slashCommand(data, async ({ interaction }) => { color: Colors.Red, }); return interaction.reply({ embeds: [URLEmbed] }); - } catch (_) { /**/ } + } catch (_) { + /**/ + } const filter = new Filter(); if (filter.isProfane(searchWord)) { diff --git a/src/commands/utils/github/functions/githubPullRequest.ts b/src/commands/utils/github/functions/githubPullRequest.ts index c656d566..f656d479 100644 --- a/src/commands/utils/github/functions/githubPullRequest.ts +++ b/src/commands/utils/github/functions/githubPullRequest.ts @@ -35,7 +35,9 @@ export async function handleGithubPullRequest(interaction: ChatInputCommandInter } } else { try { - const response = await request('GET /repos/flybywiresim/a32nx/pulls/{pull_number}', { pull_number: cleanedPrNumber }); + const response = await request('GET /repos/flybywiresim/a32nx/pulls/{pull_number}', { + pull_number: cleanedPrNumber, + }); return interaction.reply(response.data.html_url); } catch { return interaction.reply({ embeds: [invalidEmbed] }); diff --git a/src/commands/utils/github/functions/handleGithubIssue.ts b/src/commands/utils/github/functions/handleGithubIssue.ts index cb7864a4..0611e36b 100644 --- a/src/commands/utils/github/functions/handleGithubIssue.ts +++ b/src/commands/utils/github/functions/handleGithubIssue.ts @@ -35,7 +35,9 @@ export async function handleGithubIssue(interaction: ChatInputCommandInteraction } } else { try { - const response = await request('GET /repos/flybywiresim/a32nx/issues/{issue_number}', { issue_number: cleanedIssueNumber }); + const response = await request('GET /repos/flybywiresim/a32nx/issues/{issue_number}', { + issue_number: cleanedIssueNumber, + }); return interaction.reply(response.data.html_url); } catch { return interaction.reply({ embeds: [invalidEmbed] }); diff --git a/src/commands/utils/github/github.ts b/src/commands/utils/github/github.ts index 3cfec522..0de351c8 100644 --- a/src/commands/utils/github/github.ts +++ b/src/commands/utils/github/github.ts @@ -12,36 +12,38 @@ const data = slashCommandStructure({ name: 'pr', description: 'Retrieves the link of the provided GitHub pull request.', type: ApplicationCommandOptionType.Subcommand, - options: [{ - name: 'pr_number', - description: 'Please provide the pull request number.', - type: ApplicationCommandOptionType.String, - required: true, - }, - { - name: 'repo', - description: 'Please provide the repo name.', - type: ApplicationCommandOptionType.String, - required: false, - }, + options: [ + { + name: 'pr_number', + description: 'Please provide the pull request number.', + type: ApplicationCommandOptionType.String, + required: true, + }, + { + name: 'repo', + description: 'Please provide the repo name.', + type: ApplicationCommandOptionType.String, + required: false, + }, ], }, { name: 'issue', description: 'Retrieves the link of the provided GitHub issue.', type: ApplicationCommandOptionType.Subcommand, - options: [{ - name: 'issue_number', - description: 'Please provide the issue number.', - type: ApplicationCommandOptionType.String, - required: true, - }, - { - name: 'repo', - description: 'Please provide the repo name.', - type: ApplicationCommandOptionType.String, - required: false, - }, + options: [ + { + name: 'issue_number', + description: 'Please provide the issue number.', + type: ApplicationCommandOptionType.String, + required: true, + }, + { + name: 'repo', + description: 'Please provide the repo name.', + type: ApplicationCommandOptionType.String, + required: false, + }, ], }, ], @@ -51,14 +53,14 @@ export default slashCommand(data, async ({ interaction }) => { const subcommandName = interaction.options.getSubcommand(); switch (subcommandName) { - case 'pr': - await handleGithubPullRequest(interaction); - break; - case 'issue': - await handleGithubIssue(interaction); - break; + case 'pr': + await handleGithubPullRequest(interaction); + break; + case 'issue': + await handleGithubIssue(interaction); + break; - default: - await interaction.reply({ content: 'Unknown subcommand', ephemeral: true }); + default: + await interaction.reply({ content: 'Unknown subcommand', ephemeral: true }); } }); diff --git a/src/commands/utils/help.ts b/src/commands/utils/help.ts index 7702a60a..3c92ee1e 100644 --- a/src/commands/utils/help.ts +++ b/src/commands/utils/help.ts @@ -46,52 +46,55 @@ export default slashCommand(data, async ({ interaction }: { interaction: Command const totalPages = Math.ceil(sortedCommands.length / pageLimit); // Build the description with subcommands and subcommand groups - const description = currentCommands.map((command) => { - let { description } = command; - - // Check if it's a context-specific message command - const isMessageCommand = command.type === ApplicationCommandType.Message; - - // Check if it's a context-specific user command - const isUserCommand = command.type === ApplicationCommandType.User; - - const subcommandList = command.options?.filter( - (option) => option.type === ApplicationCommandOptionType.Subcommand - || option.type === ApplicationCommandOptionType.SubcommandGroup, - ); - - if (subcommandList && subcommandList.length > 0) { - const subcommandDescription = subcommandList - .map((subcommand) => { - if (subcommand.type === ApplicationCommandOptionType.Subcommand) { - return subcommand.name; - } - if (subcommand.type === ApplicationCommandOptionType.SubcommandGroup) { - const groupSubcommands = subcommand.options?.filter( - (sub) => sub.type === ApplicationCommandOptionType.Subcommand, - ); - if (groupSubcommands && groupSubcommands.length > 0) { - return `${subcommand.name} [${groupSubcommands - .map((sub) => sub.name) - .join(', ')}]`; + const description = currentCommands + .map((command) => { + let { description } = command; + + // Check if it's a context-specific message command + const isMessageCommand = command.type === ApplicationCommandType.Message; + + // Check if it's a context-specific user command + const isUserCommand = command.type === ApplicationCommandType.User; + + const subcommandList = command.options?.filter( + (option) => + option.type === ApplicationCommandOptionType.Subcommand || + option.type === ApplicationCommandOptionType.SubcommandGroup, + ); + + if (subcommandList && subcommandList.length > 0) { + const subcommandDescription = subcommandList + .map((subcommand) => { + if (subcommand.type === ApplicationCommandOptionType.Subcommand) { + return subcommand.name; } - return `${subcommand.name} [None]`; - } - return ''; - }) - .join(', '); // Use a comma to separate subcommands - description += `\n**Subcommands and Groups:** \n${subcommandDescription}`; - } - - // Append a label for context-specific message and user commands - if (isMessageCommand) { - description += '\n(Context Command - Message)'; - } else if (isUserCommand) { - description += '\n(Context Command - User)'; - } - - return `**${command.name}**: ${description}`; - }).join('\n\n'); + if (subcommand.type === ApplicationCommandOptionType.SubcommandGroup) { + const groupSubcommands = subcommand.options?.filter( + (sub) => sub.type === ApplicationCommandOptionType.Subcommand, + ); + if (groupSubcommands && groupSubcommands.length > 0) { + return `${subcommand.name} [${groupSubcommands + .map((sub) => sub.name) + .join(', ')}]`; + } + return `${subcommand.name} [None]`; + } + return ''; + }) + .join(', '); // Use a comma to separate subcommands + description += `\n**Subcommands and Groups:** \n${subcommandDescription}`; + } + + // Append a label for context-specific message and user commands + if (isMessageCommand) { + description += '\n(Context Command - Message)'; + } else if (isUserCommand) { + description += '\n(Context Command - User)'; + } + + return `**${command.name}**: ${description}`; + }) + .join('\n\n'); const embed = makeEmbed({ title: `Bot Commands - Page ${page + 1} of ${totalPages}`, diff --git a/src/commands/utils/locate/functions/filterSearchResults.ts b/src/commands/utils/locate/functions/filterSearchResults.ts index c0779d4d..ceb1d4f6 100644 --- a/src/commands/utils/locate/functions/filterSearchResults.ts +++ b/src/commands/utils/locate/functions/filterSearchResults.ts @@ -3,7 +3,9 @@ import { Panel } from '../panels/panel'; export const filterSearchResults = (query: string, source: Map) => { // Get any target that includes the query string. - const possibleTargets = Array.from(source.keys()).filter((current) => current.toLowerCase().includes(query.toLowerCase())); + const possibleTargets = Array.from(source.keys()).filter((current) => + current.toLowerCase().includes(query.toLowerCase()), + ); // Sort possible targets based on the length of the match. -> More equal characters between query and target = higher ranking possibleTargets.sort((a, b) => a.indexOf(query) - b.indexOf(query)); diff --git a/src/commands/utils/locate/functions/handleCommand.ts b/src/commands/utils/locate/functions/handleCommand.ts index 9f339b6d..35ae8e24 100644 --- a/src/commands/utils/locate/functions/handleCommand.ts +++ b/src/commands/utils/locate/functions/handleCommand.ts @@ -15,17 +15,18 @@ const invalidTargetEmbed = makeEmbed({ color: Colors.Red, }); -const locateEmbed = (panel: Panel) => makeEmbed({ - title: panel.title, - url: panel.docsUrl, - description: makeLines([ - `Learn more about the ${panel.name} and the flight deck:`, - `* [${panel.name} Documentation](${panel.docsUrl})`, - `* [Flight Deck Overview](${panel.flightDeckUrl})`, - ]), - image: { url: panel.imageUrl }, - footer: { text: 'Tip: Click the image to view in full size' }, -}); +const locateEmbed = (panel: Panel) => + makeEmbed({ + title: panel.title, + url: panel.docsUrl, + description: makeLines([ + `Learn more about the ${panel.name} and the flight deck:`, + `* [${panel.name} Documentation](${panel.docsUrl})`, + `* [Flight Deck Overview](${panel.flightDeckUrl})`, + ]), + image: { url: panel.imageUrl }, + footer: { text: 'Tip: Click the image to view in full size' }, + }); export async function handleCommand(interaction: ChatInputCommandInteraction<'cached'>, panelMap: Map) { const target = interaction.options.getString('target'); diff --git a/src/commands/utils/locate/locate.ts b/src/commands/utils/locate/locate.ts index 13dd0f6e..a50b4838 100644 --- a/src/commands/utils/locate/locate.ts +++ b/src/commands/utils/locate/locate.ts @@ -68,34 +68,38 @@ const autocompleteCallback: AutocompleteCallback = ({ interaction }) => { let choices: ApplicationCommandOptionChoiceData[]; switch (subcommand) { - case 'a32nx': - choices = filterSearchResults(cleanTarget, a32nxPanelMap); - break; - /* case 'a380x': + case 'a32nx': + choices = filterSearchResults(cleanTarget, a32nxPanelMap); + break; + /* case 'a380x': choices = filterSearchResults(cleanTarget, a380xPanelMap); break; */ - default: - return interaction.respond([]); + default: + return interaction.respond([]); } return interaction.respond(choices); }; -export default slashCommand(data, async ({ interaction }) => { - await interaction.deferReply(); +export default slashCommand( + data, + async ({ interaction }) => { + await interaction.deferReply(); - const subcommand = interaction.options.getSubcommand(); + const subcommand = interaction.options.getSubcommand(); - switch (subcommand) { - case 'a32nx': - await handleCommand(interaction, a32nxPanelMap); - break; - /* case 'a380x': + switch (subcommand) { + case 'a32nx': + await handleCommand(interaction, a32nxPanelMap); + break; + /* case 'a380x': await handleCommand(interaction, a380xPanelMap); break; */ - default: - await interaction.editReply({ content: 'Unknown subcommand' }); - } -}, autocompleteCallback); + default: + await interaction.editReply({ content: 'Unknown subcommand' }); + } + }, + autocompleteCallback, +); diff --git a/src/commands/utils/locate/panels/a32nx/a32nx-panels.ts b/src/commands/utils/locate/panels/a32nx/a32nx-panels.ts index 51272118..91632077 100644 --- a/src/commands/utils/locate/panels/a32nx/a32nx-panels.ts +++ b/src/commands/utils/locate/panels/a32nx/a32nx-panels.ts @@ -1,9 +1,73 @@ import { Panel } from '../panel'; import { flyPad } from './flyPad'; -import { accuPressPanel, autobrakeAndGearPanel, clockPanel, dcdu, ewd, instrumentLightingPanel, isis, nd, pfd, sd } from './front-panel'; +import { + accuPressPanel, + autobrakeAndGearPanel, + clockPanel, + dcdu, + ewd, + instrumentLightingPanel, + isis, + nd, + pfd, + sd, +} from './front-panel'; import { efisPanel, fcuPanel, lightKnobsPanel, warningPanel } from './glareshield'; -import { antiIcePanel, adirsPanel, apuPanel, callsPanel, cvrPanel, emerElecPwrPanel, evacPanel, extLtPanel, fltCtlPanel, gpwsPanel, intLtPanel, oxyPanel, paVideoPanel, signsPanel, wiperPanel, cabinPressPanel, airCondPanel, elecPanel, fuelPanel, hydPanel, firePanel, engManStartPanel, ventilationPanel, cargoSmokePanel, cargoVentPanel, thirdACP, readingLightsJumpSeats, cockpitDoorIndicatorPanel, eltPanel, pedestalLightPanel, emerCbPanel, fmsLoadPanel, maintenancePanel } from './overhead'; -import { aidsDfdrPanel, atcTcasPanel, captPedestalLightingPanel, cockpitDoorPanel, console, ecamControlPanel, engPanel, flaps, gravityGearExtensionPanel, mcdu, parkBrkPanel, printer, rmpAcpPanel, rudderTrim, speedBrake, switchingPanel, thrLvrPitchTrim, wxPanel } from './pedestal'; +import { + antiIcePanel, + adirsPanel, + apuPanel, + callsPanel, + cvrPanel, + emerElecPwrPanel, + evacPanel, + extLtPanel, + fltCtlPanel, + gpwsPanel, + intLtPanel, + oxyPanel, + paVideoPanel, + signsPanel, + wiperPanel, + cabinPressPanel, + airCondPanel, + elecPanel, + fuelPanel, + hydPanel, + firePanel, + engManStartPanel, + ventilationPanel, + cargoSmokePanel, + cargoVentPanel, + thirdACP, + readingLightsJumpSeats, + cockpitDoorIndicatorPanel, + eltPanel, + pedestalLightPanel, + emerCbPanel, + fmsLoadPanel, + maintenancePanel, +} from './overhead'; +import { + aidsDfdrPanel, + atcTcasPanel, + captPedestalLightingPanel, + cockpitDoorPanel, + console, + ecamControlPanel, + engPanel, + flaps, + gravityGearExtensionPanel, + mcdu, + parkBrkPanel, + printer, + rmpAcpPanel, + rudderTrim, + speedBrake, + switchingPanel, + thrLvrPitchTrim, + wxPanel, +} from './pedestal'; import { rearBackCbPanel } from './rear-cb-panel'; export const a32nxPanels: Panel[] = [ diff --git a/src/commands/utils/locate/panels/a32nx/flyPad.ts b/src/commands/utils/locate/panels/a32nx/flyPad.ts index 36e4dc0a..0b8e7194 100644 --- a/src/commands/utils/locate/panels/a32nx/flyPad.ts +++ b/src/commands/utils/locate/panels/a32nx/flyPad.ts @@ -7,9 +7,5 @@ export const flyPad: Panel = { docsUrl: LOCATE_DOCS_BASE_URLS.a32nx.flypad, flightDeckUrl: LOCATE_DOCS_BASE_URLS.a32nx.flightdeck, imageUrl: `${LOCATE_IMAGE_BASE_URLS.a32nx.flypad}/efb_downscaled.gif`, - identifiers: [ - 'flypad', - 'efb', - 'electronic-flight-bag', - ], + identifiers: ['flypad', 'efb', 'electronic-flight-bag'], }; diff --git a/src/commands/utils/locate/panels/a32nx/front-panel.ts b/src/commands/utils/locate/panels/a32nx/front-panel.ts index 6a75d57b..50c2e862 100644 --- a/src/commands/utils/locate/panels/a32nx/front-panel.ts +++ b/src/commands/utils/locate/panels/a32nx/front-panel.ts @@ -51,13 +51,7 @@ export const nd: Panel = { docsUrl: `${FRONT_DOCS_BASE_URL}/nd`, flightDeckUrl: LOCATE_DOCS_BASE_URLS.a32nx.flightdeck, imageUrl: `${FRONT_IMAGE_BASE_URL}/nd.png`, - identifiers: [ - 'nd', - 'navigation-display', - 'weather-radar', - 'terrain-map', - 'terr-on-nd-switch', - ], + identifiers: ['nd', 'navigation-display', 'weather-radar', 'terrain-map', 'terr-on-nd-switch'], }; export const isis: Panel = { @@ -66,11 +60,7 @@ export const isis: Panel = { docsUrl: `${FRONT_DOCS_BASE_URL}/isis`, flightDeckUrl: LOCATE_DOCS_BASE_URLS.a32nx.flightdeck, imageUrl: `${FRONT_IMAGE_BASE_URL}/isis.png`, - identifiers: [ - 'isis', - 'integrated-standby-instrument-system', - 'backup-pfd', - ], + identifiers: ['isis', 'integrated-standby-instrument-system', 'backup-pfd'], }; export const dcdu: Panel = { @@ -79,11 +69,7 @@ export const dcdu: Panel = { docsUrl: `${FRONT_DOCS_BASE_URL}/dcdu`, flightDeckUrl: LOCATE_DOCS_BASE_URLS.a32nx.flightdeck, imageUrl: `${FRONT_IMAGE_BASE_URL}/dcdu.png`, - identifiers: [ - 'dcdu', - 'datalink-ctl-and-display-unit', - 'cpdlc', - ], + identifiers: ['dcdu', 'datalink-ctl-and-display-unit', 'cpdlc'], }; export const ewd: Panel = { @@ -92,13 +78,7 @@ export const ewd: Panel = { docsUrl: `${FRONT_DOCS_BASE_URL}/upper-ecam`, flightDeckUrl: LOCATE_DOCS_BASE_URLS.a32nx.flightdeck, imageUrl: `${FRONT_IMAGE_BASE_URL}/ewd.png`, - identifiers: [ - 'ecam-upper', - 'upper-ecam', - 'ewd', - 'engine-and-warning-display', - 'n1-display', - ], + identifiers: ['ecam-upper', 'upper-ecam', 'ewd', 'engine-and-warning-display', 'n1-display'], }; export const sd: Panel = { @@ -144,10 +124,7 @@ export const clockPanel: Panel = { docsUrl: `${FRONT_DOCS_BASE_URL}/clock`, flightDeckUrl: LOCATE_DOCS_BASE_URLS.a32nx.flightdeck, imageUrl: `${FRONT_IMAGE_BASE_URL}/clock.png`, - identifiers: [ - 'clock', - 'date', - ], + identifiers: ['clock', 'date'], }; export const accuPressPanel: Panel = { @@ -156,9 +133,5 @@ export const accuPressPanel: Panel = { docsUrl: `${FRONT_DOCS_BASE_URL}/accu`, flightDeckUrl: LOCATE_DOCS_BASE_URLS.a32nx.flightdeck, imageUrl: `${FRONT_IMAGE_BASE_URL}/accu_press.png`, - identifiers: [ - 'accu-press', - 'accumulator-pressure-indicator', - 'brake-pressure-indicator', - ], + identifiers: ['accu-press', 'accumulator-pressure-indicator', 'brake-pressure-indicator'], }; diff --git a/src/commands/utils/locate/panels/a32nx/glareshield.ts b/src/commands/utils/locate/panels/a32nx/glareshield.ts index c7f999a5..c49ccad7 100644 --- a/src/commands/utils/locate/panels/a32nx/glareshield.ts +++ b/src/commands/utils/locate/panels/a32nx/glareshield.ts @@ -93,9 +93,5 @@ export const lightKnobsPanel: Panel = { docsUrl: `${GLARESHIELD_DOCS_BASE_URL}/light-knobs/`, flightDeckUrl: LOCATE_DOCS_BASE_URLS.a32nx.flightdeck, imageUrl: `${GLARESHIELD_IMAGE_BASE_URL}/light_knobs.png`, - identifiers: [ - 'table-light-knob', - 'integral-glareshield-lighting-knob', - 'fcu-brightness-knob', - ], + identifiers: ['table-light-knob', 'integral-glareshield-lighting-knob', 'fcu-brightness-knob'], }; diff --git a/src/commands/utils/locate/panels/a32nx/overhead.ts b/src/commands/utils/locate/panels/a32nx/overhead.ts index bb3c89b0..05d55d0c 100644 --- a/src/commands/utils/locate/panels/a32nx/overhead.ts +++ b/src/commands/utils/locate/panels/a32nx/overhead.ts @@ -32,11 +32,7 @@ export const callsPanel: Panel = { docsUrl: `${OVHD_DOCS_BASE_URL}/calls/`, flightDeckUrl: LOCATE_DOCS_BASE_URLS.a32nx.flightdeck, imageUrl: `${OVHD_IMAGE_BASE_URL}/calls.png`, - identifiers: [ - 'calls-panel', - 'call', - 'calls', - ], + identifiers: ['calls-panel', 'call', 'calls'], }; export const oxyPanel: Panel = { @@ -45,13 +41,7 @@ export const oxyPanel: Panel = { docsUrl: `${OVHD_DOCS_BASE_URL}/oxygen/`, flightDeckUrl: LOCATE_DOCS_BASE_URLS.a32nx.flightdeck, imageUrl: `${OVHD_IMAGE_BASE_URL}/oxygen.png`, - identifiers: [ - 'oxy', - 'oxygen-panel', - 'oxygen', - 'mask-man-on-switch', - 'crew-supply-switch', - ], + identifiers: ['oxy', 'oxygen-panel', 'oxygen', 'mask-man-on-switch', 'crew-supply-switch'], }; export const cvrPanel: Panel = { @@ -113,14 +103,7 @@ export const evacPanel: Panel = { docsUrl: `${OVHD_DOCS_BASE_URL}/evacuation/`, flightDeckUrl: LOCATE_DOCS_BASE_URLS.a32nx.flightdeck, imageUrl: `${OVHD_IMAGE_BASE_URL}/evac.png`, - identifiers: [ - 'evac-panel', - 'evac', - 'evacuation', - 'command-switch', - 'horn-shut-off-button', - 'capt-purs-switch', - ], + identifiers: ['evac-panel', 'evac', 'evacuation', 'command-switch', 'horn-shut-off-button', 'capt-purs-switch'], }; export const fltCtlPanel: Panel = { @@ -129,14 +112,7 @@ export const fltCtlPanel: Panel = { docsUrl: `${OVHD_DOCS_BASE_URL}/flight-control-computer/`, flightDeckUrl: LOCATE_DOCS_BASE_URLS.a32nx.flightdeck, imageUrl: `${OVHD_IMAGE_BASE_URL}/flt_ctl.png`, - identifiers: [ - 'flight-controls', - 'flight-control-panel', - 'flt-ctl', - 'elac', - 'sec', - 'fac', - ], + identifiers: ['flight-controls', 'flight-control-panel', 'flt-ctl', 'elac', 'sec', 'fac'], }; export const adirsPanel: Panel = { @@ -145,14 +121,7 @@ export const adirsPanel: Panel = { docsUrl: `${OVHD_DOCS_BASE_URL}/adirs/`, flightDeckUrl: LOCATE_DOCS_BASE_URLS.a32nx.flightdeck, imageUrl: `${OVHD_IMAGE_BASE_URL}/adirs.png`, - identifiers: [ - 'adirs-panel', - 'adirs', - 'adiru', - 'irs', - 'adr', - 'ir-selector', - ], + identifiers: ['adirs-panel', 'adirs', 'adiru', 'irs', 'adr', 'ir-selector'], }; export const paVideoPanel: Panel = { @@ -161,13 +130,7 @@ export const paVideoPanel: Panel = { docsUrl: `${OVHD_DOCS_BASE_URL}/pa-cockpit-video/`, flightDeckUrl: LOCATE_DOCS_BASE_URLS.a32nx.flightdeck, imageUrl: `${OVHD_IMAGE_BASE_URL}/pa_video.png`, - identifiers: [ - 'pa-panel', - 'video', - 'cockpit-video-panel', - 'cockpit-door-video', - 'cockpit-door-video-switch', - ], + identifiers: ['pa-panel', 'video', 'cockpit-video-panel', 'cockpit-door-video', 'cockpit-door-video-switch'], }; export const extLtPanel: Panel = { @@ -202,13 +165,7 @@ export const apuPanel: Panel = { docsUrl: `${OVHD_DOCS_BASE_URL}/apu/`, flightDeckUrl: LOCATE_DOCS_BASE_URLS.a32nx.flightdeck, imageUrl: `${OVHD_IMAGE_BASE_URL}/apu.png`, - identifiers: [ - 'apu-panel', - 'apu', - 'auxiliary-power-unit', - 'apu-master-switch', - 'apu-start-button', - ], + identifiers: ['apu-panel', 'apu', 'auxiliary-power-unit', 'apu-master-switch', 'apu-start-button'], }; export const signsPanel: Panel = { @@ -348,15 +305,7 @@ export const fuelPanel: Panel = { docsUrl: `${OVHD_DOCS_BASE_URL}/fuel/`, flightDeckUrl: LOCATE_DOCS_BASE_URLS.a32nx.flightdeck, imageUrl: `${OVHD_IMAGE_BASE_URL}/fuel.png`, - identifiers: [ - 'fuel', - 'fuel-panel', - 'fuel-pumps', - 'x-feed', - 'cross-feed', - 'wing-tanks', - 'center-tanks', - ], + identifiers: ['fuel', 'fuel-panel', 'fuel-pumps', 'x-feed', 'cross-feed', 'wing-tanks', 'center-tanks'], }; export const hydPanel: Panel = { @@ -386,13 +335,7 @@ export const firePanel: Panel = { docsUrl: `${OVHD_DOCS_BASE_URL}/fire/`, flightDeckUrl: LOCATE_DOCS_BASE_URLS.a32nx.flightdeck, imageUrl: `${OVHD_IMAGE_BASE_URL}/fire.png`, - identifiers: [ - 'engine-fire-panel', - 'fire', - 'smoke', - 'fire-agent', - 'disch', - ], + identifiers: ['engine-fire-panel', 'fire', 'smoke', 'fire-agent', 'disch'], }; export const engManStartPanel: Panel = { @@ -401,11 +344,7 @@ export const engManStartPanel: Panel = { docsUrl: `${OVHD_DOCS_BASE_URL}/eng-man/`, flightDeckUrl: LOCATE_DOCS_BASE_URLS.a32nx.flightdeck, imageUrl: `${OVHD_IMAGE_BASE_URL}/eng_n1.png`, - identifiers: [ - 'eng-n1', - 'manual-engine-start', - 'eng-man-start-switch', - ], + identifiers: ['eng-n1', 'manual-engine-start', 'eng-man-start-switch'], }; export const ventilationPanel: Panel = { @@ -414,13 +353,7 @@ export const ventilationPanel: Panel = { docsUrl: `${OVHD_DOCS_BASE_URL}/vent/`, flightDeckUrl: LOCATE_DOCS_BASE_URLS.a32nx.flightdeck, imageUrl: `${OVHD_IMAGE_BASE_URL}/ventilation.png`, - identifiers: [ - 'vent', - 'ventilation-panel', - 'cabin-fans', - 'blower-switch', - 'extract-ventilation-switch', - ], + identifiers: ['vent', 'ventilation-panel', 'cabin-fans', 'blower-switch', 'extract-ventilation-switch'], }; export const cargoSmokePanel: Panel = { @@ -429,10 +362,7 @@ export const cargoSmokePanel: Panel = { docsUrl: `${OVHD_DOCS_BASE_URL}/cargo-smoke/`, flightDeckUrl: LOCATE_DOCS_BASE_URLS.a32nx.flightdeck, imageUrl: `${OVHD_IMAGE_BASE_URL}/cargo_smoke.png`, - identifiers: [ - 'cargo-fire', - 'cargo-smoke-panel', - ], + identifiers: ['cargo-fire', 'cargo-smoke-panel'], }; export const cargoVentPanel: Panel = { @@ -441,11 +371,7 @@ export const cargoVentPanel: Panel = { docsUrl: `${OVHD_DOCS_BASE_URL}/cargo-vent/`, flightDeckUrl: LOCATE_DOCS_BASE_URLS.a32nx.flightdeck, imageUrl: `${OVHD_IMAGE_BASE_URL}/cargo_vent.png`, - identifiers: [ - 'cargo-vent-panel', - 'cargo-ventilation', - 'aft-isol-valve-switch', - ], + identifiers: ['cargo-vent-panel', 'cargo-ventilation', 'aft-isol-valve-switch'], }; export const thirdACP: Panel = { @@ -454,11 +380,7 @@ export const thirdACP: Panel = { docsUrl: `${OVHD_DOCS_BASE_URL}/3rd-acp/`, flightDeckUrl: LOCATE_DOCS_BASE_URLS.a32nx.flightdeck, imageUrl: `${OVHD_IMAGE_BASE_URL}/acp_3.png`, - identifiers: [ - 'acp3', - '3rd-acp', - '3rd-audio-control-panel', - ], + identifiers: ['acp3', '3rd-acp', '3rd-audio-control-panel'], }; export const readingLightsJumpSeats: Panel = { @@ -467,10 +389,7 @@ export const readingLightsJumpSeats: Panel = { docsUrl: `${AFT_OVHD_DOCS_BASE_URL}/reading-light/`, flightDeckUrl: LOCATE_DOCS_BASE_URLS.a32nx.flightdeck, imageUrl: `${AFT_OVHD_IMAGE_BASE_URL}/jump_seat_reading_lt.png`, - identifiers: [ - 'reading-lights-jump-seat', - 'jump-seat-reading-lights', - ], + identifiers: ['reading-lights-jump-seat', 'jump-seat-reading-lights'], }; export const cockpitDoorIndicatorPanel: Panel = { @@ -479,10 +398,7 @@ export const cockpitDoorIndicatorPanel: Panel = { docsUrl: `${AFT_OVHD_DOCS_BASE_URL}/cockpit-door/#description`, flightDeckUrl: LOCATE_DOCS_BASE_URLS.a32nx.flightdeck, imageUrl: `${AFT_OVHD_IMAGE_BASE_URL}/ckpt_door_cont.png`, - identifiers: [ - 'cockpit-door-cont', - 'cockpit-door-indicator-panel', - ], + identifiers: ['cockpit-door-cont', 'cockpit-door-indicator-panel'], }; export const eltPanel: Panel = { @@ -491,11 +407,7 @@ export const eltPanel: Panel = { docsUrl: `${AFT_OVHD_DOCS_BASE_URL}/elt/`, flightDeckUrl: LOCATE_DOCS_BASE_URLS.a32nx.flightdeck, imageUrl: `${AFT_OVHD_IMAGE_BASE_URL}/elt.png`, - identifiers: [ - 'elt', - 'elt-panel', - 'emergency-locator-transmitter', - ], + identifiers: ['elt', 'elt-panel', 'emergency-locator-transmitter'], }; export const pedestalLightPanel: Panel = { @@ -504,11 +416,7 @@ export const pedestalLightPanel: Panel = { docsUrl: `${AFT_OVHD_DOCS_BASE_URL}/pedestal-light/`, flightDeckUrl: LOCATE_DOCS_BASE_URLS.a32nx.flightdeck, imageUrl: `${AFT_OVHD_IMAGE_BASE_URL}/pedestal_light.png`, - identifiers: [ - 'pedestal-light-panel', - 'acp3-switching-selector', - 'audio-control-panel-3-switching-selector', - ], + identifiers: ['pedestal-light-panel', 'acp3-switching-selector', 'audio-control-panel-3-switching-selector'], }; export const emerCbPanel: Panel = { @@ -517,10 +425,7 @@ export const emerCbPanel: Panel = { docsUrl: `${AFT_OVHD_DOCS_BASE_URL}/circuit/`, flightDeckUrl: LOCATE_DOCS_BASE_URLS.a32nx.flightdeck, imageUrl: `${AFT_OVHD_IMAGE_BASE_URL}/emer_cb.png`, - identifiers: [ - 'emer-cb', - 'emergency-circuit-breaker-panel', - ], + identifiers: ['emer-cb', 'emergency-circuit-breaker-panel'], }; export const fmsLoadPanel: Panel = { @@ -529,9 +434,7 @@ export const fmsLoadPanel: Panel = { docsUrl: `${AFT_OVHD_DOCS_BASE_URL}/fms-load/`, flightDeckUrl: LOCATE_DOCS_BASE_URLS.a32nx.flightdeck, imageUrl: `${AFT_OVHD_IMAGE_BASE_URL}/fms_load.png`, - identifiers: [ - 'fms-load-panel', - ], + identifiers: ['fms-load-panel'], }; export const maintenancePanel: Panel = { diff --git a/src/commands/utils/locate/panels/a32nx/pedestal.ts b/src/commands/utils/locate/panels/a32nx/pedestal.ts index d3beb6e3..81f3f862 100644 --- a/src/commands/utils/locate/panels/a32nx/pedestal.ts +++ b/src/commands/utils/locate/panels/a32nx/pedestal.ts @@ -27,12 +27,7 @@ export const mcdu: Panel = { docsUrl: `${PEDESTAL_DOCS_BASE_URL}/mcdu`, flightDeckUrl: LOCATE_DOCS_BASE_URLS.a32nx.flightdeck, imageUrl: `${PEDESTAL_IMAGE_BASE_URL}/mcdu.png`, - identifiers: [ - 'fms', - 'cdu', - 'mcdu', - 'fmgc', - ], + identifiers: ['fms', 'cdu', 'mcdu', 'fmgc'], }; export const rmpAcpPanel: Panel = { @@ -41,13 +36,7 @@ export const rmpAcpPanel: Panel = { docsUrl: `${PEDESTAL_DOCS_BASE_URL}/rmp`, flightDeckUrl: LOCATE_DOCS_BASE_URLS.a32nx.flightdeck, imageUrl: `${PEDESTAL_IMAGE_BASE_URL}/rmp_acp.png`, - identifiers: [ - 'rmp', - 'radio-management-panel', - 'acp', - 'audio-control-panel', - 'atc-panel', - ], + identifiers: ['rmp', 'radio-management-panel', 'acp', 'audio-control-panel', 'atc-panel'], }; export const captPedestalLightingPanel: Panel = { @@ -56,9 +45,7 @@ export const captPedestalLightingPanel: Panel = { docsUrl: `${PEDESTAL_DOCS_BASE_URL}/lighting-capt`, flightDeckUrl: LOCATE_DOCS_BASE_URLS.a32nx.flightdeck, imageUrl: `${PEDESTAL_IMAGE_BASE_URL}/capt_pedestal_lt.png`, - identifiers: [ - 'captain-pedestal-lighting-panel', - ], + identifiers: ['captain-pedestal-lighting-panel'], }; export const wxPanel: Panel = { @@ -67,13 +54,7 @@ export const wxPanel: Panel = { docsUrl: `${PEDESTAL_DOCS_BASE_URL}/radar`, flightDeckUrl: LOCATE_DOCS_BASE_URLS.a32nx.flightdeck, imageUrl: `${PEDESTAL_IMAGE_BASE_URL}/wx_radar.png`, - identifiers: [ - 'wx', - 'weather-radar', - 'wx-radar', - 'pws', - 'predictive-windshear-systems', - ], + identifiers: ['wx', 'weather-radar', 'wx-radar', 'pws', 'predictive-windshear-systems'], }; export const speedBrake: Panel = { @@ -82,12 +63,7 @@ export const speedBrake: Panel = { docsUrl: `${PEDESTAL_DOCS_BASE_URL}/speedbrake`, flightDeckUrl: LOCATE_DOCS_BASE_URLS.a32nx.flightdeck, imageUrl: `${PEDESTAL_IMAGE_BASE_URL}/spd_brk.png`, - identifiers: [ - 'speed-brake', - 'spd-brk', - 'spoilers', - 'gnd-sprls', - ], + identifiers: ['speed-brake', 'spd-brk', 'spoilers', 'gnd-sprls'], }; export const cockpitDoorPanel: Panel = { @@ -96,12 +72,7 @@ export const cockpitDoorPanel: Panel = { docsUrl: `${PEDESTAL_DOCS_BASE_URL}/cockpit-door`, flightDeckUrl: LOCATE_DOCS_BASE_URLS.a32nx.flightdeck, imageUrl: `${PEDESTAL_IMAGE_BASE_URL}/cockpit_door.png`, - identifiers: [ - 'cockpit-door', - 'cockpit-door-panel', - 'cockpit-door-switch', - 'cockpit-door-video-button', - ], + identifiers: ['cockpit-door', 'cockpit-door-panel', 'cockpit-door-switch', 'cockpit-door-video-button'], }; export const switchingPanel: Panel = { @@ -180,9 +151,7 @@ export const rudderTrim: Panel = { docsUrl: `${PEDESTAL_DOCS_BASE_URL}/rudder-trim`, flightDeckUrl: LOCATE_DOCS_BASE_URLS.a32nx.flightdeck, imageUrl: `${PEDESTAL_IMAGE_BASE_URL}/rudder_trim.png`, - identifiers: [ - 'rudder-trim', - ], + identifiers: ['rudder-trim'], }; export const parkBrkPanel: Panel = { @@ -191,10 +160,7 @@ export const parkBrkPanel: Panel = { docsUrl: `${PEDESTAL_DOCS_BASE_URL}/parking-brake`, flightDeckUrl: LOCATE_DOCS_BASE_URLS.a32nx.flightdeck, imageUrl: `${PEDESTAL_IMAGE_BASE_URL}/park_brk.png`, - identifiers: [ - 'parking-brake', - 'park-brk', - ], + identifiers: ['parking-brake', 'park-brk'], }; export const gravityGearExtensionPanel: Panel = { @@ -203,9 +169,7 @@ export const gravityGearExtensionPanel: Panel = { docsUrl: `${PEDESTAL_DOCS_BASE_URL}/gravity-gear-ext`, flightDeckUrl: LOCATE_DOCS_BASE_URLS.a32nx.flightdeck, imageUrl: `${PEDESTAL_IMAGE_BASE_URL}/gravity_gear_extn.png`, - identifiers: [ - 'gravity-gear-extension', - ], + identifiers: ['gravity-gear-extension'], }; export const aidsDfdrPanel: Panel = { @@ -214,14 +178,7 @@ export const aidsDfdrPanel: Panel = { docsUrl: `${PEDESTAL_DOCS_BASE_URL}/lighting-aids-dfdr`, flightDeckUrl: LOCATE_DOCS_BASE_URLS.a32nx.flightdeck, imageUrl: `${PEDESTAL_IMAGE_BASE_URL}/aids_dfdr.png`, - identifiers: [ - 'aids', - 'dfdr', - 'ped-flood-lt-knob', - 'pedestal-flood-light-knob', - 'aids-button', - 'dfdr-button', - ], + identifiers: ['aids', 'dfdr', 'ped-flood-lt-knob', 'pedestal-flood-light-knob', 'aids-button', 'dfdr-button'], }; export const atcTcasPanel: Panel = { @@ -230,13 +187,7 @@ export const atcTcasPanel: Panel = { docsUrl: `${PEDESTAL_DOCS_BASE_URL}/atc-tcas`, flightDeckUrl: LOCATE_DOCS_BASE_URLS.a32nx.flightdeck, imageUrl: `${PEDESTAL_IMAGE_BASE_URL}/atc_tcas.png`, - identifiers: [ - 'xpdr', - 'atc-tcas-panel', - 'transponder', - 'tcas', - 'alt-rptg-switch', - ], + identifiers: ['xpdr', 'atc-tcas-panel', 'transponder', 'tcas', 'alt-rptg-switch'], }; export const flaps: Panel = { @@ -245,9 +196,7 @@ export const flaps: Panel = { docsUrl: `${PEDESTAL_DOCS_BASE_URL}/flaps`, flightDeckUrl: LOCATE_DOCS_BASE_URLS.a32nx.flightdeck, imageUrl: `${PEDESTAL_IMAGE_BASE_URL}/flaps.png`, - identifiers: [ - 'flaps', - ], + identifiers: ['flaps'], }; export const printer: Panel = { @@ -256,7 +205,5 @@ export const printer: Panel = { docsUrl: `${PEDESTAL_DOCS_BASE_URL}/printer`, flightDeckUrl: LOCATE_DOCS_BASE_URLS.a32nx.flightdeck, imageUrl: `${PEDESTAL_IMAGE_BASE_URL}/printer.png`, - identifiers: [ - 'printer', - ], + identifiers: ['printer'], }; diff --git a/src/commands/utils/locate/panels/a32nx/rear-cb-panel.ts b/src/commands/utils/locate/panels/a32nx/rear-cb-panel.ts index 87f6037f..5a801244 100644 --- a/src/commands/utils/locate/panels/a32nx/rear-cb-panel.ts +++ b/src/commands/utils/locate/panels/a32nx/rear-cb-panel.ts @@ -7,8 +7,5 @@ export const rearBackCbPanel: Panel = { docsUrl: `${LOCATE_DOCS_BASE_URLS.a32nx.aftOverhead}/circuit/#rear-right-back-panel`, flightDeckUrl: LOCATE_DOCS_BASE_URLS.a32nx.flightdeck, imageUrl: `${LOCATE_IMAGE_BASE_URLS.a32nx.rearCb}/rear_right_back.jpg`, - identifiers: [ - 'rear-back-circuit-breaker-panel', - 'secondary-circuit-breaker-panel', - ], + identifiers: ['rear-back-circuit-breaker-panel', 'secondary-circuit-breaker-panel'], }; diff --git a/src/commands/utils/metar.ts b/src/commands/utils/metar.ts index dd688e48..4a5ae8b3 100644 --- a/src/commands/utils/metar.ts +++ b/src/commands/utils/metar.ts @@ -6,14 +6,16 @@ const data = slashCommandStructure({ name: 'metar', description: 'Provides the METAR report of the requested airport', type: ApplicationCommandType.ChatInput, - options: [{ - name: 'icao', - description: 'Provide an airport ICAO code.', - type: ApplicationCommandOptionType.String, - max_length: 4, - min_length: 4, - required: true, - }], + options: [ + { + name: 'icao', + description: 'Provide an airport ICAO code.', + type: ApplicationCommandOptionType.String, + max_length: 4, + min_length: 4, + required: true, + }, + ], }); export default slashCommand(data, async ({ interaction }) => { @@ -36,8 +38,7 @@ export default slashCommand(data, async ({ interaction }) => { const metarReport: any = await fetch(`https://avwx.rest/api/metar/${icao}`, { method: 'GET', headers: { Authorization: metarToken }, - }) - .then((res) => res.json()); + }).then((res) => res.json()); if (metarReport.error) { const invalidEmbed = makeEmbed({ @@ -70,7 +71,9 @@ export default slashCommand(data, async ({ interaction }) => { inline: false, }, ], - footer: { text: 'This METAR report may not accurately reflect the weather in the simulator. However, it will always be similar to the current conditions present in the sim.' }, + footer: { + text: 'This METAR report may not accurately reflect the weather in the simulator. However, it will always be similar to the current conditions present in the sim.', + }, }); return interaction.editReply({ embeds: [metarEmbed] }); diff --git a/src/commands/utils/ping.ts b/src/commands/utils/ping.ts index 5d29b95b..93c8f6a5 100644 --- a/src/commands/utils/ping.ts +++ b/src/commands/utils/ping.ts @@ -5,13 +5,15 @@ const data = slashCommandStructure({ name: 'ping', description: 'Ping the bot for a response.', type: ApplicationCommandType.ChatInput, - options: [{ - name: 'message', - description: 'Provide some text to send back.', - type: ApplicationCommandOptionType.String, - max_length: 100, - required: false, - }], + options: [ + { + name: 'message', + description: 'Provide some text to send back.', + type: ApplicationCommandOptionType.String, + max_length: 100, + required: false, + }, + ], }); export default slashCommand(data, async ({ interaction }) => { diff --git a/src/commands/utils/reportedIssues.ts b/src/commands/utils/reportedIssues.ts index c00677e7..0390431f 100644 --- a/src/commands/utils/reportedIssues.ts +++ b/src/commands/utils/reportedIssues.ts @@ -6,17 +6,20 @@ const data = slashCommandStructure({ name: 'reported-issues', description: 'Provides a link to the reported issues page within docs.', type: ApplicationCommandType.ChatInput, - options: [{ - name: 'query', - description: 'Provide a query to search for.', - type: ApplicationCommandOptionType.String, - max_length: 100, - required: true, - }], + options: [ + { + name: 'query', + description: 'Provide a query to search for.', + type: ApplicationCommandOptionType.String, + max_length: 100, + required: true, + }, + ], }); const FBW_DOCS_REPORTED_ISSUES_URL = 'https://docs.flybywiresim.com/fbw-a32nx/support/reported-issues/'; -const FBW_DOCS_AUTOPILOT_ISSUES_URL = 'https://docs.flybywiresim.com/fbw-a32nx/feature-guides/autopilot-fbw/#typical-issues-and-how-to-solve-them'; +const FBW_DOCS_AUTOPILOT_ISSUES_URL = + 'https://docs.flybywiresim.com/fbw-a32nx/feature-guides/autopilot-fbw/#typical-issues-and-how-to-solve-them'; const FBW_DOCS_SIMBRIDGE_ISSUES_URL = 'https://docs.flybywiresim.com/simbridge/troubleshooting/'; const genericReportedIssuesEmbed = makeEmbed({ @@ -24,11 +27,13 @@ const genericReportedIssuesEmbed = makeEmbed({ description: `I couldn't find a match foy your query. Please see [this link](${FBW_DOCS_REPORTED_ISSUES_URL}) for a current list of reported issues.`, }); -const issueInSubsectionEmbed = (fields: EmbedField[]) => makeEmbed({ - title: 'FlyByWire A32NX | Reported Issues', - description: 'Your issue is in our reported issues list. Please try the possible solutions in the following link(s) and report back if they didn\'t help. Include all the steps you tried.', - fields, -}); +const issueInSubsectionEmbed = (fields: EmbedField[]) => + makeEmbed({ + title: 'FlyByWire A32NX | Reported Issues', + description: + "Your issue is in our reported issues list. Please try the possible solutions in the following link(s) and report back if they didn't help. Include all the steps you tried.", + fields, + }); const subsectionLinkEmbedField = (id: string, title: string): EmbedField[] => [ { @@ -50,12 +55,15 @@ const simbridgeEmbed = makeEmbed({ const generalTroubleshootingEmbed = makeEmbed({ title: 'FlyByWire A32NX | Reported Issues', - description: 'Please try the general troubleshooting steps from our reported issues page and report back if they didn\'t help. Include all the steps you tried.', - fields: [{ - inline: false, - name: 'General Troubleshooting Steps', - value: `[Link to reported issues section](${FBW_DOCS_REPORTED_ISSUES_URL}#general-troubleshooting-steps)`, - }], + description: + "Please try the general troubleshooting steps from our reported issues page and report back if they didn't help. Include all the steps you tried.", + fields: [ + { + inline: false, + name: 'General Troubleshooting Steps', + value: `[Link to reported issues section](${FBW_DOCS_REPORTED_ISSUES_URL}#general-troubleshooting-steps)`, + }, + ], }); const tooManyResultsEmbed = makeEmbed({ @@ -102,7 +110,9 @@ export default slashCommand(data, async ({ interaction }) => { return interaction.reply({ embeds: [genericReportedIssuesEmbed] }); } - const fields = reportedIssues.map((sectionElement: any) => subsectionLinkEmbedField(sectionElement.id, sectionElement.title)).flat(); + const fields = reportedIssues + .map((sectionElement: any) => subsectionLinkEmbedField(sectionElement.id, sectionElement.title)) + .flat(); return interaction.reply({ embeds: [issueInSubsectionEmbed(fields)] }); } catch (error: any) { Logger.error(error); diff --git a/src/commands/utils/roleInfo.ts b/src/commands/utils/roleInfo.ts index 8ba7233f..86c87e2a 100644 --- a/src/commands/utils/roleInfo.ts +++ b/src/commands/utils/roleInfo.ts @@ -3,14 +3,16 @@ import { slashCommand, slashCommandStructure, makeEmbed } from '../../lib'; const data = slashCommandStructure({ name: 'role-info', - description: 'Lists the given role\'s amount of members.', + description: "Lists the given role's amount of members.", type: ApplicationCommandType.ChatInput, - options: [{ - name: 'role', - description: 'Provide the role to get info about.', - type: ApplicationCommandOptionType.Role, - required: true, - }], + options: [ + { + name: 'role', + description: 'Provide the role to get info about.', + type: ApplicationCommandOptionType.Role, + required: true, + }, + ], }); export default slashCommand(data, async ({ interaction }) => { diff --git a/src/commands/utils/searchFaq.ts b/src/commands/utils/searchFaq.ts index 465a07c2..29ebe50b 100644 --- a/src/commands/utils/searchFaq.ts +++ b/src/commands/utils/searchFaq.ts @@ -16,20 +16,21 @@ const data = slashCommandStructure({ ], }); -const noFaqsFoundEmbed = (searchTerm: string) => makeEmbed({ - title: `No FAQs found - ${searchTerm}`, - description: 'No FAQs found matching your search term. Please try again or see the links below.', - fields: [ - { - name: '**FAQ Channel**', - value: `<#${constantsConfig.channels.FAQ}>`, - }, - { - name: '**Docs FAQ**', - value: 'https://docs.flybywiresim.com/fbw-a32nx/faq/', - }, - ], -}); +const noFaqsFoundEmbed = (searchTerm: string) => + makeEmbed({ + title: `No FAQs found - ${searchTerm}`, + description: 'No FAQs found matching your search term. Please try again or see the links below.', + fields: [ + { + name: '**FAQ Channel**', + value: `<#${constantsConfig.channels.FAQ}>`, + }, + { + name: '**Docs FAQ**', + value: 'https://docs.flybywiresim.com/fbw-a32nx/faq/', + }, + ], + }); export default slashCommand(data, async ({ interaction }) => { const searchTerm = interaction.options.getString('search_term') ?? ''; diff --git a/src/commands/utils/simbriefData.ts b/src/commands/utils/simbriefData.ts index 26f81e69..50e456ce 100644 --- a/src/commands/utils/simbriefData.ts +++ b/src/commands/utils/simbriefData.ts @@ -11,13 +11,15 @@ const data = slashCommandStructure({ name: 'retrieve', description: 'Shows data for your last filed flight plan.', type: ApplicationCommandOptionType.Subcommand, - options: [{ - name: 'pilot_id', - description: 'Please provide your pilot ID.', - type: ApplicationCommandOptionType.String, - max_length: 100, - required: true, - }], + options: [ + { + name: 'pilot_id', + description: 'Please provide your pilot ID.', + type: ApplicationCommandOptionType.String, + max_length: 100, + required: true, + }, + ], }, { name: 'support-request', @@ -40,31 +42,33 @@ const simbriefdatarequestEmbed = makeEmbed({ ]), }); -const errorEmbed = (errorMessage: any) => makeEmbed({ - title: 'SimBrief Error', - description: makeLines(['SimBrief data could not be read.', errorMessage]), - color: Colors.Red, -}); - -const simbriefIdMismatchEmbed = (enteredId: any, flightplanId: any) => makeEmbed({ - title: 'SimBrief Data', - description: makeLines([ - `Entered pilotId ${enteredId} and returned pilotId ${flightplanId} don't match. The pilotId might be used as username by someone else.`, - ]), -}); +const errorEmbed = (errorMessage: any) => + makeEmbed({ + title: 'SimBrief Error', + description: makeLines(['SimBrief data could not be read.', errorMessage]), + color: Colors.Red, + }); -const simbriefEmbed = (flightplan: any) => makeEmbed({ - title: 'SimBrief Data', - description: makeLines([ - `**Generated at**: ${moment(flightplan.params.time_generated * 1000).format('DD.MM.YYYY, HH:mm:ss')}`, - `**AirFrame**: ${flightplan.aircraft.name} ${flightplan.aircraft.internal_id} ${(flightplan.aircraft.internal_id === FBW_AIRFRAME_ID) ? '(provided by FBW)' : ''}`, - `**AIRAC Cycle**: ${flightplan.params.airac}`, - `**Origin**: ${flightplan.origin.icao_code}`, - `**Destination**: ${flightplan.destination.icao_code}`, - `**Route**: ${flightplan.general.route}`, - ]), +const simbriefIdMismatchEmbed = (enteredId: any, flightplanId: any) => + makeEmbed({ + title: 'SimBrief Data', + description: makeLines([ + `Entered pilotId ${enteredId} and returned pilotId ${flightplanId} don't match. The pilotId might be used as username by someone else.`, + ]), + }); -}); +const simbriefEmbed = (flightplan: any) => + makeEmbed({ + title: 'SimBrief Data', + description: makeLines([ + `**Generated at**: ${moment(flightplan.params.time_generated * 1000).format('DD.MM.YYYY, HH:mm:ss')}`, + `**AirFrame**: ${flightplan.aircraft.name} ${flightplan.aircraft.internal_id} ${flightplan.aircraft.internal_id === FBW_AIRFRAME_ID ? '(provided by FBW)' : ''}`, + `**AIRAC Cycle**: ${flightplan.params.airac}`, + `**Origin**: ${flightplan.origin.icao_code}`, + `**Destination**: ${flightplan.destination.icao_code}`, + `**Route**: ${flightplan.general.route}`, + ]), + }); export default slashCommand(data, async ({ interaction }) => { if (interaction.options.getSubcommand() === 'support-request') { @@ -75,7 +79,9 @@ export default slashCommand(data, async ({ interaction }) => { const simbriefId = interaction.options.getString('pilot_id'); if (!simbriefId) return interaction.reply({ content: 'Invalid pilot ID!', ephemeral: true }); - const flightplan = await fetch(`https://www.simbrief.com/api/xml.fetcher.php?json=1&userid=${simbriefId}&username=${simbriefId}`).then((res) => res.json()); + const flightplan = await fetch( + `https://www.simbrief.com/api/xml.fetcher.php?json=1&userid=${simbriefId}&username=${simbriefId}`, + ).then((res) => res.json()); if (flightplan.fetch.status !== 'Success') { interaction.reply({ embeds: [errorEmbed(flightplan.fetch.status)], ephemeral: true }); diff --git a/src/commands/utils/station.ts b/src/commands/utils/station.ts index 8cde14a2..70fa684d 100644 --- a/src/commands/utils/station.ts +++ b/src/commands/utils/station.ts @@ -6,14 +6,16 @@ const data = slashCommandStructure({ name: 'station', description: 'Provides station information.', type: ApplicationCommandType.ChatInput, - options: [{ - name: 'icao', - description: 'Provide an airport ICAO code.', - type: ApplicationCommandOptionType.String, - max_length: 4, - min_length: 4, - required: true, - }], + options: [ + { + name: 'icao', + description: 'Provide an airport ICAO code.', + type: ApplicationCommandOptionType.String, + max_length: 4, + min_length: 4, + required: true, + }, + ], }); const noQueryEmbed = makeEmbed({ @@ -55,9 +57,12 @@ export default slashCommand(data, async ({ interaction }) => { return interaction.editReply({ embeds: [invalidEmbed] }); } - const runwayIdents = stationReport.runways.map((runways: any) => `**${runways.ident1}/${runways.ident2}:** ` - + `${runways.length_ft} ft x ${runways.width_ft} ft / ` - + `${Math.round(runways.length_ft * 0.3048)} m x ${Math.round(runways.width_ft * 0.3048)} m`); + const runwayIdents = stationReport.runways.map( + (runways: any) => + `**${runways.ident1}/${runways.ident2}:** ` + + `${runways.length_ft} ft x ${runways.width_ft} ft / ` + + `${Math.round(runways.length_ft * 0.3048)} m x ${Math.round(runways.width_ft * 0.3048)} m`, + ); const stationEmbed = makeEmbed({ title: `Station Info | ${stationReport.icao}`, diff --git a/src/commands/utils/taf.ts b/src/commands/utils/taf.ts index dba64551..78792ad3 100644 --- a/src/commands/utils/taf.ts +++ b/src/commands/utils/taf.ts @@ -6,14 +6,16 @@ const data = slashCommandStructure({ name: 'taf', description: 'Provides the TAF report of the requested airport.', type: ApplicationCommandType.ChatInput, - options: [{ - name: 'icao', - description: 'Provide an airport ICAO code.', - type: ApplicationCommandOptionType.String, - max_length: 4, - min_length: 4, - required: true, - }], + options: [ + { + name: 'icao', + description: 'Provide an airport ICAO code.', + type: ApplicationCommandOptionType.String, + max_length: 4, + min_length: 4, + required: true, + }, + ], }); const noQueryEmbed = makeEmbed({ @@ -86,7 +88,9 @@ export default slashCommand(data, async ({ interaction }) => { inline: false, }, ], - footer: { text: 'This TAF report is only a forecast, and may not accurately reflect weather in the simulator.' }, + footer: { + text: 'This TAF report is only a forecast, and may not accurately reflect weather in the simulator.', + }, }); return interaction.editReply({ embeds: [tafEmbed] }); diff --git a/src/commands/utils/vatsim/functions/vatsimControllers.ts b/src/commands/utils/vatsim/functions/vatsimControllers.ts index 08e5cd2b..32dcf34a 100644 --- a/src/commands/utils/vatsim/functions/vatsimControllers.ts +++ b/src/commands/utils/vatsim/functions/vatsimControllers.ts @@ -3,13 +3,21 @@ import { makeEmbed } from '../../../../lib'; /* eslint-disable camelcase */ -const listEmbed = (type: string, fields: EmbedField[], totalCount: number, shownCount: number, callsign: string) => makeEmbed({ - title: `VATSIM Data - ${callsign} - ${totalCount} ${type} online`, - description: `A list of ${shownCount} online ${type} matching ${callsign}.`, - fields, -}); +const listEmbed = (type: string, fields: EmbedField[], totalCount: number, shownCount: number, callsign: string) => + makeEmbed({ + title: `VATSIM Data - ${callsign} - ${totalCount} ${type} online`, + description: `A list of ${shownCount} online ${type} matching ${callsign}.`, + fields, + }); -const controllersListEmbedFields = (callsign: string, frequency: string, logon: string, rating: string, atis: string, atisCode: string): EmbedField[] => { +const controllersListEmbedFields = ( + callsign: string, + frequency: string, + logon: string, + rating: string, + atis: string, + atisCode: string, +): EmbedField[] => { const fields = [ { name: 'Callsign', @@ -49,38 +57,58 @@ const controllersListEmbedFields = (callsign: string, frequency: string, logon: return fields; }; -const handleLocaleDateTimeString = (date: Date) => date.toLocaleDateString('en-US', { - hour: 'numeric', - minute: 'numeric', - weekday: 'short', - month: 'short', - day: 'numeric', -}); +const handleLocaleDateTimeString = (date: Date) => + date.toLocaleDateString('en-US', { + hour: 'numeric', + minute: 'numeric', + weekday: 'short', + month: 'short', + day: 'numeric', + }); -export async function handleVatsimControllers(interaction: ChatInputCommandInteraction<'cached'>, vatsimData: any, callsignSearch: any) { - const vatsimAllControllers = vatsimData.controllers ? vatsimData.controllers.filter((controller: { facility: number; }) => controller.facility > 0) : null; +export async function handleVatsimControllers( + interaction: ChatInputCommandInteraction<'cached'>, + vatsimData: any, + callsignSearch: any, +) { + const vatsimAllControllers = vatsimData.controllers + ? vatsimData.controllers.filter((controller: { facility: number }) => controller.facility > 0) + : null; const vatsimControllerRatings = vatsimData.ratings ? vatsimData.ratings : null; - const vatsimControllers = vatsimAllControllers ? vatsimAllControllers.filter((controller: { callsign: string | string[]; }) => controller.callsign.includes(callsignSearch)) : null; - const vatsimAtis = vatsimData.atis ? vatsimData.atis.filter((atis: { callsign: string | string[]; }) => atis.callsign.includes(callsignSearch)) : null; + const vatsimControllers = vatsimAllControllers + ? vatsimAllControllers.filter((controller: { callsign: string | string[] }) => + controller.callsign.includes(callsignSearch), + ) + : null; + const vatsimAtis = vatsimData.atis + ? vatsimData.atis.filter((atis: { callsign: string | string[] }) => atis.callsign.includes(callsignSearch)) + : null; const { keys }: ObjectConstructor = Object; - const fields: EmbedField[] = [...vatsimControllers.sort((a: { facility: number; }, b: { facility: number; }) => b.facility - a.facility), ...vatsimAtis] + const fields: EmbedField[] = [ + ...vatsimControllers.sort((a: { facility: number }, b: { facility: number }) => b.facility - a.facility), + ...vatsimAtis, + ] .map((vatsimController) => { const { callsign, frequency, logon_time, atis_code, text_atis, rating } = vatsimController; const logonTime = new Date(logon_time); const logonTimeString = handleLocaleDateTimeString(logonTime); - const ratingDetail = vatsimControllerRatings.filter((ratingInfo: { id: any; }) => ratingInfo.id === rating); + const ratingDetail = vatsimControllerRatings.filter((ratingInfo: { id: any }) => ratingInfo.id === rating); const { short, long } = ratingDetail[0]; const ratingText = `${short} - ${long}`; const atisText = text_atis ? text_atis.join('\n') : null; return controllersListEmbedFields(callsign, frequency, logonTimeString, ratingText, atisText, atis_code); - }).slice(0, 5).flat(); + }) + .slice(0, 5) + .flat(); const totalCount = keys(vatsimControllers).length + keys(vatsimAtis).length; const shownCount = totalCount < 5 ? totalCount : 5; - return interaction.reply({ embeds: [listEmbed('Controllers & ATIS', fields, totalCount, shownCount, callsignSearch)] }); + return interaction.reply({ + embeds: [listEmbed('Controllers & ATIS', fields, totalCount, shownCount, callsignSearch)], + }); } diff --git a/src/commands/utils/vatsim/functions/vatsimEvents.ts b/src/commands/utils/vatsim/functions/vatsimEvents.ts index 468c8f83..9206c400 100644 --- a/src/commands/utils/vatsim/functions/vatsimEvents.ts +++ b/src/commands/utils/vatsim/functions/vatsimEvents.ts @@ -3,16 +3,18 @@ import { Logger, makeEmbed } from '../../../../lib'; const BASE_VATSIM_URL = 'https://my.vatsim.net'; -const handleLocaleTimeString = (date: Date) => date.toLocaleTimeString('en-US', { - hour: 'numeric', - minute: 'numeric', -}); +const handleLocaleTimeString = (date: Date) => + date.toLocaleTimeString('en-US', { + hour: 'numeric', + minute: 'numeric', + }); -const handleLocaleDateString = (date: Date) => date.toLocaleDateString('en-US', { - weekday: 'short', - month: 'short', - day: 'numeric', -}); +const handleLocaleDateString = (date: Date) => + date.toLocaleDateString('en-US', { + weekday: 'short', + month: 'short', + day: 'numeric', + }); export async function handleVatsimEvents(interaction: ChatInputCommandInteraction<'cached'>) { await interaction.deferReply(); @@ -21,52 +23,55 @@ export async function handleVatsimEvents(interaction: ChatInputCommandInteractio const eventsList = await fetch(`${BASE_VATSIM_URL}/api/v1/events/all`) .then((res) => res.json()) .then((res) => res.data) - .then((res) => res.filter((event: { type: string; }) => event.type === 'Event')) + .then((res) => res.filter((event: { type: string }) => event.type === 'Event')) .then((res) => res.slice(0, 5)); - const fields: EmbedField[] = eventsList.map((event: any) => { - // eslint-disable-next-line camelcase - const { name, organisers, end_time, start_time, link } = event; - const { division } = organisers[0]; - const startDate = new Date(start_time); - const endDate = new Date(end_time); - const startTime = handleLocaleTimeString(startDate); - const endTime = handleLocaleTimeString(endDate); - const startDateString = handleLocaleDateString(startDate); - const endDateString = handleLocaleDateString(endDate); + const fields: EmbedField[] = eventsList + .map((event: any) => { + // eslint-disable-next-line camelcase + const { name, organisers, end_time, start_time, link } = event; + const { division } = organisers[0]; + const startDate = new Date(start_time); + const endDate = new Date(end_time); + const startTime = handleLocaleTimeString(startDate); + const endTime = handleLocaleTimeString(endDate); + const startDateString = handleLocaleDateString(startDate); + const endDateString = handleLocaleDateString(endDate); - return [ - { - name: 'Name', - value: name, - inline: false, - }, - { - name: 'Start Time/Date', - value: `${startTime}/${startDateString}`, - inline: true, - }, - { - name: 'End Time/Date', - value: `${endTime}/${endDateString}`, - inline: true, - }, - { - name: 'Division', - value: `${division}`, - inline: true, - }, - { - name: 'Link', - value: `${link}`, - inline: false, - }, - ]; - }).flat(); + return [ + { + name: 'Name', + value: name, + inline: false, + }, + { + name: 'Start Time/Date', + value: `${startTime}/${startDateString}`, + inline: true, + }, + { + name: 'End Time/Date', + value: `${endTime}/${endDateString}`, + inline: true, + }, + { + name: 'Division', + value: `${division}`, + inline: true, + }, + { + name: 'Link', + value: `${link}`, + inline: false, + }, + ]; + }) + .flat(); const eventsEmbed = makeEmbed({ title: 'VATSIM Events', - description: 'A list of upcoming events on the VATSIM network. Find the full list [here.](https://my.vatsim.net/events)', + description: + 'A list of upcoming events on the VATSIM network. Find the full list [here.](https://my.vatsim.net/events)', fields, }); diff --git a/src/commands/utils/vatsim/functions/vatsimObservers.ts b/src/commands/utils/vatsim/functions/vatsimObservers.ts index 48fd6ed1..900c9067 100644 --- a/src/commands/utils/vatsim/functions/vatsimObservers.ts +++ b/src/commands/utils/vatsim/functions/vatsimObservers.ts @@ -3,11 +3,12 @@ import { makeEmbed } from '../../../../lib'; /* eslint-disable camelcase */ -const listEmbed = (type: string, fields: EmbedField[], totalCount: number, shownCount: number, callsign: string) => makeEmbed({ - title: `VATSIM Data - ${callsign} - ${totalCount} ${type} online`, - description: `A list of ${shownCount} online ${type} matching ${callsign}.`, - fields, -}); +const listEmbed = (type: string, fields: EmbedField[], totalCount: number, shownCount: number, callsign: string) => + makeEmbed({ + title: `VATSIM Data - ${callsign} - ${totalCount} ${type} online`, + description: `A list of ${shownCount} online ${type} matching ${callsign}.`, + fields, + }); const observersListEmbedFields = (callsign: string, logon: string, rating: string, atis: string): EmbedField[] => { const fields = [ @@ -39,33 +40,49 @@ const observersListEmbedFields = (callsign: string, logon: string, rating: strin return fields; }; -const handleLocaleDateTimeString = (date: Date) => date.toLocaleDateString('en-US', { - hour: 'numeric', - minute: 'numeric', - weekday: 'short', - month: 'short', - day: 'numeric', -}); +const handleLocaleDateTimeString = (date: Date) => + date.toLocaleDateString('en-US', { + hour: 'numeric', + minute: 'numeric', + weekday: 'short', + month: 'short', + day: 'numeric', + }); -export async function handleVatsimObservers(interaction: ChatInputCommandInteraction<'cached'>, vatsimData: any, callsignSearch: any) { - const vatsimAllObservers = vatsimData.controllers ? vatsimData.controllers.filter((controller: { facility: number; }) => controller.facility <= 0) : null; +export async function handleVatsimObservers( + interaction: ChatInputCommandInteraction<'cached'>, + vatsimData: any, + callsignSearch: any, +) { + const vatsimAllObservers = vatsimData.controllers + ? vatsimData.controllers.filter((controller: { facility: number }) => controller.facility <= 0) + : null; const vatsimControllerRatings = vatsimData.ratings ? vatsimData.ratings : null; - const vatsimObservers = vatsimAllObservers ? vatsimAllObservers.filter((observer: { callsign: string | any[]; }) => observer.callsign.includes(callsignSearch)) : null; + const vatsimObservers = vatsimAllObservers + ? vatsimAllObservers.filter((observer: { callsign: string | any[] }) => + observer.callsign.includes(callsignSearch), + ) + : null; const { keys }: ObjectConstructor = Object; - const fields: EmbedField[] = [...vatsimObservers.sort((a: { rating: number; }, b: { rating: number; }) => b.rating - a.rating)].map((vatsimObserver) => { - const { callsign, logon_time, text_atis, rating } = vatsimObserver; - const logonTime = new Date(logon_time); - const logonTimeString = handleLocaleDateTimeString(logonTime); - const ratingDetail = vatsimControllerRatings.filter((ratingInfo: { id: any; }) => ratingInfo.id === rating); - const { short, long } = ratingDetail[0]; - const ratingText = `${short} - ${long}`; - const atisText = text_atis ? text_atis.join('\n') : null; + const fields: EmbedField[] = [ + ...vatsimObservers.sort((a: { rating: number }, b: { rating: number }) => b.rating - a.rating), + ] + .map((vatsimObserver) => { + const { callsign, logon_time, text_atis, rating } = vatsimObserver; + const logonTime = new Date(logon_time); + const logonTimeString = handleLocaleDateTimeString(logonTime); + const ratingDetail = vatsimControllerRatings.filter((ratingInfo: { id: any }) => ratingInfo.id === rating); + const { short, long } = ratingDetail[0]; + const ratingText = `${short} - ${long}`; + const atisText = text_atis ? text_atis.join('\n') : null; - return observersListEmbedFields(callsign, logonTimeString, ratingText, atisText); - }).slice(0, 5).flat(); + return observersListEmbedFields(callsign, logonTimeString, ratingText, atisText); + }) + .slice(0, 5) + .flat(); const totalCount = keys(vatsimObservers).length; const shownCount = totalCount < 5 ? totalCount : 5; diff --git a/src/commands/utils/vatsim/functions/vatsimPilots.ts b/src/commands/utils/vatsim/functions/vatsimPilots.ts index e73c6300..bb299da1 100644 --- a/src/commands/utils/vatsim/functions/vatsimPilots.ts +++ b/src/commands/utils/vatsim/functions/vatsimPilots.ts @@ -3,11 +3,12 @@ import { makeEmbed } from '../../../../lib'; /* eslint-disable camelcase */ -const listEmbed = (type: string, fields: EmbedField[], totalCount: number, shownCount: number, callsign: string) => makeEmbed({ - title: `VATSIM Data - ${callsign} - ${totalCount} ${type} online`, - description: `A list of ${shownCount} online ${type} matching ${callsign}.`, - fields, -}); +const listEmbed = (type: string, fields: EmbedField[], totalCount: number, shownCount: number, callsign: string) => + makeEmbed({ + title: `VATSIM Data - ${callsign} - ${totalCount} ${type} online`, + description: `A list of ${shownCount} online ${type} matching ${callsign}.`, + fields, + }); const pilotsListEmbedFields = (callsign: string, rating: string, flightPlan: any) => { const fields = [ { @@ -41,20 +42,35 @@ const pilotsListEmbedFields = (callsign: string, rating: string, flightPlan: any return fields; }; -export async function handleVatsimPilots(interaction: ChatInputCommandInteraction<'cached'>, vatsimData: any, callsignSearch: any) { +export async function handleVatsimPilots( + interaction: ChatInputCommandInteraction<'cached'>, + vatsimData: any, + callsignSearch: any, +) { const vatsimPilotRatings = vatsimData.pilot_ratings ? vatsimData.pilot_ratings : null; - const vatsimPilots = vatsimData.pilots ? vatsimData.pilots.filter((pilot: { callsign: (string | null)[]; }) => pilot.callsign.includes(callsignSearch)) : null; + const vatsimPilots = vatsimData.pilots + ? vatsimData.pilots.filter((pilot: { callsign: (string | null)[] }) => pilot.callsign.includes(callsignSearch)) + : null; const { keys }: ObjectConstructor = Object; - const fields: EmbedField[] = [...vatsimPilots.sort((a: { pilot_rating: number; }, b: { pilot_rating: number; }) => b.pilot_rating - a.pilot_rating)].map((vatsimPilot) => { - const { callsign, pilot_rating, flight_plan } = vatsimPilot; - const ratingDetail = vatsimPilotRatings.filter((ratingInfo: { id: number; }) => ratingInfo.id === pilot_rating); - const { short_name, long_name } = ratingDetail[0]; - const ratingText = `${short_name} - ${long_name}`; + const fields: EmbedField[] = [ + ...vatsimPilots.sort( + (a: { pilot_rating: number }, b: { pilot_rating: number }) => b.pilot_rating - a.pilot_rating, + ), + ] + .map((vatsimPilot) => { + const { callsign, pilot_rating, flight_plan } = vatsimPilot; + const ratingDetail = vatsimPilotRatings.filter( + (ratingInfo: { id: number }) => ratingInfo.id === pilot_rating, + ); + const { short_name, long_name } = ratingDetail[0]; + const ratingText = `${short_name} - ${long_name}`; - return pilotsListEmbedFields(callsign, ratingText, flight_plan); - }).slice(0, 5).flat(); + return pilotsListEmbedFields(callsign, ratingText, flight_plan); + }) + .slice(0, 5) + .flat(); const totalCount = keys(vatsimPilots).length; const shownCount = totalCount < 5 ? totalCount : 5; diff --git a/src/commands/utils/vatsim/functions/vatsimStats.ts b/src/commands/utils/vatsim/functions/vatsimStats.ts index a37c7c82..19b065fe 100644 --- a/src/commands/utils/vatsim/functions/vatsimStats.ts +++ b/src/commands/utils/vatsim/functions/vatsimStats.ts @@ -1,36 +1,47 @@ import { ChatInputCommandInteraction } from 'discord.js'; import { makeEmbed } from '../../../../lib'; -const statsEmbed = (pilots: string, controllers: string, atis: string, observers: string, callsign: any) => makeEmbed({ - title: callsign ? `VATSIM Data | Statistics for callsign ${callsign}` : 'VATSIM Data | Statistics', - description: callsign ? `An overview of the current active Pilots, Controllers, ATIS and Observers matching ${callsign}.` : 'An overview of the current active Pilots, Controllers, ATIS and Observers.', - fields: [ - { - name: 'Pilots', - value: pilots, - inline: true, - }, - { - name: 'Controllers', - value: controllers, - inline: true, - }, - { - name: 'ATIS', - value: atis, - inline: true, - }, - { - name: 'Observers', - value: observers, - inline: true, - }, - ], -}); +const statsEmbed = (pilots: string, controllers: string, atis: string, observers: string, callsign: any) => + makeEmbed({ + title: callsign ? `VATSIM Data | Statistics for callsign ${callsign}` : 'VATSIM Data | Statistics', + description: callsign + ? `An overview of the current active Pilots, Controllers, ATIS and Observers matching ${callsign}.` + : 'An overview of the current active Pilots, Controllers, ATIS and Observers.', + fields: [ + { + name: 'Pilots', + value: pilots, + inline: true, + }, + { + name: 'Controllers', + value: controllers, + inline: true, + }, + { + name: 'ATIS', + value: atis, + inline: true, + }, + { + name: 'Observers', + value: observers, + inline: true, + }, + ], + }); -export async function handleVatsimStats(interaction: ChatInputCommandInteraction<'cached'>, vatsimData: any, callsignSearch: any) { - const vatsimAllControllers = vatsimData.controllers ? vatsimData.controllers.filter((controller: { facility: number; }) => controller.facility > 0) : null; - const vatsimAllObservers = vatsimData.controllers ? vatsimData.controllers.filter((controller: { facility: number; }) => controller.facility <= 0) : null; +export async function handleVatsimStats( + interaction: ChatInputCommandInteraction<'cached'>, + vatsimData: any, + callsignSearch: any, +) { + const vatsimAllControllers = vatsimData.controllers + ? vatsimData.controllers.filter((controller: { facility: number }) => controller.facility > 0) + : null; + const vatsimAllObservers = vatsimData.controllers + ? vatsimData.controllers.filter((controller: { facility: number }) => controller.facility <= 0) + : null; if (!callsignSearch) { const vatsimPilotCount = vatsimData.pilots ? vatsimData.pilots.length : 0; @@ -38,17 +49,35 @@ export async function handleVatsimStats(interaction: ChatInputCommandInteraction const vatsimAtisCount = vatsimData.atis ? vatsimData.atis.length : 0; const vatsimObserverCount = vatsimAllObservers ? vatsimAllObservers.length : 0; - return interaction.reply({ embeds: [statsEmbed(vatsimPilotCount, vatsimControllerCount, vatsimAtisCount, vatsimObserverCount, null)] }); + return interaction.reply({ + embeds: [statsEmbed(vatsimPilotCount, vatsimControllerCount, vatsimAtisCount, vatsimObserverCount, null)], + }); } - const vatsimPilots = vatsimData.pilots ? vatsimData.pilots.filter((pilot: { callsign: string | string[]; }) => pilot.callsign.includes(callsignSearch)) : null; - const vatsimControllers = vatsimAllControllers ? vatsimAllControllers.filter((controller: { callsign: string | string[]; }) => controller.callsign.includes(callsignSearch)) : null; - const vatsimAtis = vatsimData.atis ? vatsimData.atis.filter((atis: { callsign: string | string[]; }) => atis.callsign.includes(callsignSearch)) : null; - const vatsimObservers = vatsimAllObservers ? vatsimAllObservers.filter((observer: { callsign: string | string[]; }) => observer.callsign.includes(callsignSearch)) : null; + const vatsimPilots = vatsimData.pilots + ? vatsimData.pilots.filter((pilot: { callsign: string | string[] }) => pilot.callsign.includes(callsignSearch)) + : null; + const vatsimControllers = vatsimAllControllers + ? vatsimAllControllers.filter((controller: { callsign: string | string[] }) => + controller.callsign.includes(callsignSearch), + ) + : null; + const vatsimAtis = vatsimData.atis + ? vatsimData.atis.filter((atis: { callsign: string | string[] }) => atis.callsign.includes(callsignSearch)) + : null; + const vatsimObservers = vatsimAllObservers + ? vatsimAllObservers.filter((observer: { callsign: string | string[] }) => + observer.callsign.includes(callsignSearch), + ) + : null; const vatsimPilotCount = vatsimPilots ? vatsimPilots.length : 0; const vatsimControllerCount = vatsimControllers ? vatsimControllers.length : 0; const vatsimAtisCount = vatsimAtis ? vatsimAtis.length : 0; const vatsimObserverCount = vatsimObservers ? vatsimObservers.length : 0; - return interaction.reply({ embeds: [statsEmbed(vatsimPilotCount, vatsimControllerCount, vatsimAtisCount, vatsimObserverCount, callsignSearch)] }); + return interaction.reply({ + embeds: [ + statsEmbed(vatsimPilotCount, vatsimControllerCount, vatsimAtisCount, vatsimObserverCount, callsignSearch), + ], + }); } diff --git a/src/commands/utils/vatsim/vatsim.ts b/src/commands/utils/vatsim/vatsim.ts index c1511937..8c34ec55 100644 --- a/src/commands/utils/vatsim/vatsim.ts +++ b/src/commands/utils/vatsim/vatsim.ts @@ -78,11 +78,12 @@ const data = slashCommandStructure({ ], }); -const fetchErrorEmbed = (error: any) => makeEmbed({ - title: 'VATSIM Data - Fetching data failure', - description: `Could not fetch the VATSIM data from the VATSIM API service: ${error}`, - color: Colors.Red, -}); +const fetchErrorEmbed = (error: any) => + makeEmbed({ + title: 'VATSIM Data - Fetching data failure', + description: `Could not fetch the VATSIM data from the VATSIM API service: ${error}`, + color: Colors.Red, + }); export default slashCommand(data, async ({ interaction }) => { // Fetch VATSIM data @@ -113,7 +114,10 @@ export default slashCommand(data, async ({ interaction }) => { if (!regexMatches || !regexMatches.groups || !regexMatches.groups.callsignSearch) { // eslint-disable-next-line consistent-return - return interaction.reply({ content: 'You need to provide a valid callsign or part of a callsign to search for', ephemeral: true }); + return interaction.reply({ + content: 'You need to provide a valid callsign or part of a callsign to search for', + ephemeral: true, + }); } callsignSearch = regexMatches.groups.callsignSearch; @@ -124,23 +128,23 @@ export default slashCommand(data, async ({ interaction }) => { const subcommandName = interaction.options.getSubcommand(); switch (subcommandName) { - case 'stats': - await handleVatsimStats(interaction, vatsimData, callsignSearch); - break; - case 'controllers': - await handleVatsimControllers(interaction, vatsimData, callsignSearch); - break; - case 'pilots': - await handleVatsimPilots(interaction, vatsimData, callsignSearch); - break; - case 'observers': - await handleVatsimObservers(interaction, vatsimData, callsignSearch); - break; - case 'events': - await handleVatsimEvents(interaction); - break; + case 'stats': + await handleVatsimStats(interaction, vatsimData, callsignSearch); + break; + case 'controllers': + await handleVatsimControllers(interaction, vatsimData, callsignSearch); + break; + case 'pilots': + await handleVatsimPilots(interaction, vatsimData, callsignSearch); + break; + case 'observers': + await handleVatsimObservers(interaction, vatsimData, callsignSearch); + break; + case 'events': + await handleVatsimEvents(interaction); + break; - default: - await interaction.reply({ content: 'Unknown subcommand', ephemeral: true }); + default: + await interaction.reply({ content: 'Unknown subcommand', ephemeral: true }); } }); diff --git a/src/commands/utils/wolframAlpha.ts b/src/commands/utils/wolframAlpha.ts index 71ed2744..36b83e6a 100644 --- a/src/commands/utils/wolframAlpha.ts +++ b/src/commands/utils/wolframAlpha.ts @@ -5,12 +5,14 @@ const data = slashCommandStructure({ name: 'wolframalpha', description: 'Queries the Wolfram Alpha API.', type: ApplicationCommandType.ChatInput, - options: [{ - name: 'query', - description: 'Please provide a query. For example: `.wa How much is 1 + 1?`.', - type: ApplicationCommandOptionType.String, - required: true, - }], + options: [ + { + name: 'query', + description: 'Please provide a query. For example: `.wa How much is 1 + 1?`.', + type: ApplicationCommandOptionType.String, + required: true, + }, + ], }); const noQueryEmbed = makeEmbed({ @@ -50,8 +52,7 @@ export default slashCommand(data, async ({ interaction }) => { const searchParams = new URLSearchParams(params); try { - const response = await fetch(`${WOLFRAMALPHA_API_URL}${searchParams.toString()}`) - .then((res) => res.json()); + const response = await fetch(`${WOLFRAMALPHA_API_URL}${searchParams.toString()}`).then((res) => res.json()); if (response.error) { const errorEmbed = makeEmbed({ @@ -93,18 +94,14 @@ export default slashCommand(data, async ({ interaction }) => { } const noResultsEmbed = makeEmbed({ title: 'Wolfram Alpha Error | No Results', - description: makeLines([ - 'No results were found for your query.', - ]), + description: makeLines(['No results were found for your query.']), color: Colors.Red, }); return interaction.followUp({ embeds: [noResultsEmbed], ephemeral: true }); } const obscureQueryEmbed = makeEmbed({ title: 'Wolfram Alpha Error | Could not understand query', - description: makeLines([ - 'Wolfram Alpha could not understand your query.', - ]), + description: makeLines(['Wolfram Alpha could not understand your query.']), color: Colors.Red, }); return interaction.followUp({ embeds: [obscureQueryEmbed], ephemeral: true }); diff --git a/src/commands/utils/zulu.ts b/src/commands/utils/zulu.ts index 74575a05..22557283 100644 --- a/src/commands/utils/zulu.ts +++ b/src/commands/utils/zulu.ts @@ -6,12 +6,14 @@ const data = slashCommandStructure({ name: 'zulu', description: 'Get the current time at a given UTC-offset timezone.', type: ApplicationCommandType.ChatInput, - options: [{ - name: 'offset', - description: 'Please provide a timezone within UTC-12 and UTC+14.', - type: ApplicationCommandOptionType.String, - required: false, - }], + options: [ + { + name: 'offset', + description: 'Please provide a timezone within UTC-12 and UTC+14.', + type: ApplicationCommandOptionType.String, + required: false, + }, + ], }); const dateFormat = 'HH:mm (LT)'; @@ -23,15 +25,10 @@ export default slashCommand(data, async ({ interaction }) => { const numericOffset = parseInt(utcOffset); const sign = utcOffset.startsWith('-') ? '-' : '+'; - if (Number.isNaN(numericOffset) - || numericOffset < -12 - || numericOffset > 14) { + if (Number.isNaN(numericOffset) || numericOffset < -12 || numericOffset > 14) { const invalidEmbed = makeEmbed({ title: 'Zulu Error | Invalid Offset', - description: makeLines([ - 'Please provide a timezone within UTC-12 and UTC+14.', - 'For example: `/zulu -5`.', - ]), + description: makeLines(['Please provide a timezone within UTC-12 and UTC+14.', 'For example: `/zulu -5`.']), color: Colors.Red, }); return interaction.reply({ embeds: [invalidEmbed], ephemeral: true }); @@ -39,5 +36,7 @@ export default slashCommand(data, async ({ interaction }) => { const formattedOffset = `${sign}${Math.abs(numericOffset)}`; - return interaction.reply({ content: `It is ${moment().utc().add(utcOffset, 'hours').format(dateFormat)} in that timezone (UTC${formattedOffset}).` }); + return interaction.reply({ + content: `It is ${moment().utc().add(utcOffset, 'hours').format(dateFormat)} in that timezone (UTC${formattedOffset}).`, + }); }); diff --git a/src/events/buttonHandlers/buttonHandler.ts b/src/events/buttonHandlers/buttonHandler.ts index c2cdac81..65000dc9 100644 --- a/src/events/buttonHandlers/buttonHandler.ts +++ b/src/events/buttonHandlers/buttonHandler.ts @@ -14,18 +14,22 @@ export default event(Events.InteractionCreate, async ({ log }, interaction) => { const [prefix, ...params] = interaction.customId.split('_'); switch (prefix) { - case 'roleAssignment': - const [roleID] = params; - await handleRoleAssignment(interaction, roleID); - log(`Button Handler: Role assignment button pressed by ${user.tag} (${user.id}). roleID: ${roleID}`); - break; - default: - if (buttonLabel) { - log(`Button Handler: Custom ID not matched. Skipping...\nCustom ID: ${customId}, Label: ${buttonLabel}, User: ${user.tag}, User ID: ${user.id}`); - } else { - log(`Button Handler: Custom ID not matched. Skipping...\nCustom ID: ${customId}, Label: null, User: ${user.tag}, User ID: ${user.id}`); - } - return; + case 'roleAssignment': + const [roleID] = params; + await handleRoleAssignment(interaction, roleID); + log(`Button Handler: Role assignment button pressed by ${user.tag} (${user.id}). roleID: ${roleID}`); + break; + default: + if (buttonLabel) { + log( + `Button Handler: Custom ID not matched. Skipping...\nCustom ID: ${customId}, Label: ${buttonLabel}, User: ${user.tag}, User ID: ${user.id}`, + ); + } else { + log( + `Button Handler: Custom ID not matched. Skipping...\nCustom ID: ${customId}, Label: null, User: ${user.tag}, User ID: ${user.id}`, + ); + } + return; } } catch (error) { log('Button Handler: Error handling button press', error); diff --git a/src/events/buttonHandlers/functions/handleRoleAssignment.ts b/src/events/buttonHandlers/functions/handleRoleAssignment.ts index 53233829..7d91d2e7 100644 --- a/src/events/buttonHandlers/functions/handleRoleAssignment.ts +++ b/src/events/buttonHandlers/functions/handleRoleAssignment.ts @@ -14,7 +14,7 @@ export async function handleRoleAssignment(interaction: ButtonInteraction, roleI if (!role) { Logger.error('Role Assignment: Role not found'); - interaction.editReply({ content: 'I couldn\'t find that role' }); + interaction.editReply({ content: "I couldn't find that role" }); return; } @@ -36,6 +36,9 @@ export async function handleRoleAssignment(interaction: ButtonInteraction, roleI } } catch (error) { Logger.error(error); - await interaction.editReply({ content: 'Something went wrong, this role may no longer exist. Please try again. The error message has been logged.' }); + await interaction.editReply({ + content: + 'Something went wrong, this role may no longer exist. Please try again. The error message has been logged.', + }); } } diff --git a/src/events/contextInteractionHandler.ts b/src/events/contextInteractionHandler.ts index d8afd555..47728c45 100644 --- a/src/events/contextInteractionHandler.ts +++ b/src/events/contextInteractionHandler.ts @@ -1,9 +1,7 @@ import { Color, ContextMenuCommand, event, Events, makeEmbed, Reply } from '../lib'; import contextArray from '../commands/context'; -const contextMap = new Map( - contextArray.map((c) => [c.meta.name, c]), -); +const contextMap = new Map(contextArray.map((c) => [c.meta.name, c])); export default event(Events.InteractionCreate, async ({ log, client }, interaction) => { if (!interaction.isContextMenuCommand()) { @@ -11,9 +9,7 @@ export default event(Events.InteractionCreate, async ({ log, client }, interacti } if (!interaction.inCachedGuild()) { - await interaction.reply( - Reply('This bot can only be used in a server!', Color.Error), - ); + await interaction.reply(Reply('This bot can only be used in a server!', Color.Error)); return; } diff --git a/src/events/logging/detectBan.ts b/src/events/logging/detectBan.ts index d9ae940a..29334d6f 100644 --- a/src/events/logging/detectBan.ts +++ b/src/events/logging/detectBan.ts @@ -8,93 +8,96 @@ import { constantsConfig, event, Events, Infraction, Logger, makeEmbed, makeLine const MAX_RETRIES = 5; const SLEEP_TIMER = 0.5 * 1000; -const noLogEmbed = (user: User, guildName: string) => makeEmbed({ - color: Colors.Red, - author: { - name: `[BANNED] ${user.tag}`, - iconURL: user.displayAvatarURL(), - }, - description: makeLines([ - `${user.tag} was banned from ${guildName} but no audit log could be found.`, - '', - bold('NOTE - This was a non bot ban.'), - '', - `Please remember to send the user the reason they were banned and the ban appeal form - ${process.env.BAN_APPEAL_URL}`, - ]), - footer: { text: `User ID: ${user.id}` }, -}); - -const modLogEmbed = (user: User, executor: User, reason: string, formattedDate: string) => makeEmbed({ - color: Colors.Red, - author: { - name: `[BANNED] ${user.tag}`, - iconURL: user.displayAvatarURL(), - }, - description: makeLines([ - bold('NOTE - This was a non bot ban.'), - '', - `Please remember to send the user the reason they were banned and the ban appeal form - ${process.env.BAN_APPEAL_URL}`, - ]), - fields: [ - { - name: 'User', - value: `${user}`, - }, - { - name: 'Moderator', - value: `${executor}`, +const noLogEmbed = (user: User, guildName: string) => + makeEmbed({ + color: Colors.Red, + author: { + name: `[BANNED] ${user.tag}`, + iconURL: user.displayAvatarURL(), }, - { - name: 'Reason', - value: reason || 'No reason provided', + description: makeLines([ + `${user.tag} was banned from ${guildName} but no audit log could be found.`, + '', + bold('NOTE - This was a non bot ban.'), + '', + `Please remember to send the user the reason they were banned and the ban appeal form - ${process.env.BAN_APPEAL_URL}`, + ]), + footer: { text: `User ID: ${user.id}` }, + }); + +const modLogEmbed = (user: User, executor: User, reason: string, formattedDate: string) => + makeEmbed({ + color: Colors.Red, + author: { + name: `[BANNED] ${user.tag}`, + iconURL: user.displayAvatarURL(), }, - { - name: 'Days of messages deleted', - value: 'Unavailable with a non bot ban', + description: makeLines([ + bold('NOTE - This was a non bot ban.'), + '', + `Please remember to send the user the reason they were banned and the ban appeal form - ${process.env.BAN_APPEAL_URL}`, + ]), + fields: [ + { + name: 'User', + value: `${user}`, + }, + { + name: 'Moderator', + value: `${executor}`, + }, + { + name: 'Reason', + value: reason || 'No reason provided', + }, + { + name: 'Days of messages deleted', + value: 'Unavailable with a non bot ban', + }, + { + name: 'Date', + value: formattedDate, + }, + ], + footer: { text: `User ID: ${user.id}` }, + }); + +const userBannedIncompleteEmbed = (user: User, formattedDate: string) => + makeEmbed({ + color: Colors.Red, + author: { + name: `[BANNED] ${user.tag}`, + iconURL: user.displayAvatarURL(), }, - { - name: 'Date', - value: formattedDate, - }, - ], - footer: { text: `User ID: ${user.id}` }, -}); - -const userBannedIncompleteEmbed = (user: User, formattedDate: string) => makeEmbed({ - color: Colors.Red, - author: { - name: `[BANNED] ${user.tag}`, - iconURL: user.displayAvatarURL(), - }, - description: makeLines([ - bold('NOTE - This was a non bot ban.'), - '', - `Please remember to send the user the reason they were banned and the ban appeal form - ${process.env.BAN_APPEAL_URL}`, - ]), - fields: [ - { - name: 'Member', - value: user.tag, - }, - { - name: 'Moderator', - value: 'Unavailable - Audit log incomplete', - }, - { - name: 'Reason', - value: 'Unavailable - Audit log incomplete', - }, - { - name: 'Days of messages deleted', - value: 'Unavailable with a non bot ban', - }, - { - name: 'Date', - value: formattedDate, - }, - ], - footer: { text: `User ID: ${user.id}` }, -}); + description: makeLines([ + bold('NOTE - This was a non bot ban.'), + '', + `Please remember to send the user the reason they were banned and the ban appeal form - ${process.env.BAN_APPEAL_URL}`, + ]), + fields: [ + { + name: 'Member', + value: user.tag, + }, + { + name: 'Moderator', + value: 'Unavailable - Audit log incomplete', + }, + { + name: 'Reason', + value: 'Unavailable - Audit log incomplete', + }, + { + name: 'Days of messages deleted', + value: 'Unavailable with a non bot ban', + }, + { + name: 'Date', + value: formattedDate, + }, + ], + footer: { text: `User ID: ${user.id}` }, + }); const logFailed = makeEmbed({ title: 'Non Bot Ban - Failed to log', @@ -112,16 +115,16 @@ export default event(Events.GuildBanAdd, async (_, msg) => { return; } - const modLogsChannel = await guildBanAdd.guild.channels.resolve(constantsConfig.channels.MOD_LOGS) as TextChannel | null; + const modLogsChannel = (await guildBanAdd.guild.channels.resolve( + constantsConfig.channels.MOD_LOGS, + )) as TextChannel | null; if (!modLogsChannel) { // Exit as can't post return; } const currentDate = new Date(); - const formattedDate: string = moment(currentDate) - .utcOffset(0) - .format(); + const formattedDate: string = moment(currentDate).utcOffset(0).format(); let executor; let reason; @@ -144,8 +147,7 @@ export default event(Events.GuildBanAdd, async (_, msg) => { } retryCount--; - } - while ((!target || target.id !== guildBanAdd.user.id) && retryCount > 0); + } while ((!target || target.id !== guildBanAdd.user.id) && retryCount > 0); if (!target) { await modLogsChannel.send({ embeds: [noLogEmbed(guildBanAdd.user, guildBanAdd.guild.name)] }); @@ -156,7 +158,10 @@ export default event(Events.GuildBanAdd, async (_, msg) => { return; } if (executor && !constantsConfig.modLogExclude.includes(executor.id)) { - await modLogsChannel.send({ content: executor.toString(), embeds: [modLogEmbed(guildBanAdd.user, executor, reason as string, formattedDate)] }); + await modLogsChannel.send({ + content: executor.toString(), + embeds: [modLogEmbed(guildBanAdd.user, executor, reason as string, formattedDate)], + }); //Log to the DB Logger.info('Starting Infraction process'); diff --git a/src/events/logging/messageDelete.ts b/src/events/logging/messageDelete.ts index 74215e10..71b03f4a 100644 --- a/src/events/logging/messageDelete.ts +++ b/src/events/logging/messageDelete.ts @@ -7,12 +7,12 @@ const CONTENT_NOT_AVAIL = 'Unable to find content or embeds.'; export default event(Events.MessageDelete, async (_, msg) => { try { if (msg.guild === null || msg.author === null) { - // DMs + // DMs return; } if (msg.content === null || msg.content.trim() === '') { - // Old Message or empty content + // Old Message or empty content return; } @@ -22,9 +22,7 @@ export default event(Events.MessageDelete, async (_, msg) => { }); const deletionLog = fetchedLogs.entries.first(); const currentDate = new Date(); - const formattedDate: string = moment(currentDate) - .utcOffset(0) - .format('DD, MM, YYYY, HH:mm:ss'); + const formattedDate: string = moment(currentDate).utcOffset(0).format('DD, MM, YYYY, HH:mm:ss'); const userLogsChannel = msg.guild.channels.resolve(constantsConfig.channels.USER_LOGS) as TextChannel | null; const messageEmbeds = msg.embeds.length > 0 ? msg.embeds : []; const messageComponents = []; @@ -93,7 +91,10 @@ export default event(Events.MessageDelete, async (_, msg) => { }, { name: 'Deleted by', - value: (deletionLog && deletionLog.target.id === msg.author.id) ? `${deletionLog.executor}` : 'No audit log was found, message was either deleted by author, or a bot', + value: + deletionLog && deletionLog.target.id === msg.author.id + ? `${deletionLog.executor}` + : 'No audit log was found, message was either deleted by author, or a bot', inline: false, }, { diff --git a/src/events/logging/messageUpdate.ts b/src/events/logging/messageUpdate.ts index 11d509a5..ff8d2d70 100644 --- a/src/events/logging/messageUpdate.ts +++ b/src/events/logging/messageUpdate.ts @@ -1,17 +1,17 @@ import { Colors, TextChannel } from 'discord.js'; import { constantsConfig, event, Events, imageBaseUrl, Logger, makeEmbed } from '../../lib'; -const FEATURE_NOT_AVAIL = '(can\'t show embeds or images)'; +const FEATURE_NOT_AVAIL = "(can't show embeds or images)"; export default event(Events.MessageUpdate, async (_, oldMessage, newMessage) => { try { if (oldMessage.guild === null || oldMessage.author === null || newMessage.author === null) { - // DMs + // DMs return; } if (oldMessage.content === null) { - // Old Message + // Old Message return; } @@ -20,7 +20,9 @@ export default event(Events.MessageUpdate, async (_, oldMessage, newMessage) => return; } - const userLogsChannel = oldMessage.guild.channels.resolve(constantsConfig.channels.USER_LOGS) as TextChannel | null; + const userLogsChannel = oldMessage.guild.channels.resolve( + constantsConfig.channels.USER_LOGS, + ) as TextChannel | null; const MAX_MESSAGE_LENGTH = 1024; @@ -51,8 +53,16 @@ export default event(Events.MessageUpdate, async (_, oldMessage, newMessage) => fields: [ { name: 'Author', value: `${oldMessage.author}`, inline: true }, { name: 'Channel', value: `${oldMessage.channel}`, inline: true }, - { name: originalMessageFieldTitle, value: oldMessageContent ? `\`\`\`${oldMessageContent}\`\`\`` : FEATURE_NOT_AVAIL, inline: false }, - { name: editedMessageFieldTitle, value: newMessageContent ? `\`\`\`${newMessageContent}\`\`\`` : FEATURE_NOT_AVAIL, inline: false }, + { + name: originalMessageFieldTitle, + value: oldMessageContent ? `\`\`\`${oldMessageContent}\`\`\`` : FEATURE_NOT_AVAIL, + inline: false, + }, + { + name: editedMessageFieldTitle, + value: newMessageContent ? `\`\`\`${newMessageContent}\`\`\`` : FEATURE_NOT_AVAIL, + inline: false, + }, ], footer: { text: `User ID: ${oldMessage.author.id}` }, }); diff --git a/src/events/logging/scamLogs.ts b/src/events/logging/scamLogs.ts index 1b2cb265..86199bbf 100644 --- a/src/events/logging/scamLogs.ts +++ b/src/events/logging/scamLogs.ts @@ -1,6 +1,16 @@ import { codeBlock, Colors, DMChannel, TextChannel } from 'discord.js'; import mongoose from 'mongoose'; -import { constantsConfig, makeEmbed, makeLines, event, Events, getConn, Infraction, Logger, imageBaseUrl } from '../../lib'; +import { + constantsConfig, + makeEmbed, + makeLines, + event, + Events, + getConn, + Infraction, + Logger, + imageBaseUrl, +} from '../../lib'; const excludedRoles = [ constantsConfig.roles.ADMIN_TEAM, @@ -143,7 +153,9 @@ export default event(Events.MessageCreate, async ({ log }, msg) => { } // Try and send a DM try { - await msg.author.send('We have detected use of @everyone in one of our text channels. This function is in place to prevent discord scams and has resulted in an automatic timeout and notification of our moderation team. If this was done in error, our moderation team will reverse the timeout, however please refrain from using the @everyone ping in future.'); + await msg.author.send( + 'We have detected use of @everyone in one of our text channels. This function is in place to prevent discord scams and has resulted in an automatic timeout and notification of our moderation team. If this was done in error, our moderation team will reverse the timeout, however please refrain from using the @everyone ping in future.', + ); } catch (e) { log(e); diff --git a/src/events/ready.ts b/src/events/ready.ts index d907af85..7b7a54fa 100644 --- a/src/events/ready.ts +++ b/src/events/ready.ts @@ -1,15 +1,6 @@ import { ActivityType, TextChannel } from 'discord.js'; import moment from 'moment'; -import { - constantsConfig, - event, - Events, - connect, - setupScheduler, - Logger, - imageBaseUrl, - getScheduler, -} from '../lib'; +import { constantsConfig, event, Events, connect, setupScheduler, Logger, imageBaseUrl, getScheduler } from '../lib'; import { deployCommands } from '../scripts/deployCommands'; import commandArray from '../commands'; import contextArray from '../commands/context'; @@ -35,16 +26,16 @@ export default event(Events.ClientReady, async ({ log }, client) => { if (process.env.DEPLOY === 'true') { log('DEPLOY variable set to true, deploying commands and contexts.'); try { - await deployCommands(commandArray, contextArray) - .then(async (user) => { - const bot = `<@${user.id}>`; + await deployCommands(commandArray, contextArray).then(async (user) => { + const bot = `<@${user.id}>`; - const response = process.env.NODE_ENV === 'production' + const response = + process.env.NODE_ENV === 'production' ? `Deployed ${commandArray.length} commands and ${contextArray.length} contexts globally as ${bot}!` : `Deployed ${commandArray.length} commands and ${contextArray.length} contexts to \`<@${constantsConfig.guildId}>\` as ${bot}!`; - log(response); - }); + log(response); + }); } catch (error) { log('Failed to deploy commands:', error); } @@ -81,14 +72,18 @@ export default event(Events.ClientReady, async ({ log }, client) => { if (scheduler) { const heartbeatJobList = await scheduler.jobs({ name: 'sendHeartbeat' }); if (heartbeatJobList.length === 0) { - scheduler.every(`${process.env.HEARTBEAT_INTERVAL} seconds`, 'sendHeartbeat', { interval: process.env.HEARTBEAT_INTERVAL }); + scheduler.every(`${process.env.HEARTBEAT_INTERVAL} seconds`, 'sendHeartbeat', { + interval: process.env.HEARTBEAT_INTERVAL, + }); Logger.info(`Heartbeat job scheduled with interval ${process.env.HEARTBEAT_INTERVAL}`); } else { const heartbeatJob = heartbeatJobList[0]; const { interval } = heartbeatJob.attrs.data as { interval: string }; if (interval !== process.env.HEARTBEAT_INTERVAL) { await scheduler.cancel({ name: 'sendHeartbeat' }); - scheduler.every(`${process.env.HEARTBEAT_INTERVAL} seconds`, 'sendHeartbeat', { interval: process.env.HEARTBEAT_INTERVAL }); + scheduler.every(`${process.env.HEARTBEAT_INTERVAL} seconds`, 'sendHeartbeat', { + interval: process.env.HEARTBEAT_INTERVAL, + }); Logger.info(`Heartbeat job rescheduled with new interval ${process.env.HEARTBEAT_INTERVAL}`); } else { Logger.info('Heartbeat job already scheduled'); @@ -103,14 +98,18 @@ export default event(Events.ClientReady, async ({ log }, client) => { if (scheduler) { const birthdayJobList = await scheduler.jobs({ name: 'postBirthdays' }); if (birthdayJobList.length === 0) { - scheduler.every(`${process.env.BIRTHDAY_INTERVAL} seconds`, 'postBirthdays', { interval: process.env.BIRTHDAY_INTERVAL }); + scheduler.every(`${process.env.BIRTHDAY_INTERVAL} seconds`, 'postBirthdays', { + interval: process.env.BIRTHDAY_INTERVAL, + }); Logger.info(`Birthday job scheduled with interval ${process.env.BIRTHDAY_INTERVAL}`); } else { const birthdayJob = birthdayJobList[0]; const { interval } = birthdayJob.attrs.data as { interval: string }; if (interval !== process.env.BIRTHDAY_INTERVAL) { await scheduler.cancel({ name: 'postBirthdays' }); - scheduler.every(`${process.env.BIRTHDAY_INTERVAL} seconds`, 'postBirthdays', { interval: process.env.BIRTHDAY_INTERVAL }); + scheduler.every(`${process.env.BIRTHDAY_INTERVAL} seconds`, 'postBirthdays', { + interval: process.env.BIRTHDAY_INTERVAL, + }); Logger.info(`Birthday job rescheduled with new interval ${process.env.BIRTHDAY_INTERVAL}`); } else { Logger.info('Birthday job already scheduled'); @@ -123,9 +122,7 @@ export default event(Events.ClientReady, async ({ log }, client) => { const botDevChannel = client.channels.resolve(constantsConfig.channels.MOD_LOGS) as TextChannel; if (botDevChannel) { const currentDate = new Date(); - const formattedDate = moment(currentDate) - .utcOffset(0) - .format(); + const formattedDate = moment(currentDate).utcOffset(0).format(); // Include the database connection and scheduler status in the mod logs message. let logMessage = `<@&${constantsConfig.roles.BOT_DEVELOPER}>\n[${formattedDate}] - ${client.user?.username} has connected! - DB State: ${dbConnected ? 'Connected' : 'Disconnected'}`; diff --git a/src/events/slashCommandHandler.ts b/src/events/slashCommandHandler.ts index 0d6edaf0..84f2b2a1 100644 --- a/src/events/slashCommandHandler.ts +++ b/src/events/slashCommandHandler.ts @@ -15,14 +15,12 @@ export default event(Events.InteractionCreate, async ({ log, client }, interacti } if (!interaction.inCachedGuild()) { - await interaction.reply( - Reply('This bot can only be used in a server!', Color.Error), - ); + await interaction.reply(Reply('This bot can only be used in a server!', Color.Error)); return; } try { - const { commandName, options } = interaction as{ + const { commandName, options } = interaction as { commandName: any; options: any; }; diff --git a/src/lib/config.ts b/src/lib/config.ts index 7a9e9760..8fb45900 100644 --- a/src/lib/config.ts +++ b/src/lib/config.ts @@ -8,8 +8,8 @@ const imageBaseUrl = originalBaseUrl.endsWith('/') ? originalBaseUrl.slice(0, -1 export { imageBaseUrl }; interface roleAssignmentId { - group: string, - roles: { id: string, label: string}[] + group: string; + roles: { id: string; label: string }[]; } // Config constants that are directly used in code should be mandatory, @@ -19,62 +19,62 @@ interface roleAssignmentId { // not mandatory, as they can be dynamic. interface Config { aircraftTypeList: { - [x: string]: string, - }, + [x: string]: string; + }; channels: { - A32NX_SUPPORT: string, - FAQ: string, - FLIGHT_SCHOOL: string, - KNOWN_ISSUES: string, - MOD_ALERTS: string, - MOD_LOGS: string, - ROLES: string, - SCAM_REPORT_LOGS: string, - TEAM: string, - USER_LOGS: string, - VIDEOS: string, - [x: string]: string, - }, + A32NX_SUPPORT: string; + FAQ: string; + FLIGHT_SCHOOL: string; + KNOWN_ISSUES: string; + MOD_ALERTS: string; + MOD_LOGS: string; + ROLES: string; + SCAM_REPORT_LOGS: string; + TEAM: string; + USER_LOGS: string; + VIDEOS: string; + [x: string]: string; + }; colors: { - FBW_CYAN: string, - [x: string]: string, - }, + FBW_CYAN: string; + [x: string]: string; + }; commandPermission: { - MANAGE_SERVER: string, - [x: string]: string, - }, - guildId: string, - modLogExclude: string[], - roleAssignmentIds: roleAssignmentId[], + MANAGE_SERVER: string; + [x: string]: string; + }; + guildId: string; + modLogExclude: string[]; + roleAssignmentIds: roleAssignmentId[]; roleGroups: { - [x: string]: string[], - }, + [x: string]: string[]; + }; roles: { - ADMIN_TEAM: string, - BOT_DEVELOPER: string, - COMMUNITY_SUPPORT: string, - DEVELOPMENT_TEAM: string, - FBW_EMERITUS: string, - MEDIA_TEAM: string, - MODERATION_TEAM: string, - [x: string]: string, - }, + ADMIN_TEAM: string; + BOT_DEVELOPER: string; + COMMUNITY_SUPPORT: string; + DEVELOPMENT_TEAM: string; + FBW_EMERITUS: string; + MEDIA_TEAM: string; + MODERATION_TEAM: string; + [x: string]: string; + }; threads: { - BIRTHDAY_THREAD: string, - COUNT_THREAD: string, - [x: string]: string, - }, + BIRTHDAY_THREAD: string; + COUNT_THREAD: string; + [x: string]: string; + }; units: { - CELSIUS: string, - DEGREES: string, - [x: string]: string, - }, - userLogExclude: string[], + CELSIUS: string; + DEGREES: string; + [x: string]: string; + }; + userLogExclude: string[]; } let parsedConfig: Config; try { - parsedConfig = (botConfig as unknown as Config); + parsedConfig = botConfig as unknown as Config; if (!parsedConfig.commandPermission.MANAGE_SERVER) { // Making sure this is always set, even if an empty string is given parsedConfig.commandPermission.MANAGE_SERVER = '32'; diff --git a/src/lib/contextMenuCommand.ts b/src/lib/contextMenuCommand.ts index 33051c80..6b1856bb 100644 --- a/src/lib/contextMenuCommand.ts +++ b/src/lib/contextMenuCommand.ts @@ -2,7 +2,8 @@ import { Awaitable, Client, ContextMenuCommandBuilder, - RESTPostAPIApplicationCommandsJSONBody, ContextMenuCommandInteraction, + RESTPostAPIApplicationCommandsJSONBody, + ContextMenuCommandInteraction, } from 'discord.js'; import { LogMethods } from './index'; @@ -14,9 +15,7 @@ export interface ContextMenuCommandProps { export type ContextMenuCommandCallback = (props: ContextMenuCommandProps) => Awaitable; -export type ContextMenuCommandStructure = - | ContextMenuCommandBuilder - | RESTPostAPIApplicationCommandsJSONBody +export type ContextMenuCommandStructure = ContextMenuCommandBuilder | RESTPostAPIApplicationCommandsJSONBody; export interface ContextMenuCommand { meta: ContextMenuCommandStructure; @@ -27,6 +26,9 @@ export function contextMenuCommandStructure(data: RESTPostAPIApplicationCommands return data; } -export function contextMenuCommand(meta: ContextMenuCommandStructure, callback: ContextMenuCommandCallback): ContextMenuCommand { +export function contextMenuCommand( + meta: ContextMenuCommandStructure, + callback: ContextMenuCommandCallback, +): ContextMenuCommand { return { meta, callback }; } diff --git a/src/lib/durationInEnglish.ts b/src/lib/durationInEnglish.ts index 1b15515a..fcade0af 100644 --- a/src/lib/durationInEnglish.ts +++ b/src/lib/durationInEnglish.ts @@ -3,10 +3,12 @@ export function durationInEnglish(milliseconds: any) { if (seconds < 60) { return `${Math.floor(seconds)} second${Math.floor(seconds) === 1 ? '' : 's'}`; - } if (seconds < 3600) { + } + if (seconds < 3600) { const minutes = seconds / 60; return `${Math.floor(minutes)} minute${Math.floor(minutes) === 1 ? '' : 's'}`; - } if (seconds < 86400) { + } + if (seconds < 86400) { const hours = seconds / 3600; return `${Math.floor(hours)} hour${Math.floor(hours) === 1 ? '' : 's'}`; } diff --git a/src/lib/embed.ts b/src/lib/embed.ts index 5d3f3155..e1d17a9d 100644 --- a/src/lib/embed.ts +++ b/src/lib/embed.ts @@ -16,11 +16,11 @@ export function makeLines(lines: string[]): string { export const makeList = (lines: string[], type?: ListTypes): string => { switch (type) { - case 'bullet': - return lines.map((line) => `• ${line}`).join('\n'); - case 'ordered': - return lines.map((line, index) => `${index + 1}. ${line}`).join('\n'); - default: - return lines.map((line) => `- ${line}`).join('\n'); + case 'bullet': + return lines.map((line) => `• ${line}`).join('\n'); + case 'ordered': + return lines.map((line, index) => `${index + 1}. ${line}`).join('\n'); + default: + return lines.map((line) => `- ${line}`).join('\n'); } }; diff --git a/src/lib/events.ts b/src/lib/events.ts index cc3e23a4..2cb44ce4 100644 --- a/src/lib/events.ts +++ b/src/lib/events.ts @@ -11,10 +11,7 @@ export interface EventProps { log: LogMethods; } -export type EventCallback = ( - props: EventProps, - ...args: ClientEvents[T] -) => Awaitable; +export type EventCallback = (props: EventProps, ...args: ClientEvents[T]) => Awaitable; export interface Event { key: T; diff --git a/src/lib/genericEmbedPagination.ts b/src/lib/genericEmbedPagination.ts index e1024331..e3422c6d 100644 --- a/src/lib/genericEmbedPagination.ts +++ b/src/lib/genericEmbedPagination.ts @@ -1,6 +1,20 @@ -import { ActionRowBuilder, ButtonBuilder, ButtonInteraction, ButtonStyle, CommandInteraction, ComponentType, EmbedBuilder, Interaction, InteractionResponse, Message } from 'discord.js'; +import { + ActionRowBuilder, + ButtonBuilder, + ButtonInteraction, + ButtonStyle, + CommandInteraction, + ComponentType, + EmbedBuilder, + Interaction, + InteractionResponse, + Message, +} from 'discord.js'; -export async function createPaginatedEmbedHandler(initialInteraction: CommandInteraction, embeds: EmbedBuilder[]): Promise { +export async function createPaginatedEmbedHandler( + initialInteraction: CommandInteraction, + embeds: EmbedBuilder[], +): Promise { let currentPage = 0; const nextButton = new ButtonBuilder() @@ -25,7 +39,11 @@ export async function createPaginatedEmbedHandler(initialInteraction: CommandInt } const filter = (buttonInteraction: Interaction) => initialInteraction.user.id === buttonInteraction.user.id; - const collector = message.createMessageComponentCollector({ filter, componentType: ComponentType.Button, time: 120_000 }); + const collector = message.createMessageComponentCollector({ + filter, + componentType: ComponentType.Button, + time: 120_000, + }); collector.on('collect', async (collectedInteraction: ButtonInteraction) => { await collectedInteraction.deferUpdate(); @@ -51,7 +69,14 @@ export async function createPaginatedEmbedHandler(initialInteraction: CommandInt function handleEmbedExpire() { const embed = embeds[currentPage]; - initialInteraction.editReply({ embeds: [embed.setFooter({ text: `${embed.data.footer ? `${embed.data.footer.text} - ` : ''}This embed has expired.` })], components: [] }); + initialInteraction.editReply({ + embeds: [ + embed.setFooter({ + text: `${embed.data.footer ? `${embed.data.footer.text} - ` : ''}This embed has expired.`, + }), + ], + components: [], + }); } function setButtonDisabledStates() { diff --git a/src/lib/infractionEmbedPagination.ts b/src/lib/infractionEmbedPagination.ts index a5150526..3c268884 100644 --- a/src/lib/infractionEmbedPagination.ts +++ b/src/lib/infractionEmbedPagination.ts @@ -1,6 +1,26 @@ -import { ActionRowBuilder, ButtonBuilder, ButtonStyle, Interaction, CommandInteraction, ButtonInteraction, EmbedBuilder } from 'discord.js'; - -export async function createPaginatedInfractionEmbedHandler(initialInteraction: CommandInteraction, user:string, embeds: EmbedBuilder[], infractionsLengths: { warnsLength: string; timeoutsLength: string; scamLogsLength: string; bansLength: string; unbansLength: string; notesLength: string; }): Promise { +import { + ActionRowBuilder, + ButtonBuilder, + ButtonStyle, + Interaction, + CommandInteraction, + ButtonInteraction, + EmbedBuilder, +} from 'discord.js'; + +export async function createPaginatedInfractionEmbedHandler( + initialInteraction: CommandInteraction, + user: string, + embeds: EmbedBuilder[], + infractionsLengths: { + warnsLength: string; + timeoutsLength: string; + scamLogsLength: string; + bansLength: string; + unbansLength: string; + notesLength: string; + }, +): Promise { let currentPage = 0; const aboutButton = new ButtonBuilder() @@ -39,8 +59,16 @@ export async function createPaginatedInfractionEmbedHandler(initialInteraction: .setStyle(ButtonStyle.Primary); const buttonRow1 = new ActionRowBuilder().addComponents(aboutButton, warnButton, timeoutButton); - const buttonRow2 = new ActionRowBuilder().addComponents(scamLogButton, banButton, unbanButton, noteButton); - const message = await initialInteraction.followUp({ embeds: [embeds[currentPage]], components: [buttonRow1, buttonRow2] }); + const buttonRow2 = new ActionRowBuilder().addComponents( + scamLogButton, + banButton, + unbanButton, + noteButton, + ); + const message = await initialInteraction.followUp({ + embeds: [embeds[currentPage]], + components: [buttonRow1, buttonRow2], + }); const filter = (interaction: Interaction) => interaction.user.id === user; const collector = message.createMessageComponentCollector({ filter, time: 120_000 }); @@ -85,6 +113,13 @@ export async function createPaginatedInfractionEmbedHandler(initialInteraction: function handleEmbedExpire() { const embed = embeds[currentPage]; - initialInteraction.editReply({ embeds: [embed.setFooter({ text: `${embed.data.footer ? `${embed.data.footer.text} - ` : ''}This embed has expired.` })], components: [] }); + initialInteraction.editReply({ + embeds: [ + embed.setFooter({ + text: `${embed.data.footer ? `${embed.data.footer.text} - ` : ''}This embed has expired.`, + }), + ], + components: [], + }); } } diff --git a/src/lib/logger.ts b/src/lib/logger.ts index d2f2e6f4..c8237154 100644 --- a/src/lib/logger.ts +++ b/src/lib/logger.ts @@ -19,7 +19,5 @@ const format = () => { export const Logger = winston.createLogger({ level: level(), format: format(), - transports: [ - new winston.transports.Console(), - ], + transports: [new winston.transports.Console()], }); diff --git a/src/lib/replies.ts b/src/lib/replies.ts index 472fcf34..e25d588f 100644 --- a/src/lib/replies.ts +++ b/src/lib/replies.ts @@ -11,15 +11,17 @@ export enum Color { export const EditReply = (msg: string, color: Color = Color.Info): InteractionEditReplyOptions => ({ content: undefined, - embeds: [{ - description: msg, - color, - }], + embeds: [ + { + description: msg, + color, + }, + ], components: [], files: [], }); export const Reply = (msg: string, color: Color = Color.Info): InteractionReplyOptions => ({ ephemeral: true, - ...EditReply(msg, color) as InteractionReplyOptions, + ...(EditReply(msg, color) as InteractionReplyOptions), }); diff --git a/src/lib/schedulerJobs/autoDisableSlowMode.ts b/src/lib/schedulerJobs/autoDisableSlowMode.ts index 1684d5e2..272b83a9 100644 --- a/src/lib/schedulerJobs/autoDisableSlowMode.ts +++ b/src/lib/schedulerJobs/autoDisableSlowMode.ts @@ -3,17 +3,19 @@ import { ChannelType, TextChannel, Colors } from 'discord.js'; import { client } from '../../client'; import { constantsConfig, makeEmbed, Logger, getScheduler } from '../index'; -const failedEmbed = (action: string, channel: string) => makeEmbed({ - title: `Slow Message - ${action} failed`, - description: `Failed to ${action} the slow mode for channel <#${channel}>.`, - color: Colors.Red, -}); +const failedEmbed = (action: string, channel: string) => + makeEmbed({ + title: `Slow Message - ${action} failed`, + description: `Failed to ${action} the slow mode for channel <#${channel}>.`, + color: Colors.Red, + }); -const modLogEmbed = (action: string, fields: any, color: number) => makeEmbed({ - title: `Slow Mode - ${action}`, - fields, - color, -}); +const modLogEmbed = (action: string, fields: any, color: number) => + makeEmbed({ + title: `Slow Mode - ${action}`, + fields, + color, + }); export async function autoDisableSlowMode(job: Job) { const scheduler = getScheduler(); @@ -31,7 +33,12 @@ export async function autoDisableSlowMode(job: Job) { const { channelId } = job.attrs.data as { channelId: string }; const modLogsChannel = client.channels.resolve(constantsConfig.channels.MOD_LOGS) as TextChannel | null; const slowmodeChannel = client.channels.resolve(channelId); - if (!slowmodeChannel || [ChannelType.GuildText, ChannelType.GuildForum, ChannelType.PublicThread, ChannelType.PrivateThread].indexOf(slowmodeChannel.type) === -1) { + if ( + !slowmodeChannel || + [ChannelType.GuildText, ChannelType.GuildForum, ChannelType.PublicThread, ChannelType.PrivateThread].indexOf( + slowmodeChannel.type, + ) === -1 + ) { Logger.error('Slow mode - Auto disable - Unable to disable for non-existing channel'); if (modLogsChannel) { await modLogsChannel.send({ embeds: [failedEmbed('Auto disable', channelId)] }); @@ -39,7 +46,12 @@ export async function autoDisableSlowMode(job: Job) { return; } try { - if (slowmodeChannel.type === ChannelType.GuildForum || slowmodeChannel.type === ChannelType.GuildText || slowmodeChannel.type === ChannelType.PrivateThread || slowmodeChannel.type === ChannelType.PublicThread) { + if ( + slowmodeChannel.type === ChannelType.GuildForum || + slowmodeChannel.type === ChannelType.GuildText || + slowmodeChannel.type === ChannelType.PrivateThread || + slowmodeChannel.type === ChannelType.PublicThread + ) { await slowmodeChannel.setRateLimitPerUser(0, 'Slow mode disabled through bot'); } await job.remove(); @@ -51,29 +63,34 @@ export async function autoDisableSlowMode(job: Job) { try { // @ts-ignore await modLogsChannel.send({ - embeds: [modLogEmbed('Auto Disable', [ - { - inline: true, - name: 'Channel', - value: `<#${channelId}>`, - }, - { - inline: true, - name: 'Slow mode limit', - value: 'Disabled', - }, - { - inline: true, - name: 'Auto disable timeout', - value: 'None', - }, - { - inline: true, - name: 'Moderator', - value: 'FBW Bot', - }, + embeds: [ + modLogEmbed( + 'Auto Disable', + [ + { + inline: true, + name: 'Channel', + value: `<#${channelId}>`, + }, + { + inline: true, + name: 'Slow mode limit', + value: 'Disabled', + }, + { + inline: true, + name: 'Auto disable timeout', + value: 'None', + }, + { + inline: true, + name: 'Moderator', + value: 'FBW Bot', + }, + ], + Colors.Green, + ), ], - Colors.Green)], }); } catch (err) { Logger.warn(`Failed to send Mod Log for auto disable of slow mode for channel <#${channelId}>: ${err}`); diff --git a/src/lib/schedulerJobs/postBirthdays.ts b/src/lib/schedulerJobs/postBirthdays.ts index 6b11f669..bde84ffb 100644 --- a/src/lib/schedulerJobs/postBirthdays.ts +++ b/src/lib/schedulerJobs/postBirthdays.ts @@ -47,7 +47,9 @@ export async function postBirthdays(job: Job) { // Get all threads (archived included) await channel.threads.fetch({ archived: {} }); - const thread = channel.threads.cache.find((t) => t.id === constantsConfig.threads.BIRTHDAY_THREAD) as ThreadChannel | null; + const thread = channel.threads.cache.find( + (t) => t.id === constantsConfig.threads.BIRTHDAY_THREAD, + ) as ThreadChannel | null; if (!thread) { Logger.error('Birthday handler - Thread not found'); return; @@ -106,7 +108,9 @@ export async function postBirthdays(job: Job) { }); // Update birthday to next year - const nextBirthdayDatetime = new Date(Date.UTC(currentDate.getUTCFullYear() + 1, birthday.month! - 1, birthday.day!)); + const nextBirthdayDatetime = new Date( + Date.UTC(currentDate.getUTCFullYear() + 1, birthday.month! - 1, birthday.day!), + ); nextBirthdayDatetime.setUTCHours(10 - birthday.timezone!); birthday.utcDatetime = nextBirthdayDatetime; try { diff --git a/src/lib/slashCommand.ts b/src/lib/slashCommand.ts index 9184c8f3..94f3e359 100644 --- a/src/lib/slashCommand.ts +++ b/src/lib/slashCommand.ts @@ -1,34 +1,47 @@ -import type { Awaitable, Client, ChatInputCommandInteraction, SlashCommandBuilder, SlashCommandSubcommandsOnlyBuilder, RESTPostAPIApplicationCommandsJSONBody } from 'discord.js'; +import type { + Awaitable, + Client, + ChatInputCommandInteraction, + SlashCommandBuilder, + SlashCommandSubcommandsOnlyBuilder, + RESTPostAPIApplicationCommandsJSONBody, +} from 'discord.js'; import { LogMethods, AutocompleteCallback } from './index'; /// Props that will be passed through the command callback. export interface SlashCommandProps { - interaction: ChatInputCommandInteraction<'cached'>, - client: Client, - log: LogMethods, + interaction: ChatInputCommandInteraction<'cached'>; + client: Client; + log: LogMethods; } export type SlashCommandCallback = (props: SlashCommandProps) => Awaitable; /// Command structure for slash commands export type SlashCommandStructure = - | SlashCommandBuilder & { category?: string } - | SlashCommandSubcommandsOnlyBuilder & { category?: string } - | Omit & { category?: string } - | RESTPostAPIApplicationCommandsJSONBody & { category?: string }; + | (SlashCommandBuilder & { category?: string }) + | (SlashCommandSubcommandsOnlyBuilder & { category?: string }) + | (Omit & { category?: string }) + | (RESTPostAPIApplicationCommandsJSONBody & { category?: string }); /// Internal structure that represents a command and its callback. export interface SlashCommand { - meta: SlashCommandStructure, - callback: SlashCommandCallback, - autocompleteCallback?: AutocompleteCallback, + meta: SlashCommandStructure; + callback: SlashCommandCallback; + autocompleteCallback?: AutocompleteCallback; } /// Function to provide data for slash commands -export function slashCommandStructure(data: RESTPostAPIApplicationCommandsJSONBody & { category?: string }): SlashCommandStructure { +export function slashCommandStructure( + data: RESTPostAPIApplicationCommandsJSONBody & { category?: string }, +): SlashCommandStructure { return data; } /// Creates command structure -export function slashCommand(meta: SlashCommandStructure, callback: SlashCommandCallback, autocompleteCallback?: AutocompleteCallback): SlashCommand { +export function slashCommand( + meta: SlashCommandStructure, + callback: SlashCommandCallback, + autocompleteCallback?: AutocompleteCallback, +): SlashCommand { return { meta, callback, autocompleteCallback }; } diff --git a/src/scripts/deployCommands.ts b/src/scripts/deployCommands.ts index d350c027..2de43807 100644 --- a/src/scripts/deployCommands.ts +++ b/src/scripts/deployCommands.ts @@ -12,15 +12,13 @@ if (!process.env.BOT_SECRET) { const rest = new REST({ version: '10' }).setToken(process.env.BOT_SECRET); export async function deployCommands(commandArray: any[], contextArray: any[]) { - const body = [ - ...commandArray.map((cmd) => cmd.meta), - ...contextArray.map((ctx) => ctx.meta), - ]; - const currentUser = await rest.get(Routes.user()) as APIUser; + const body = [...commandArray.map((cmd) => cmd.meta), ...contextArray.map((ctx) => ctx.meta)]; + const currentUser = (await rest.get(Routes.user())) as APIUser; - const endpoint = process.env.NODE_ENV === 'production' - ? Routes.applicationCommands(currentUser.id) - : Routes.applicationGuildCommands(currentUser.id, constantsConfig.guildId); + const endpoint = + process.env.NODE_ENV === 'production' + ? Routes.applicationCommands(currentUser.id) + : Routes.applicationGuildCommands(currentUser.id, constantsConfig.guildId); await rest.put(endpoint, { body }); From 3691161dda5d5e7b9a912c51876eadbffcd4f1fb Mon Sep 17 00:00:00 2001 From: ExampleWasTaken <58574351+ExampleWasTaken@users.noreply.github.com> Date: Mon, 17 Jun 2024 20:42:38 +0200 Subject: [PATCH 07/82] add temporary test npm script --- package.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/package.json b/package.json index da54ab9b..eeab280d 100644 --- a/package.json +++ b/package.json @@ -10,7 +10,8 @@ "build": "tsc", "build:digitalocean": "npm ci --include=dev && npm run build", "lint": "eslint", - "lint-fix": "eslint --fix" + "lint-fix": "eslint --fix", + "test": "npm run build && npm run lint" // TODO: Remove before merge }, "author": "FlyByWire Simulations", "license": "AGPL-3.0", From 8f16c61e1a204bf54c8c1a246a852dd560b22f21 Mon Sep 17 00:00:00 2001 From: ExampleWasTaken <58574351+ExampleWasTaken@users.noreply.github.com> Date: Mon, 17 Jun 2024 22:09:00 +0200 Subject: [PATCH 08/82] add prettier scripts --- package.json | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/package.json b/package.json index eeab280d..2003679e 100644 --- a/package.json +++ b/package.json @@ -11,7 +11,10 @@ "build:digitalocean": "npm ci --include=dev && npm run build", "lint": "eslint", "lint-fix": "eslint --fix", - "test": "npm run build && npm run lint" // TODO: Remove before merge + "prettier": "prettier \"**/*.ts\" \"**/*.js\" \"**/*.json\" \"**/*.yaml\" \"**/*.yml\" \"**/*.md\"", + "prettier:check": "npm run prettier -- --check", + "prettier:write": "npm run prettier -- --write", + "test": "tsc --noEmit && eslint & npm run prettier:check" }, "author": "FlyByWire Simulations", "license": "AGPL-3.0", From ad9155ad42751c2f37ddd0f33468fffc2f34890e Mon Sep 17 00:00:00 2001 From: ExampleWasTaken <58574351+ExampleWasTaken@users.noreply.github.com> Date: Mon, 17 Jun 2024 22:09:41 +0200 Subject: [PATCH 09/82] fix editorconfig and prettierrc --- .editorconfig | 14 ++++++++++++-- .prettierrc | 12 +----------- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/.editorconfig b/.editorconfig index ec34d4a5..eba61550 100644 --- a/.editorconfig +++ b/.editorconfig @@ -1,8 +1,18 @@ +root = true + [*] charset = utf-8 indent_size = 4 indent_style = space insert_final_newline = true -max_line_length = 120 tab_width = 4 -trim_trailing_whitespace = true + +[*.{js,jsx,ts,tsx}] +indent_size = 2 +insert_final_newline = true +tab_width = 2 + +# YAML is usually 2 spaces +[*.{yml,yaml}] +indent_size = 2 +tab_width = 2 diff --git a/.prettierrc b/.prettierrc index 0e2a0078..b005b62a 100644 --- a/.prettierrc +++ b/.prettierrc @@ -1,15 +1,5 @@ { "singleQuote": true, "printWidth": 120, - "parser": "typescript", - "endOfLine": "auto", - "overrides": [ - { - "See https://github.com/prettier/prettier/issues/2276": "", - "files": "*.json", - "options": { - "parser": "jsonc" - } - } - ] + "endOfLine": "auto" } \ No newline at end of file From b2d787c3a0af7918c266ba1ab39477f17fe77dbf Mon Sep 17 00:00:00 2001 From: ExampleWasTaken <58574351+ExampleWasTaken@users.noreply.github.com> Date: Mon, 17 Jun 2024 23:23:04 +0200 Subject: [PATCH 10/82] fix markdown formatting --- .editorconfig | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.editorconfig b/.editorconfig index eba61550..cef82d52 100644 --- a/.editorconfig +++ b/.editorconfig @@ -13,6 +13,7 @@ insert_final_newline = true tab_width = 2 # YAML is usually 2 spaces -[*.{yml,yaml}] +# Markdown will cause weird formating with 4 spaces +[*.{md,yml,yaml}] indent_size = 2 tab_width = 2 From fce004d32040d5526e87fb06c1b2db12666e44e9 Mon Sep 17 00:00:00 2001 From: ExampleWasTaken <58574351+ExampleWasTaken@users.noreply.github.com> Date: Tue, 18 Jun 2024 00:59:50 +0200 Subject: [PATCH 11/82] fix prettier --- .github/CHANGELOG.md | 12 +- .github/CONTRIBUTING.md | 61 +- .github/ISSUE_TEMPLATE/bug_report_beta.yaml | 2 +- .../ISSUE_TEMPLATE/feature_request_beta.yaml | 2 +- .github/dependabot.yml | 24 +- .github/workflows/cdn-upload-production.yaml | 40 +- .github/workflows/cdn-upload-staging.yaml | 40 +- .github/workflows/pr.yaml | 56 +- .github/workflows/verify-changelog.yml | 48 +- README.md | 4 +- config/production.json | 213 +- config/staging.json | 203 +- nodemon.json | 14 +- package-lock.json | 11622 ++++++++-------- package.json | 106 +- src/client.ts | 52 +- src/commands/context/message/reportMessage.ts | 564 +- src/commands/context/user/listInfractions.ts | 12 +- src/commands/context/user/userInfo.ts | 126 +- src/commands/index.ts | 64 +- src/commands/moderation/cacheUpdate.ts | 232 +- src/commands/moderation/clearMessages.ts | 212 +- src/commands/moderation/commandTable.ts | 214 +- src/commands/moderation/deployCommands.ts | 88 +- src/commands/moderation/faq/faq.ts | 120 +- .../moderation/faq/functions/addFaq.ts | 242 +- .../moderation/faq/functions/faqPrintAll.ts | 110 +- .../moderation/faq/functions/listFaq.ts | 132 +- .../moderation/faq/functions/removeFaq.ts | 104 +- .../moderation/infractions/functions/ban.ts | 316 +- .../functions/deleteInfractions.ts | 158 +- .../infractions/functions/listInfractions.ts | 694 +- .../infractions/functions/removeTimeout.ts | 136 +- .../infractions/functions/timeout.ts | 358 +- .../infractions/functions/unbanInfractions.ts | 204 +- .../infractions/functions/userNote.ts | 206 +- .../moderation/infractions/functions/warn.ts | 280 +- .../moderation/infractions/infractions.ts | 414 +- src/commands/moderation/listRoleUsers.ts | 126 +- src/commands/moderation/roleAssignment.ts | 154 +- src/commands/moderation/rules.ts | 108 +- .../moderation/slowmode/functions/disable.ts | 78 +- .../moderation/slowmode/functions/set.ts | 98 +- src/commands/moderation/slowmode/slowmode.ts | 326 +- src/commands/moderation/welcome.ts | 172 +- src/commands/moderation/whois.ts | 144 +- src/commands/utils/avatar.ts | 34 +- src/commands/utils/birthday/birthday.ts | 152 +- .../utils/birthday/functions/listBirthday.ts | 102 +- .../birthday/functions/removeBirthday.ts | 36 +- .../utils/birthday/functions/setBirthday.ts | 132 +- src/commands/utils/count.ts | 52 +- src/commands/utils/docSearch.ts | 96 +- .../github/functions/githubPullRequest.ts | 58 +- .../github/functions/handleGithubIssue.ts | 58 +- src/commands/utils/github/github.ts | 100 +- src/commands/utils/help.ts | 208 +- src/commands/utils/liveFlights.ts | 46 +- src/commands/utils/locate/base-urls.ts | 38 +- .../locate/functions/filterSearchResults.ts | 36 +- .../utils/locate/functions/handleCommand.ts | 52 +- src/commands/utils/locate/locate.ts | 102 +- .../utils/locate/panels/a32nx/a32nx-panels.ts | 266 +- .../utils/locate/panels/a32nx/flyPad.ts | 12 +- .../utils/locate/panels/a32nx/front-panel.ts | 204 +- .../utils/locate/panels/a32nx/glareshield.ts | 160 +- .../utils/locate/panels/a32nx/overhead.ts | 698 +- .../utils/locate/panels/a32nx/pedestal.ts | 294 +- .../locate/panels/a32nx/rear-cb-panel.ts | 12 +- src/commands/utils/locate/panels/panel.ts | 48 +- src/commands/utils/memberCount.ts | 16 +- src/commands/utils/metar.ts | 149 +- src/commands/utils/ping.ts | 30 +- src/commands/utils/reportedIssues.ts | 182 +- src/commands/utils/roleInfo.ts | 40 +- src/commands/utils/searchFaq.ts | 98 +- src/commands/utils/simbriefData.ts | 142 +- src/commands/utils/station.ts | 154 +- src/commands/utils/taf.ts | 173 +- .../vatsim/functions/vatsimControllers.ts | 180 +- .../utils/vatsim/functions/vatsimEvents.ts | 144 +- .../utils/vatsim/functions/vatsimObservers.ts | 136 +- .../utils/vatsim/functions/vatsimPilots.ts | 116 +- .../utils/vatsim/functions/vatsimStats.ts | 140 +- src/commands/utils/vatsim/vatsim.ts | 240 +- src/commands/utils/wolframAlpha.ts | 182 +- src/commands/utils/zulu.ts | 54 +- src/events/autocompleteHandler.ts | 50 +- src/events/buttonHandlers/buttonHandler.ts | 50 +- .../functions/handleRoleAssignment.ts | 64 +- src/events/contextInteractionHandler.ts | 58 +- src/events/index.ts | 18 +- src/events/logging/detectBan.ts | 352 +- src/events/logging/messageDelete.ts | 192 +- src/events/logging/messageUpdate.ts | 112 +- src/events/logging/scamLogs.ts | 377 +- src/events/ready.ts | 228 +- src/events/slashCommandHandler.ts | 102 +- src/lib/autocomplete.ts | 6 +- src/lib/config.ts | 182 +- src/lib/contextMenuCommand.ts | 28 +- src/lib/db.ts | 44 +- src/lib/durationInEnglish.ts | 28 +- src/lib/embed.ts | 26 +- src/lib/events.ts | 34 +- src/lib/genericEmbedPagination.ts | 132 +- src/lib/infractionEmbedPagination.ts | 234 +- src/lib/logger.ts | 24 +- src/lib/replies.ts | 28 +- src/lib/scheduler.ts | 52 +- src/lib/schedulerJobs/autoDisableSlowMode.ts | 164 +- src/lib/schedulerJobs/postBirthdays.ts | 230 +- src/lib/schedulerJobs/sendHeartbeat.ts | 50 +- src/lib/schemas/birthdaySchema.ts | 10 +- src/lib/schemas/faqSchema.ts | 8 +- src/lib/schemas/infractionSchema.ts | 28 +- src/lib/slashCommand.ts | 44 +- src/scripts/deployCommands.ts | 20 +- tsconfig.json | 22 +- 119 files changed, 13402 insertions(+), 13458 deletions(-) diff --git a/.github/CHANGELOG.md b/.github/CHANGELOG.md index 1aa61ff1..4ac0a4e3 100644 --- a/.github/CHANGELOG.md +++ b/.github/CHANGELOG.md @@ -1,6 +1,6 @@ ## Changelog -Update _ May 2024 +Update \_ May 2024 - fix: keep footer on embed expire (29/05/2024) - feat: /clear-messages command (29/05/2024) @@ -16,12 +16,12 @@ Update _ May 2024 - fix: lint workflow failing silently (18/05/2024) - chore: fix eol issues on Windows (17/05/2024) -Update _ April 2024 +Update \_ April 2024 - fix: clarify errors in timeout command (30/04/2024) - fix: adds mod alerts to the config requirements (30/04/2024) -Update _ March 2024 +Update \_ March 2024 - fix: birthday handler user caching issue (23/03/2024) - feat: adds github issue command (18/03/2024) @@ -29,7 +29,7 @@ Update _ March 2024 - fix: multiple plus symbols in zulu command (18/03/2024) - feat: add infractions counts to buttons in list infractions command (18/03/2024) -Update _ February 2024 +Update \_ February 2024 - fix: report message logging bug (18/02/2024) - feat: command to list users in a role (18/02/2024) @@ -40,7 +40,7 @@ Update _ February 2024 - fix: message edit and delete crash (01/02/2024) - feat: add heartbeat mechanism for monitoring (01/02/2024) -Update _ January 2024 +Update \_ January 2024 - fix: defer interaction for cache update (28/01/2024) - fix: defer interaction on birthday list command (28/01/2024) @@ -50,7 +50,7 @@ Update _ January 2024 - fix: ScamLog - Ignore messages entirely unless it has everyone (28/01/2024) - fix: command names (28/01/2024) - fix: ignore Dyno bot (27/01/2024) -- fix: use - instead of _ in command names (27/01/2024) +- fix: use - instead of \_ in command names (27/01/2024) - feat: auto-generation of the command table (24/01/2024) - feat: migrate reportedIssues command (22/01/2024) - feat: docSearch command (22/01/2024) diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index a3b8b5b5..b779954c 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -183,7 +183,7 @@ Some commands may require additional tokens. If you would like to test them out ## Adding a New Command ->Please note, this will only show the basics of adding a command. +> Please note, this will only show the basics of adding a command. 1. Create a new file in the relevant folder within `src/commands/` and name it appropriately. `yourcommand.ts`. 2. Create your command. @@ -224,42 +224,49 @@ import { ApplicationCommandOptionType, ApplicationCommandType } from 'discord.js import { slashCommand, slashCommandStructure, AutocompleteCallback, makeEmbed } from '../../lib'; const data = slashCommandStructure({ - name: 'ping', - description: 'Ping the bot for a response.', - type: ApplicationCommandType.ChatInput, - default_member_permissions: constantsConfig.commandPermission.MANAGE_SERVER, //Optional command permission - always use MANAGE_SERVER and add a comment to specify overrides needed (roles, channels etc.) - dm_permission: false, // Optional, this sets if commands can be run in DMs (global commands only) - options: [{ // Optional, this is where you can add options to your command - name: 'message', - description: 'Provide some text to send back.', - type: ApplicationCommandOptionType.String, - max_length: 100, - required: false, - autocomplete: true, // Optional - This is only required if you plan on using autocomplete for your command. - }], + name: 'ping', + description: 'Ping the bot for a response.', + type: ApplicationCommandType.ChatInput, + default_member_permissions: constantsConfig.commandPermission.MANAGE_SERVER, //Optional command permission - always use MANAGE_SERVER and add a comment to specify overrides needed (roles, channels etc.) + dm_permission: false, // Optional, this sets if commands can be run in DMs (global commands only) + options: [ + { + // Optional, this is where you can add options to your command + name: 'message', + description: 'Provide some text to send back.', + type: ApplicationCommandOptionType.String, + max_length: 100, + required: false, + autocomplete: true, // Optional - This is only required if you plan on using autocomplete for your command. + }, + ], }); // Optional - This is only required if you plan on using autocomplete for your command. const autocompleteCallback: AutocompleteCallback = ({ interaction }) => { - // Autocomplete logic goes here - const choices = [ - { - name: 'Display Name', - value: 'Value that is actually sent to your bot.' - }, - ]; - - // If you can't autocomplete anything respond with an empty array. - return interaction.respond(choices); + // Autocomplete logic goes here + const choices = [ + { + name: 'Display Name', + value: 'Value that is actually sent to your bot.', + }, + ]; + + // If you can't autocomplete anything respond with an empty array. + return interaction.respond(choices); }; -export default slashCommand(data, async ({ interaction }) => { +export default slashCommand( + data, + async ({ interaction }) => { const msg = interaction.options.getString('message') ?? 'Pong 🏓'; const pongEmbed = makeEmbed({ description: msg }); return interaction.reply({ embeds: [pongEmbed] }); -}, autocompleteCallback); // Optional - This is only required if you plan on using autocomplete for your command. + }, + autocompleteCallback, +); // Optional - This is only required if you plan on using autocomplete for your command. ``` ## Command Permissions @@ -272,4 +279,4 @@ Once your command is deployed, you can then go to your server settings, integrat We ask that if you are submitting a pull request that you add a comment to the `default_member_permissions` property to specify what permissions are needed to use the command. This will allow us to easily change and keep track of the permissions required when deploying the command. -Using this permission system enables us to easily change the permissions required to use a command, without having to change any code. \ No newline at end of file +Using this permission system enables us to easily change the permissions required to use a command, without having to change any code. diff --git a/.github/ISSUE_TEMPLATE/bug_report_beta.yaml b/.github/ISSUE_TEMPLATE/bug_report_beta.yaml index 70fffaca..39270b0f 100644 --- a/.github/ISSUE_TEMPLATE/bug_report_beta.yaml +++ b/.github/ISSUE_TEMPLATE/bug_report_beta.yaml @@ -4,7 +4,7 @@ labels: [Bug] body: - type: markdown attributes: - value: "# FlyByWire Discord bot Bug Report Form" + value: '# FlyByWire Discord bot Bug Report Form' - type: dropdown id: type attributes: diff --git a/.github/ISSUE_TEMPLATE/feature_request_beta.yaml b/.github/ISSUE_TEMPLATE/feature_request_beta.yaml index 09f80de0..22c8ddae 100644 --- a/.github/ISSUE_TEMPLATE/feature_request_beta.yaml +++ b/.github/ISSUE_TEMPLATE/feature_request_beta.yaml @@ -4,7 +4,7 @@ labels: [Request] body: - type: markdown attributes: - value: "# FBW Discord Bot Feature Request Form" + value: '# FBW Discord Bot Feature Request Form' - type: dropdown id: type attributes: diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 742f23e8..496872db 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -1,15 +1,15 @@ version: 2 updates: - - package-ecosystem: npm - directory: / - schedule: - interval: monthly - commit-message: - prefix: "chore" - include: scope - ignore: - - dependency-name: "*" - update-types: ["version-update:semver-minor", "version-update:semver-patch"] - open-pull-requests-limit: 10 - target-branch: staging + - package-ecosystem: npm + directory: / + schedule: + interval: monthly + commit-message: + prefix: 'chore' + include: scope + ignore: + - dependency-name: '*' + update-types: ['version-update:semver-minor', 'version-update:semver-patch'] + open-pull-requests-limit: 10 + target-branch: staging diff --git a/.github/workflows/cdn-upload-production.yaml b/.github/workflows/cdn-upload-production.yaml index 5cd033cc..375118c7 100644 --- a/.github/workflows/cdn-upload-production.yaml +++ b/.github/workflows/cdn-upload-production.yaml @@ -1,25 +1,25 @@ name: CDN Upload - Production on: - workflow_dispatch: - push: - branches: - - production - paths: - - 'assets/images**' + workflow_dispatch: + push: + branches: + - production + paths: + - 'assets/images**' jobs: - cdn_upload: - if: github.repository_owner == 'flybywiresim' # Prevent running this on forks - runs-on: ubuntu-latest - steps: - - name: checkout - uses: actions/checkout@v3 - with: - fetch-depth: 0 - - name: Upload to CloudFlare CDN - env: - CLOUDFLARE_CDN_URL: ${{ secrets.CLOUDFLARE_CDN_URL_PRODUCTION }} - CLOUDFLARE_ACCESS_KEY: ${{ secrets.CLOUDFLARE_ACCESS_KEY_PRODUCTION }} - run: | - ./.github/workflow_scripts/cf-cdn.sh + cdn_upload: + if: github.repository_owner == 'flybywiresim' # Prevent running this on forks + runs-on: ubuntu-latest + steps: + - name: checkout + uses: actions/checkout@v3 + with: + fetch-depth: 0 + - name: Upload to CloudFlare CDN + env: + CLOUDFLARE_CDN_URL: ${{ secrets.CLOUDFLARE_CDN_URL_PRODUCTION }} + CLOUDFLARE_ACCESS_KEY: ${{ secrets.CLOUDFLARE_ACCESS_KEY_PRODUCTION }} + run: | + ./.github/workflow_scripts/cf-cdn.sh diff --git a/.github/workflows/cdn-upload-staging.yaml b/.github/workflows/cdn-upload-staging.yaml index 7e774ebf..71154f56 100644 --- a/.github/workflows/cdn-upload-staging.yaml +++ b/.github/workflows/cdn-upload-staging.yaml @@ -1,25 +1,25 @@ name: CDN Upload - Staging on: - workflow_dispatch: - push: - branches: - - staging - paths: - - 'assets/images**' + workflow_dispatch: + push: + branches: + - staging + paths: + - 'assets/images**' jobs: - cdn_upload: - if: github.repository_owner == 'flybywiresim' # Prevent running this on forks - runs-on: ubuntu-latest - steps: - - name: checkout - uses: actions/checkout@v3 - with: - fetch-depth: 0 - - name: Upload to CloudFlare CDN - env: - CLOUDFLARE_CDN_URL: ${{ secrets.CLOUDFLARE_CDN_URL_STAGING }} - CLOUDFLARE_ACCESS_KEY: ${{ secrets.CLOUDFLARE_ACCESS_KEY_STAGING }} - run: | - ./.github/workflow_scripts/cf-cdn.sh + cdn_upload: + if: github.repository_owner == 'flybywiresim' # Prevent running this on forks + runs-on: ubuntu-latest + steps: + - name: checkout + uses: actions/checkout@v3 + with: + fetch-depth: 0 + - name: Upload to CloudFlare CDN + env: + CLOUDFLARE_CDN_URL: ${{ secrets.CLOUDFLARE_CDN_URL_STAGING }} + CLOUDFLARE_ACCESS_KEY: ${{ secrets.CLOUDFLARE_ACCESS_KEY_STAGING }} + run: | + ./.github/workflow_scripts/cf-cdn.sh diff --git a/.github/workflows/pr.yaml b/.github/workflows/pr.yaml index e4f2729f..66036793 100644 --- a/.github/workflows/pr.yaml +++ b/.github/workflows/pr.yaml @@ -1,33 +1,33 @@ name: PR on: - pull_request: - types: - - opened - - synchronize - - reopened - - ready_for_review + pull_request: + types: + - opened + - synchronize + - reopened + - ready_for_review jobs: - lint: - runs-on: ubuntu-latest - if: github.event.pull_request.draft == false - steps: - - name: Checkout source - uses: actions/checkout@v3 - - name: install - run: npm install --no-optional - - name: Check Lint - run: npm run lint - build: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v3 - - name: Use Node.js 18.x - uses: actions/setup-node@v3 - with: - node-version: '18.x' - - name: Install dependencies - run: npm ci - - name: Build - run: npm run build --if-present + lint: + runs-on: ubuntu-latest + if: github.event.pull_request.draft == false + steps: + - name: Checkout source + uses: actions/checkout@v3 + - name: install + run: npm install --no-optional + - name: Check Lint + run: npm run lint + build: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - name: Use Node.js 18.x + uses: actions/setup-node@v3 + with: + node-version: '18.x' + - name: Install dependencies + run: npm ci + - name: Build + run: npm run build --if-present diff --git a/.github/workflows/verify-changelog.yml b/.github/workflows/verify-changelog.yml index 2c838c61..5fab6037 100644 --- a/.github/workflows/verify-changelog.yml +++ b/.github/workflows/verify-changelog.yml @@ -1,29 +1,29 @@ name: Verify Changelog on: - pull_request: - types: - - opened - - synchronize - - reopened - - ready_for_review - - labeled - - unlabeled + pull_request: + types: + - opened + - synchronize + - reopened + - ready_for_review + - labeled + - unlabeled jobs: - verify: - runs-on: ubuntu-latest - if: ${{ github.event.pull_request.draft == false && github.repository_owner == 'flybywiresim' }} # Prevent running on forks - steps: - - name: checkout - uses: actions/checkout@v3 - with: - fetch-depth: 0 - - name: Verify changelog - uses: Zomzog/changelog-checker@v1.2.0 - with: - fileName: CHANGELOG.md - checkNotification: Simple - noChangelogLabel: skip changelog - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + verify: + runs-on: ubuntu-latest + if: ${{ github.event.pull_request.draft == false && github.repository_owner == 'flybywiresim' }} # Prevent running on forks + steps: + - name: checkout + uses: actions/checkout@v3 + with: + fetch-depth: 0 + - name: Verify changelog + uses: Zomzog/changelog-checker@v1.2.0 + with: + fileName: CHANGELOG.md + checkNotification: Simple + noChangelogLabel: skip changelog + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/README.md b/README.md index c67439a3..496a7f6c 100644 --- a/README.md +++ b/README.md @@ -13,8 +13,8 @@ This is the repository for the FlyByWire Simulations Discord Bot. You can find t ## Best Practices -* Please use clear names for your PR's and commands. -* Check the #discord-bot channel for regular discussions about the repository and what is being worked on. +- Please use clear names for your PR's and commands. +- Check the #discord-bot channel for regular discussions about the repository and what is being worked on. ## Contributing diff --git a/config/production.json b/config/production.json index 283a2955..2626986a 100644 --- a/config/production.json +++ b/config/production.json @@ -1,125 +1,106 @@ { - "aircraftTypeList": { - "a32nx": "32:1044695612337168494", - "a380x": "38:1044695718348210177" - }, - "channels": { - "A32NX_SUPPORT": "785976111875751956", - "FAQ": "751774575464939580", - "FLIGHT_SCHOOL": "887806920252076053", - "KNOWN_ISSUES": "771435594445226005", - "MOD_ALERTS": "1058416774716067921", - "MOD_LOGS": "783996780181585921", - "ROLES": "751780817772216401", - "SCAM_REPORT_LOGS": "932687046315737149", - "TEAM": "846470774361161808", - "USER_LOGS": "779944761699729418", - "VIDEOS": "739224482945826946" - }, - "colors": { - "FBW_CYAN": "0x00E0FE" - }, - "commandPermission": { - "MANAGE_SERVER": "32" - }, - "guildId": "738864299392630914", - "modLogExclude": [ - "910632773117702185", - "1195041929570832475", - "1195045377431322754", - "1163130801131634868", - "1021464464928809022" - ], - "roleAssignmentIds": [ - { - "group": "interestedIn", - "roles": [ - { - "id": "INTERESTED_IN_PROGRAMMING", - "label": "Interested in Programming" - }, - { - "id": "INTERESTED_IN_MODELLING", - "label": "Interested in Modelling/Design" - } - ] + "aircraftTypeList": { + "a32nx": "32:1044695612337168494", + "a380x": "38:1044695718348210177" }, - { - "group": "mediaAnnouncements", - "roles": [ - { - "id": "SERVER_ANNOUNCEMENT", - "label": "Server Announcements" - }, - { - "id": "A32NX_RELEASES", - "label": "A32NX Releases" - }, + "channels": { + "A32NX_SUPPORT": "785976111875751956", + "FAQ": "751774575464939580", + "FLIGHT_SCHOOL": "887806920252076053", + "KNOWN_ISSUES": "771435594445226005", + "MOD_ALERTS": "1058416774716067921", + "MOD_LOGS": "783996780181585921", + "ROLES": "751780817772216401", + "SCAM_REPORT_LOGS": "932687046315737149", + "TEAM": "846470774361161808", + "USER_LOGS": "779944761699729418", + "VIDEOS": "739224482945826946" + }, + "colors": { + "FBW_CYAN": "0x00E0FE" + }, + "commandPermission": { + "MANAGE_SERVER": "32" + }, + "guildId": "738864299392630914", + "modLogExclude": [ + "910632773117702185", + "1195041929570832475", + "1195045377431322754", + "1163130801131634868", + "1021464464928809022" + ], + "roleAssignmentIds": [ { - "id": "PROGRESS", - "label": "Progress Updates" + "group": "interestedIn", + "roles": [ + { + "id": "INTERESTED_IN_PROGRAMMING", + "label": "Interested in Programming" + }, + { + "id": "INTERESTED_IN_MODELLING", + "label": "Interested in Modelling/Design" + } + ] }, { - "id": "MEDIA_ANNOUNCEMENTS", - "label": "Media Announcements (FBW Youtube)" + "group": "mediaAnnouncements", + "roles": [ + { + "id": "SERVER_ANNOUNCEMENT", + "label": "Server Announcements" + }, + { + "id": "A32NX_RELEASES", + "label": "A32NX Releases" + }, + { + "id": "PROGRESS", + "label": "Progress Updates" + }, + { + "id": "MEDIA_ANNOUNCEMENTS", + "label": "Media Announcements (FBW Youtube)" + } + ] } - ] - } - ], - "roleGroups": { - "BOT": [ - "ADMIN_TEAM", - "MODERATION_TEAM", - "BOT_DEVELOPER" - ], - "STAFF": [ - "ADMIN_TEAM", - "MODERATION_TEAM" - ], - "SUPPORT": [ - "ADMIN_TEAM", - "MODERATION_TEAM", - "DEVELOPMENT_TEAM", - "MEDIA_TEAM", - "COMMUNITY_SUPPORT" ], - "TEAM": [ - "ADMIN_TEAM", - "MODERATION_TEAM", - "DEVELOPMENT_TEAM", - "MEDIA_TEAM", - "FBW_EMERITUS" + "roleGroups": { + "BOT": ["ADMIN_TEAM", "MODERATION_TEAM", "BOT_DEVELOPER"], + "STAFF": ["ADMIN_TEAM", "MODERATION_TEAM"], + "SUPPORT": ["ADMIN_TEAM", "MODERATION_TEAM", "DEVELOPMENT_TEAM", "MEDIA_TEAM", "COMMUNITY_SUPPORT"], + "TEAM": ["ADMIN_TEAM", "MODERATION_TEAM", "DEVELOPMENT_TEAM", "MEDIA_TEAM", "FBW_EMERITUS"] + }, + "roles": { + "A32NX_RELEASES": "748938423045193728", + "ADMIN_TEAM": "738864824305319936", + "BOT_DEVELOPER": "768888763929591818", + "COMMUNITY_SUPPORT": "870394933926830100", + "DEVELOPMENT_TEAM": "747571237475057815", + "FBW_EMERITUS": "878635657680027678", + "INTERESTED_IN_MODELLING": "739301752066801834", + "INTERESTED_IN_PROGRAMMING": "738865243681193994", + "MEDIA_ANNOUNCEMENTS": "779383764756594691", + "MEDIA_TEAM": "756972770214281346", + "MODERATION_TEAM": "739187150909866137", + "PROGRESS": "748938549516042281", + "SERVER_ANNOUNCEMENTS": "748938140701687969" + }, + "threads": { + "BIRTHDAY_THREAD": "930923893206679573", + "COUNT_THREAD": "877049017102659654" + }, + "units": { + "CELSIUS": "\u2103", + "DEGREES": "\u00B0" + }, + "userLogExclude": [ + "628400349979344919", + "910632773117702185", + "1195041929570832475", + "1195045377431322754", + "1163130801131634868", + "1021464464928809022" ] - }, - "roles": { - "A32NX_RELEASES": "748938423045193728", - "ADMIN_TEAM": "738864824305319936", - "BOT_DEVELOPER": "768888763929591818", - "COMMUNITY_SUPPORT": "870394933926830100", - "DEVELOPMENT_TEAM": "747571237475057815", - "FBW_EMERITUS": "878635657680027678", - "INTERESTED_IN_MODELLING": "739301752066801834", - "INTERESTED_IN_PROGRAMMING": "738865243681193994", - "MEDIA_ANNOUNCEMENTS": "779383764756594691", - "MEDIA_TEAM": "756972770214281346", - "MODERATION_TEAM": "739187150909866137", - "PROGRESS": "748938549516042281", - "SERVER_ANNOUNCEMENTS": "748938140701687969" - }, - "threads": { - "BIRTHDAY_THREAD": "930923893206679573", - "COUNT_THREAD": "877049017102659654" - }, - "units": { - "CELSIUS": "\u2103", - "DEGREES": "\u00B0" - }, - "userLogExclude": [ - "628400349979344919", - "910632773117702185", - "1195041929570832475", - "1195045377431322754", - "1163130801131634868", - "1021464464928809022" - ] } diff --git a/config/staging.json b/config/staging.json index 0aee3cdb..6041e4df 100644 --- a/config/staging.json +++ b/config/staging.json @@ -1,120 +1,101 @@ { - "aircraftTypeList": { - "a32nx": "32:1044695612337168494", - "a380x": "38:1044695718348210177" - }, - "channels": { - "A32NX_SUPPORT": "1162805236390449202", - "FAQ": "1162805304396877995", - "FLIGHT_SCHOOL": "1162805386378747934", - "KNOWN_ISSUES": "1162805409250291803", - "MOD_ALERTS": "1208403625672450089", - "MOD_LOGS": "1162804981338996756", - "ROLES": "1162805319966138519", - "SCAM_REPORT_LOGS": "1162805088813854932", - "TEAM": "1162805139363610664", - "USER_LOGS": "1162805003728212040", - "VIDEOS": "1162821497795133500" - }, - "colors": { - "FBW_CYAN": "0x00E0FE" - }, - "commandPermission": { - "MANAGE_SERVER": "32" - }, - "guildId": "1162804406681608252", - "modLogExclude": [ - "628400349979344919", - "910632773117702185", - "1195041929570832475", - "1195045377431322754", - "1163130801131634868", - "1021464464928809022" - ], - "roleAssignmentIds": [ - { - "group": "interestedIn", - "roles": [ - { - "id": "TESTER", - "label": "Tester" - }, - { - "id": "BOT_DEVELOPER", - "label": "Bot Developer" - }, - { - "id": "INTERESTED_IN_PROGRAMMING", - "label": "Interested in Programming" - } - ] + "aircraftTypeList": { + "a32nx": "32:1044695612337168494", + "a380x": "38:1044695718348210177" + }, + "channels": { + "A32NX_SUPPORT": "1162805236390449202", + "FAQ": "1162805304396877995", + "FLIGHT_SCHOOL": "1162805386378747934", + "KNOWN_ISSUES": "1162805409250291803", + "MOD_ALERTS": "1208403625672450089", + "MOD_LOGS": "1162804981338996756", + "ROLES": "1162805319966138519", + "SCAM_REPORT_LOGS": "1162805088813854932", + "TEAM": "1162805139363610664", + "USER_LOGS": "1162805003728212040", + "VIDEOS": "1162821497795133500" + }, + "colors": { + "FBW_CYAN": "0x00E0FE" }, - { - "group": "mediaAnnouncements", - "roles": [ + "commandPermission": { + "MANAGE_SERVER": "32" + }, + "guildId": "1162804406681608252", + "modLogExclude": [ + "628400349979344919", + "910632773117702185", + "1195041929570832475", + "1195045377431322754", + "1163130801131634868", + "1021464464928809022" + ], + "roleAssignmentIds": [ { - "id": "SERVER_ANNOUNCEMENT", - "label": "Server Announcements" + "group": "interestedIn", + "roles": [ + { + "id": "TESTER", + "label": "Tester" + }, + { + "id": "BOT_DEVELOPER", + "label": "Bot Developer" + }, + { + "id": "INTERESTED_IN_PROGRAMMING", + "label": "Interested in Programming" + } + ] }, { - "id": "PROGRESS_ANNOUNCEMENT", - "label": "Progress Announcements" + "group": "mediaAnnouncements", + "roles": [ + { + "id": "SERVER_ANNOUNCEMENT", + "label": "Server Announcements" + }, + { + "id": "PROGRESS_ANNOUNCEMENT", + "label": "Progress Announcements" + } + ] } - ] - } - ], - "roleGroups": { - "BOT": [ - "ADMIN_TEAM", - "MODERATION_TEAM", - "BOT_DEVELOPER" - ], - "STAFF": [ - "ADMIN_TEAM", - "MODERATION_TEAM" - ], - "SUPPORT": [ - "ADMIN_TEAM", - "MODERATION_TEAM", - "DEVELOPMENT_TEAM", - "MEDIA_TEAM", - "COMMUNITY_SUPPORT" ], - "TEAM": [ - "ADMIN_TEAM", - "MODERATION_TEAM", - "DEVELOPMENT_TEAM", - "MEDIA_TEAM", - "FBW_EMERITUS" + "roleGroups": { + "BOT": ["ADMIN_TEAM", "MODERATION_TEAM", "BOT_DEVELOPER"], + "STAFF": ["ADMIN_TEAM", "MODERATION_TEAM"], + "SUPPORT": ["ADMIN_TEAM", "MODERATION_TEAM", "DEVELOPMENT_TEAM", "MEDIA_TEAM", "COMMUNITY_SUPPORT"], + "TEAM": ["ADMIN_TEAM", "MODERATION_TEAM", "DEVELOPMENT_TEAM", "MEDIA_TEAM", "FBW_EMERITUS"] + }, + "roles": { + "ADMIN_TEAM": "1162821800225419272", + "BOT_DEVELOPER": "1162822853306101901", + "COMMUNITY_SUPPORT": "1162822911745347594", + "DEVELOPMENT_TEAM": "1162822704248930455", + "FBW_EMERITUS": "1162822804832522290", + "INTERESTED_IN_PROGRAMMING": "1162823114753855559", + "MEDIA_TEAM": "1162822767079588000", + "MODERATION_TEAM": "1162821885202006188", + "PROGRESS_ANNOUNCEMENT": "1162823072089387150", + "SERVER_ANNOUNCEMENT": "1162823032092495892", + "TESTER": "1162822140391850006" + }, + "threads": { + "BIRTHDAY_THREAD": "1162805202487873596", + "COUNT_THREAD": "1162805582961594438" + }, + "units": { + "CELSIUS": "\u2103", + "DEGREES": "\u00B0" + }, + "userLogExclude": [ + "628400349979344919", + "910632773117702185", + "1195041929570832475", + "1195045377431322754", + "1163130801131634868", + "1021464464928809022" ] - }, - "roles": { - "ADMIN_TEAM": "1162821800225419272", - "BOT_DEVELOPER": "1162822853306101901", - "COMMUNITY_SUPPORT": "1162822911745347594", - "DEVELOPMENT_TEAM": "1162822704248930455", - "FBW_EMERITUS": "1162822804832522290", - "INTERESTED_IN_PROGRAMMING": "1162823114753855559", - "MEDIA_TEAM": "1162822767079588000", - "MODERATION_TEAM": "1162821885202006188", - "PROGRESS_ANNOUNCEMENT": "1162823072089387150", - "SERVER_ANNOUNCEMENT": "1162823032092495892", - "TESTER": "1162822140391850006" - }, - "threads": { - "BIRTHDAY_THREAD": "1162805202487873596", - "COUNT_THREAD": "1162805582961594438" - }, - "units": { - "CELSIUS": "\u2103", - "DEGREES": "\u00B0" - }, - "userLogExclude": [ - "628400349979344919", - "910632773117702185", - "1195041929570832475", - "1195045377431322754", - "1163130801131634868", - "1021464464928809022" - ] } diff --git a/nodemon.json b/nodemon.json index 923402ab..253e4449 100644 --- a/nodemon.json +++ b/nodemon.json @@ -1,9 +1,9 @@ { - "restartable": "rs", - "ignore": ["node_modules/"], - "watch": ["src/"], - "execMap": { - "ts": "ts-node" - }, - "ext": "js,json,ts" + "restartable": "rs", + "ignore": ["node_modules/"], + "watch": ["src/"], + "execMap": { + "ts": "ts-node" + }, + "ext": "js,json,ts" } diff --git a/package-lock.json b/package-lock.json index 7ace498c..fdc3313d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,5815 +1,5815 @@ { - "name": "fbw-discord-bot", - "version": "1.0.0", - "lockfileVersion": 3, - "requires": true, - "packages": { - "": { - "name": "fbw-discord-bot", - "version": "1.0.0", - "license": "AGPL-3.0", - "dependencies": { - "@aws-sdk/client-s3": "^3.499.0", - "@aws-sdk/lib-storage": "^3.499.0", - "@hokify/agenda": "^6.0.0", - "@octokit/request": "^8.1.1", - "bad-words": "^3.0.4", - "config": "^3.3.9", - "discord.js": "^14.11.0", - "jsdom": "^23.2.0", - "moment": "^2.29.4", - "mongoose": "^8.0.3", - "node-fetch": "^2.6.10", - "winston": "^3.3.4" - }, - "devDependencies": { - "@eslint/js": "^9.3.0", - "@types/bad-words": "^3.0.3", - "@types/config": "^3.3.1", - "@types/jsdom": "^21.1.6", - "@types/node": "^18.0.0", - "@types/node-fetch": "^2.6.10", - "dotenv": "^16.0.0", - "eslint": "^9.4.0", - "eslint-config-prettier": "^9.1.0", - "eslint-plugin-prettier": "^5.1.3", - "nodemon": "^3.0.2", - "prettier": "^3.3.2", - "ts-node": "^10.4.0", - "typescript": "^5.4.5", - "typescript-eslint": "^8.0.0-alpha.30" - }, - "engines": { - "node": "18.x" - } - }, - "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/@asamuzakjp/dom-selector": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/@asamuzakjp/dom-selector/-/dom-selector-2.0.2.tgz", - "integrity": "sha512-x1KXOatwofR6ZAYzXRBL5wrdV0vwNxlTCK9NCuLqAzQYARqGcvFwiJA6A1ERuh+dgeA4Dxm3JBYictIes+SqUQ==", - "dependencies": { - "bidi-js": "^1.0.3", - "css-tree": "^2.3.1", - "is-potential-custom-element-name": "^1.0.1" - } - }, - "node_modules/@aws-crypto/crc32": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@aws-crypto/crc32/-/crc32-3.0.0.tgz", - "integrity": "sha512-IzSgsrxUcsrejQbPVilIKy16kAT52EwB6zSaI+M3xxIhKh5+aldEyvI+z6erM7TCLB2BJsFrtHjp6/4/sr+3dA==", - "dependencies": { - "@aws-crypto/util": "^3.0.0", - "@aws-sdk/types": "^3.222.0", - "tslib": "^1.11.1" - } - }, - "node_modules/@aws-crypto/crc32/node_modules/tslib": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" - }, - "node_modules/@aws-crypto/crc32c": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@aws-crypto/crc32c/-/crc32c-3.0.0.tgz", - "integrity": "sha512-ENNPPManmnVJ4BTXlOjAgD7URidbAznURqD0KvfREyc4o20DPYdEldU1f5cQ7Jbj0CJJSPaMIk/9ZshdB3210w==", - "dependencies": { - "@aws-crypto/util": "^3.0.0", - "@aws-sdk/types": "^3.222.0", - "tslib": "^1.11.1" - } - }, - "node_modules/@aws-crypto/crc32c/node_modules/tslib": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" - }, - "node_modules/@aws-crypto/ie11-detection": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@aws-crypto/ie11-detection/-/ie11-detection-3.0.0.tgz", - "integrity": "sha512-341lBBkiY1DfDNKai/wXM3aujNBkXR7tq1URPQDL9wi3AUbI80NR74uF1TXHMm7po1AcnFk8iu2S2IeU/+/A+Q==", - "dependencies": { - "tslib": "^1.11.1" - } - }, - "node_modules/@aws-crypto/ie11-detection/node_modules/tslib": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" - }, - "node_modules/@aws-crypto/sha1-browser": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@aws-crypto/sha1-browser/-/sha1-browser-3.0.0.tgz", - "integrity": "sha512-NJth5c997GLHs6nOYTzFKTbYdMNA6/1XlKVgnZoaZcQ7z7UJlOgj2JdbHE8tiYLS3fzXNCguct77SPGat2raSw==", - "dependencies": { - "@aws-crypto/ie11-detection": "^3.0.0", - "@aws-crypto/supports-web-crypto": "^3.0.0", - "@aws-crypto/util": "^3.0.0", - "@aws-sdk/types": "^3.222.0", - "@aws-sdk/util-locate-window": "^3.0.0", - "@aws-sdk/util-utf8-browser": "^3.0.0", - "tslib": "^1.11.1" - } - }, - "node_modules/@aws-crypto/sha1-browser/node_modules/tslib": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" - }, - "node_modules/@aws-crypto/sha256-browser": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@aws-crypto/sha256-browser/-/sha256-browser-3.0.0.tgz", - "integrity": "sha512-8VLmW2B+gjFbU5uMeqtQM6Nj0/F1bro80xQXCW6CQBWgosFWXTx77aeOF5CAIAmbOK64SdMBJdNr6J41yP5mvQ==", - "dependencies": { - "@aws-crypto/ie11-detection": "^3.0.0", - "@aws-crypto/sha256-js": "^3.0.0", - "@aws-crypto/supports-web-crypto": "^3.0.0", - "@aws-crypto/util": "^3.0.0", - "@aws-sdk/types": "^3.222.0", - "@aws-sdk/util-locate-window": "^3.0.0", - "@aws-sdk/util-utf8-browser": "^3.0.0", - "tslib": "^1.11.1" - } - }, - "node_modules/@aws-crypto/sha256-browser/node_modules/tslib": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" - }, - "node_modules/@aws-crypto/sha256-js": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@aws-crypto/sha256-js/-/sha256-js-3.0.0.tgz", - "integrity": "sha512-PnNN7os0+yd1XvXAy23CFOmTbMaDxgxXtTKHybrJ39Y8kGzBATgBFibWJKH6BhytLI/Zyszs87xCOBNyBig6vQ==", - "dependencies": { - "@aws-crypto/util": "^3.0.0", - "@aws-sdk/types": "^3.222.0", - "tslib": "^1.11.1" - } - }, - "node_modules/@aws-crypto/sha256-js/node_modules/tslib": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" - }, - "node_modules/@aws-crypto/supports-web-crypto": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@aws-crypto/supports-web-crypto/-/supports-web-crypto-3.0.0.tgz", - "integrity": "sha512-06hBdMwUAb2WFTuGG73LSC0wfPu93xWwo5vL2et9eymgmu3Id5vFAHBbajVWiGhPO37qcsdCap/FqXvJGJWPIg==", - "dependencies": { - "tslib": "^1.11.1" - } - }, - "node_modules/@aws-crypto/supports-web-crypto/node_modules/tslib": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" - }, - "node_modules/@aws-crypto/util": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@aws-crypto/util/-/util-3.0.0.tgz", - "integrity": "sha512-2OJlpeJpCR48CC8r+uKVChzs9Iungj9wkZrl8Z041DWEWvyIHILYKCPNzJghKsivj+S3mLo6BVc7mBNzdxA46w==", - "dependencies": { - "@aws-sdk/types": "^3.222.0", - "@aws-sdk/util-utf8-browser": "^3.0.0", - "tslib": "^1.11.1" - } - }, - "node_modules/@aws-crypto/util/node_modules/tslib": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" - }, - "node_modules/@aws-sdk/client-cognito-identity": { - "version": "3.485.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-cognito-identity/-/client-cognito-identity-3.485.0.tgz", - "integrity": "sha512-1SYhvRu/dNqQ5HcIgm7wIpyn1FsthbgG04o6QyVAnfOxmawFt4nqCEtNCwsmlX7o1ZCTYY+qNrozb7XZy+GKSQ==", - "optional": true, - "dependencies": { - "@aws-crypto/sha256-browser": "3.0.0", - "@aws-crypto/sha256-js": "3.0.0", - "@aws-sdk/client-sts": "3.485.0", - "@aws-sdk/core": "3.485.0", - "@aws-sdk/credential-provider-node": "3.485.0", - "@aws-sdk/middleware-host-header": "3.485.0", - "@aws-sdk/middleware-logger": "3.485.0", - "@aws-sdk/middleware-recursion-detection": "3.485.0", - "@aws-sdk/middleware-signing": "3.485.0", - "@aws-sdk/middleware-user-agent": "3.485.0", - "@aws-sdk/region-config-resolver": "3.485.0", - "@aws-sdk/types": "3.485.0", - "@aws-sdk/util-endpoints": "3.485.0", - "@aws-sdk/util-user-agent-browser": "3.485.0", - "@aws-sdk/util-user-agent-node": "3.485.0", - "@smithy/config-resolver": "^2.0.23", - "@smithy/core": "^1.2.2", - "@smithy/fetch-http-handler": "^2.3.2", - "@smithy/hash-node": "^2.0.18", - "@smithy/invalid-dependency": "^2.0.16", - "@smithy/middleware-content-length": "^2.0.18", - "@smithy/middleware-endpoint": "^2.3.0", - "@smithy/middleware-retry": "^2.0.26", - "@smithy/middleware-serde": "^2.0.16", - "@smithy/middleware-stack": "^2.0.10", - "@smithy/node-config-provider": "^2.1.9", - "@smithy/node-http-handler": "^2.2.2", - "@smithy/protocol-http": "^3.0.12", - "@smithy/smithy-client": "^2.2.1", - "@smithy/types": "^2.8.0", - "@smithy/url-parser": "^2.0.16", - "@smithy/util-base64": "^2.0.1", - "@smithy/util-body-length-browser": "^2.0.1", - "@smithy/util-body-length-node": "^2.1.0", - "@smithy/util-defaults-mode-browser": "^2.0.24", - "@smithy/util-defaults-mode-node": "^2.0.32", - "@smithy/util-endpoints": "^1.0.8", - "@smithy/util-retry": "^2.0.9", - "@smithy/util-utf8": "^2.0.2", - "tslib": "^2.5.0" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-sdk/client-s3": { - "version": "3.499.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-s3/-/client-s3-3.499.0.tgz", - "integrity": "sha512-4ssQqde/iY5fTJbWuFPzPuECtihdCAA9tfluv6fXYCJS3wMLf9x21qp6b7fIbUf6vjOJ2edmYd+DXk+0CMnTFg==", - "dependencies": { - "@aws-crypto/sha1-browser": "3.0.0", - "@aws-crypto/sha256-browser": "3.0.0", - "@aws-crypto/sha256-js": "3.0.0", - "@aws-sdk/client-sts": "3.499.0", - "@aws-sdk/core": "3.496.0", - "@aws-sdk/credential-provider-node": "3.499.0", - "@aws-sdk/middleware-bucket-endpoint": "3.496.0", - "@aws-sdk/middleware-expect-continue": "3.496.0", - "@aws-sdk/middleware-flexible-checksums": "3.496.0", - "@aws-sdk/middleware-host-header": "3.496.0", - "@aws-sdk/middleware-location-constraint": "3.496.0", - "@aws-sdk/middleware-logger": "3.496.0", - "@aws-sdk/middleware-recursion-detection": "3.496.0", - "@aws-sdk/middleware-sdk-s3": "3.499.0", - "@aws-sdk/middleware-signing": "3.496.0", - "@aws-sdk/middleware-ssec": "3.498.0", - "@aws-sdk/middleware-user-agent": "3.496.0", - "@aws-sdk/region-config-resolver": "3.496.0", - "@aws-sdk/signature-v4-multi-region": "3.499.0", - "@aws-sdk/types": "3.496.0", - "@aws-sdk/util-endpoints": "3.496.0", - "@aws-sdk/util-user-agent-browser": "3.496.0", - "@aws-sdk/util-user-agent-node": "3.496.0", - "@aws-sdk/xml-builder": "3.496.0", - "@smithy/config-resolver": "^2.1.1", - "@smithy/core": "^1.3.1", - "@smithy/eventstream-serde-browser": "^2.1.1", - "@smithy/eventstream-serde-config-resolver": "^2.1.1", - "@smithy/eventstream-serde-node": "^2.1.1", - "@smithy/fetch-http-handler": "^2.4.1", - "@smithy/hash-blob-browser": "^2.1.1", - "@smithy/hash-node": "^2.1.1", - "@smithy/hash-stream-node": "^2.1.1", - "@smithy/invalid-dependency": "^2.1.1", - "@smithy/md5-js": "^2.1.1", - "@smithy/middleware-content-length": "^2.1.1", - "@smithy/middleware-endpoint": "^2.4.1", - "@smithy/middleware-retry": "^2.1.1", - "@smithy/middleware-serde": "^2.1.1", - "@smithy/middleware-stack": "^2.1.1", - "@smithy/node-config-provider": "^2.2.1", - "@smithy/node-http-handler": "^2.3.1", - "@smithy/protocol-http": "^3.1.1", - "@smithy/smithy-client": "^2.3.1", - "@smithy/types": "^2.9.1", - "@smithy/url-parser": "^2.1.1", - "@smithy/util-base64": "^2.1.1", - "@smithy/util-body-length-browser": "^2.1.1", - "@smithy/util-body-length-node": "^2.2.1", - "@smithy/util-defaults-mode-browser": "^2.1.1", - "@smithy/util-defaults-mode-node": "^2.1.1", - "@smithy/util-endpoints": "^1.1.1", - "@smithy/util-retry": "^2.1.1", - "@smithy/util-stream": "^2.1.1", - "@smithy/util-utf8": "^2.1.1", - "@smithy/util-waiter": "^2.1.1", - "fast-xml-parser": "4.2.5", - "tslib": "^2.5.0" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-sdk/client-s3/node_modules/@aws-sdk/client-sso": { - "version": "3.496.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso/-/client-sso-3.496.0.tgz", - "integrity": "sha512-fuaMuxKg7CMUsP9l3kxYWCOxFsBjdA0xj5nlikaDm1661/gB4KkAiGqRY8LsQkpNXvXU8Nj+f7oCFADFyGYzyw==", - "dependencies": { - "@aws-crypto/sha256-browser": "3.0.0", - "@aws-crypto/sha256-js": "3.0.0", - "@aws-sdk/core": "3.496.0", - "@aws-sdk/middleware-host-header": "3.496.0", - "@aws-sdk/middleware-logger": "3.496.0", - "@aws-sdk/middleware-recursion-detection": "3.496.0", - "@aws-sdk/middleware-user-agent": "3.496.0", - "@aws-sdk/region-config-resolver": "3.496.0", - "@aws-sdk/types": "3.496.0", - "@aws-sdk/util-endpoints": "3.496.0", - "@aws-sdk/util-user-agent-browser": "3.496.0", - "@aws-sdk/util-user-agent-node": "3.496.0", - "@smithy/config-resolver": "^2.1.1", - "@smithy/core": "^1.3.1", - "@smithy/fetch-http-handler": "^2.4.1", - "@smithy/hash-node": "^2.1.1", - "@smithy/invalid-dependency": "^2.1.1", - "@smithy/middleware-content-length": "^2.1.1", - "@smithy/middleware-endpoint": "^2.4.1", - "@smithy/middleware-retry": "^2.1.1", - "@smithy/middleware-serde": "^2.1.1", - "@smithy/middleware-stack": "^2.1.1", - "@smithy/node-config-provider": "^2.2.1", - "@smithy/node-http-handler": "^2.3.1", - "@smithy/protocol-http": "^3.1.1", - "@smithy/smithy-client": "^2.3.1", - "@smithy/types": "^2.9.1", - "@smithy/url-parser": "^2.1.1", - "@smithy/util-base64": "^2.1.1", - "@smithy/util-body-length-browser": "^2.1.1", - "@smithy/util-body-length-node": "^2.2.1", - "@smithy/util-defaults-mode-browser": "^2.1.1", - "@smithy/util-defaults-mode-node": "^2.1.1", - "@smithy/util-endpoints": "^1.1.1", - "@smithy/util-retry": "^2.1.1", - "@smithy/util-utf8": "^2.1.1", - "tslib": "^2.5.0" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-sdk/client-s3/node_modules/@aws-sdk/client-sts": { - "version": "3.499.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-sts/-/client-sts-3.499.0.tgz", - "integrity": "sha512-Eyj9STw2DXMtXL5V/v0HYHO6+JjGPi257M5IYyxwqlvRchq6jbOsedobfxclB/gBUyBRtZdnyAIS8uCKjb4kpA==", - "dependencies": { - "@aws-crypto/sha256-browser": "3.0.0", - "@aws-crypto/sha256-js": "3.0.0", - "@aws-sdk/core": "3.496.0", - "@aws-sdk/credential-provider-node": "3.499.0", - "@aws-sdk/middleware-host-header": "3.496.0", - "@aws-sdk/middleware-logger": "3.496.0", - "@aws-sdk/middleware-recursion-detection": "3.496.0", - "@aws-sdk/middleware-user-agent": "3.496.0", - "@aws-sdk/region-config-resolver": "3.496.0", - "@aws-sdk/types": "3.496.0", - "@aws-sdk/util-endpoints": "3.496.0", - "@aws-sdk/util-user-agent-browser": "3.496.0", - "@aws-sdk/util-user-agent-node": "3.496.0", - "@smithy/config-resolver": "^2.1.1", - "@smithy/core": "^1.3.1", - "@smithy/fetch-http-handler": "^2.4.1", - "@smithy/hash-node": "^2.1.1", - "@smithy/invalid-dependency": "^2.1.1", - "@smithy/middleware-content-length": "^2.1.1", - "@smithy/middleware-endpoint": "^2.4.1", - "@smithy/middleware-retry": "^2.1.1", - "@smithy/middleware-serde": "^2.1.1", - "@smithy/middleware-stack": "^2.1.1", - "@smithy/node-config-provider": "^2.2.1", - "@smithy/node-http-handler": "^2.3.1", - "@smithy/protocol-http": "^3.1.1", - "@smithy/smithy-client": "^2.3.1", - "@smithy/types": "^2.9.1", - "@smithy/url-parser": "^2.1.1", - "@smithy/util-base64": "^2.1.1", - "@smithy/util-body-length-browser": "^2.1.1", - "@smithy/util-body-length-node": "^2.2.1", - "@smithy/util-defaults-mode-browser": "^2.1.1", - "@smithy/util-defaults-mode-node": "^2.1.1", - "@smithy/util-endpoints": "^1.1.1", - "@smithy/util-middleware": "^2.1.1", - "@smithy/util-retry": "^2.1.1", - "@smithy/util-utf8": "^2.1.1", - "fast-xml-parser": "4.2.5", - "tslib": "^2.5.0" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-sdk/client-s3/node_modules/@aws-sdk/core": { - "version": "3.496.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/core/-/core-3.496.0.tgz", - "integrity": "sha512-yT+ug7Cw/3eJi7x2es0+46x12+cIJm5Xv+GPWsrTFD1TKgqO/VPEgfDtHFagDNbFmjNQA65Ygc/kEdIX9ICX/A==", - "dependencies": { - "@smithy/core": "^1.3.1", - "@smithy/protocol-http": "^3.1.1", - "@smithy/signature-v4": "^2.1.1", - "@smithy/smithy-client": "^2.3.1", - "@smithy/types": "^2.9.1", - "tslib": "^2.5.0" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-sdk/client-s3/node_modules/@aws-sdk/credential-provider-env": { - "version": "3.496.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-env/-/credential-provider-env-3.496.0.tgz", - "integrity": "sha512-lukQMJ8SWWP5RqkRNOHi/H+WMhRvSWa3Fc5Jf/VP6xHiPLfF1XafcvthtV91e0VwPCiseI+HqChrcGq8pvnxHw==", - "dependencies": { - "@aws-sdk/types": "3.496.0", - "@smithy/property-provider": "^2.1.1", - "@smithy/types": "^2.9.1", - "tslib": "^2.5.0" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-sdk/client-s3/node_modules/@aws-sdk/credential-provider-ini": { - "version": "3.496.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-ini/-/credential-provider-ini-3.496.0.tgz", - "integrity": "sha512-2nD1jp1sIwcQaWK1y/9ruQOkW16RUxZpzgjbW/gnK3iiUXwx+/FNQWxshud+GTSx3Q4x6eIhqsbjtP4VVPPuUA==", - "dependencies": { - "@aws-sdk/credential-provider-env": "3.496.0", - "@aws-sdk/credential-provider-process": "3.496.0", - "@aws-sdk/credential-provider-sso": "3.496.0", - "@aws-sdk/credential-provider-web-identity": "3.496.0", - "@aws-sdk/types": "3.496.0", - "@smithy/credential-provider-imds": "^2.2.1", - "@smithy/property-provider": "^2.1.1", - "@smithy/shared-ini-file-loader": "^2.3.1", - "@smithy/types": "^2.9.1", - "tslib": "^2.5.0" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-sdk/client-s3/node_modules/@aws-sdk/credential-provider-node": { - "version": "3.499.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-node/-/credential-provider-node-3.499.0.tgz", - "integrity": "sha512-EsiSevVmcVSMIq7D9siSH/XVc5I0vMntg1rx6KQdng1Fq8X/RBL5t9wSWEwOl7KFo5HlEsWrLWIpo1WHuzIL/w==", - "dependencies": { - "@aws-sdk/credential-provider-env": "3.496.0", - "@aws-sdk/credential-provider-ini": "3.496.0", - "@aws-sdk/credential-provider-process": "3.496.0", - "@aws-sdk/credential-provider-sso": "3.496.0", - "@aws-sdk/credential-provider-web-identity": "3.496.0", - "@aws-sdk/types": "3.496.0", - "@smithy/credential-provider-imds": "^2.2.1", - "@smithy/property-provider": "^2.1.1", - "@smithy/shared-ini-file-loader": "^2.3.1", - "@smithy/types": "^2.9.1", - "tslib": "^2.5.0" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-sdk/client-s3/node_modules/@aws-sdk/credential-provider-process": { - "version": "3.496.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-process/-/credential-provider-process-3.496.0.tgz", - "integrity": "sha512-/YZscCTGOKVmGr916Th4XF8Sz6JDtZ/n2loHG9exok9iy/qIbACsTRNLP9zexPxhPoue/oZqecY5xbVljfY34A==", - "dependencies": { - "@aws-sdk/types": "3.496.0", - "@smithy/property-provider": "^2.1.1", - "@smithy/shared-ini-file-loader": "^2.3.1", - "@smithy/types": "^2.9.1", - "tslib": "^2.5.0" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-sdk/client-s3/node_modules/@aws-sdk/credential-provider-sso": { - "version": "3.496.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-sso/-/credential-provider-sso-3.496.0.tgz", - "integrity": "sha512-eP7GxpT2QYubSDG7uk1GJW4eNymZCq65IxDyEFCXOP/kfqkxriCY+iVEFG6/Mo3LxvgrgHXU4jxrCAXMAWN43g==", - "dependencies": { - "@aws-sdk/client-sso": "3.496.0", - "@aws-sdk/token-providers": "3.496.0", - "@aws-sdk/types": "3.496.0", - "@smithy/property-provider": "^2.1.1", - "@smithy/shared-ini-file-loader": "^2.3.1", - "@smithy/types": "^2.9.1", - "tslib": "^2.5.0" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-sdk/client-s3/node_modules/@aws-sdk/credential-provider-web-identity": { - "version": "3.496.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-web-identity/-/credential-provider-web-identity-3.496.0.tgz", - "integrity": "sha512-IbP+qLlvJSpNPj+zW6TtFuLRTK5Tf0hW+2pom4vFyi5YSH4pn8UOC136UdewX8vhXGS9BJQ5zBDMasIyl5VeGQ==", - "dependencies": { - "@aws-sdk/types": "3.496.0", - "@smithy/property-provider": "^2.1.1", - "@smithy/types": "^2.9.1", - "tslib": "^2.5.0" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-sdk/client-s3/node_modules/@aws-sdk/middleware-host-header": { - "version": "3.496.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-host-header/-/middleware-host-header-3.496.0.tgz", - "integrity": "sha512-jUdPpSJeqCYXf6hSjfwsfHway7peIV8Vz51w/BN91bF4vB/bYwAC5o9/iJiK/EoByp5asxA8fg9wFOyGjzdbLg==", - "dependencies": { - "@aws-sdk/types": "3.496.0", - "@smithy/protocol-http": "^3.1.1", - "@smithy/types": "^2.9.1", - "tslib": "^2.5.0" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-sdk/client-s3/node_modules/@aws-sdk/middleware-logger": { - "version": "3.496.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-logger/-/middleware-logger-3.496.0.tgz", - "integrity": "sha512-EwMVSY6iBMeGbVnvwdaFl/ClMS/YWtxCAo+bcEtgk8ltRuo7qgbJem8Km/fvWC1vdWvIbe4ArdJ8iGzq62ffAw==", - "dependencies": { - "@aws-sdk/types": "3.496.0", - "@smithy/types": "^2.9.1", - "tslib": "^2.5.0" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-sdk/client-s3/node_modules/@aws-sdk/middleware-recursion-detection": { - "version": "3.496.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-recursion-detection/-/middleware-recursion-detection-3.496.0.tgz", - "integrity": "sha512-+IuOcFsfqg2WAnaEzH6KhVbicqCxtOq9w3DH2jwTpddRlCx2Kqf6wCzg8luhHRGyjBZdsbIS+OXwyMevoppawA==", - "dependencies": { - "@aws-sdk/types": "3.496.0", - "@smithy/protocol-http": "^3.1.1", - "@smithy/types": "^2.9.1", - "tslib": "^2.5.0" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-sdk/client-s3/node_modules/@aws-sdk/middleware-signing": { - "version": "3.496.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-signing/-/middleware-signing-3.496.0.tgz", - "integrity": "sha512-Oq73Brs4IConvWnRlh8jM1V7LHoTw9SVQklu/QW2FPlNrB3B8fuTdWHHYIWv7ybw1bykXoCY99v865Mmq/Or/g==", - "dependencies": { - "@aws-sdk/types": "3.496.0", - "@smithy/property-provider": "^2.1.1", - "@smithy/protocol-http": "^3.1.1", - "@smithy/signature-v4": "^2.1.1", - "@smithy/types": "^2.9.1", - "@smithy/util-middleware": "^2.1.1", - "tslib": "^2.5.0" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-sdk/client-s3/node_modules/@aws-sdk/middleware-user-agent": { - "version": "3.496.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-user-agent/-/middleware-user-agent-3.496.0.tgz", - "integrity": "sha512-+iMtRxFk0GmFWNUF4ilxylOQd9PZdR4ZC9jkcPIh1PZlvKtpCyFywKlk5RRZKklSoJ/CttcqwhMvOXTNbWm/0w==", - "dependencies": { - "@aws-sdk/types": "3.496.0", - "@aws-sdk/util-endpoints": "3.496.0", - "@smithy/protocol-http": "^3.1.1", - "@smithy/types": "^2.9.1", - "tslib": "^2.5.0" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-sdk/client-s3/node_modules/@aws-sdk/region-config-resolver": { - "version": "3.496.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/region-config-resolver/-/region-config-resolver-3.496.0.tgz", - "integrity": "sha512-URrNVOPHPgEDm6QFu6lDC2cUFs+Jx23mA3jEwCvoKlXiEY/ZoWjH8wlX3OMUlLrF1qoUTuD03jjrJzF6zoCgug==", - "dependencies": { - "@aws-sdk/types": "3.496.0", - "@smithy/node-config-provider": "^2.2.1", - "@smithy/types": "^2.9.1", - "@smithy/util-config-provider": "^2.2.1", - "@smithy/util-middleware": "^2.1.1", - "tslib": "^2.5.0" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-sdk/client-s3/node_modules/@aws-sdk/token-providers": { - "version": "3.496.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/token-providers/-/token-providers-3.496.0.tgz", - "integrity": "sha512-fyi8RcObEa1jNETJdc2H6q9VHrrdKCj/b6+fbLvymb7mUVRd0aWUn+24SNUImnSOnrwYnwaMfyyEC388X4MbFQ==", - "dependencies": { - "@aws-crypto/sha256-browser": "3.0.0", - "@aws-crypto/sha256-js": "3.0.0", - "@aws-sdk/middleware-host-header": "3.496.0", - "@aws-sdk/middleware-logger": "3.496.0", - "@aws-sdk/middleware-recursion-detection": "3.496.0", - "@aws-sdk/middleware-user-agent": "3.496.0", - "@aws-sdk/region-config-resolver": "3.496.0", - "@aws-sdk/types": "3.496.0", - "@aws-sdk/util-endpoints": "3.496.0", - "@aws-sdk/util-user-agent-browser": "3.496.0", - "@aws-sdk/util-user-agent-node": "3.496.0", - "@smithy/config-resolver": "^2.1.1", - "@smithy/fetch-http-handler": "^2.4.1", - "@smithy/hash-node": "^2.1.1", - "@smithy/invalid-dependency": "^2.1.1", - "@smithy/middleware-content-length": "^2.1.1", - "@smithy/middleware-endpoint": "^2.4.1", - "@smithy/middleware-retry": "^2.1.1", - "@smithy/middleware-serde": "^2.1.1", - "@smithy/middleware-stack": "^2.1.1", - "@smithy/node-config-provider": "^2.2.1", - "@smithy/node-http-handler": "^2.3.1", - "@smithy/property-provider": "^2.1.1", - "@smithy/protocol-http": "^3.1.1", - "@smithy/shared-ini-file-loader": "^2.3.1", - "@smithy/smithy-client": "^2.3.1", - "@smithy/types": "^2.9.1", - "@smithy/url-parser": "^2.1.1", - "@smithy/util-base64": "^2.1.1", - "@smithy/util-body-length-browser": "^2.1.1", - "@smithy/util-body-length-node": "^2.2.1", - "@smithy/util-defaults-mode-browser": "^2.1.1", - "@smithy/util-defaults-mode-node": "^2.1.1", - "@smithy/util-endpoints": "^1.1.1", - "@smithy/util-retry": "^2.1.1", - "@smithy/util-utf8": "^2.1.1", - "tslib": "^2.5.0" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-sdk/client-s3/node_modules/@aws-sdk/types": { - "version": "3.496.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.496.0.tgz", - "integrity": "sha512-umkGadK4QuNQaMoDICMm7NKRI/mYSXiyPjcn3d53BhsuArYU/52CebGQKdt4At7SwwsiVJZw9RNBHyN5Mm0HVw==", - "dependencies": { - "@smithy/types": "^2.9.1", - "tslib": "^2.5.0" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-sdk/client-s3/node_modules/@aws-sdk/util-endpoints": { - "version": "3.496.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-endpoints/-/util-endpoints-3.496.0.tgz", - "integrity": "sha512-1QzOiWHi383ZwqSi/R2KgKCd7M+6DxkxI5acqLPm8mvDRDP2jRjrnVaC0g9/tlttWousGEemDUWStwrD2mVYSw==", - "dependencies": { - "@aws-sdk/types": "3.496.0", - "@smithy/types": "^2.9.1", - "@smithy/util-endpoints": "^1.1.1", - "tslib": "^2.5.0" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-sdk/client-s3/node_modules/@aws-sdk/util-user-agent-browser": { - "version": "3.496.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-browser/-/util-user-agent-browser-3.496.0.tgz", - "integrity": "sha512-4j2spN+h0I0qfSMsGvJXTfQBu1e18rPdekKvzsGJxhaAE1tNgUfUT4nbvc5uVn0sNjZmirskmJ3kfbzVOrqIFg==", - "dependencies": { - "@aws-sdk/types": "3.496.0", - "@smithy/types": "^2.9.1", - "bowser": "^2.11.0", - "tslib": "^2.5.0" - } - }, - "node_modules/@aws-sdk/client-s3/node_modules/@aws-sdk/util-user-agent-node": { - "version": "3.496.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-node/-/util-user-agent-node-3.496.0.tgz", - "integrity": "sha512-h0Ax0jlDc7UIo3KoSI4C4tVLBFoiAdx3+DhTVfgLS7x93d41dMlziPoBX2RgdcFn37qnzw6AQKTVTMwDbRCGpg==", - "dependencies": { - "@aws-sdk/types": "3.496.0", - "@smithy/node-config-provider": "^2.2.1", - "@smithy/types": "^2.9.1", - "tslib": "^2.5.0" - }, - "engines": { - "node": ">=14.0.0" - }, - "peerDependencies": { - "aws-crt": ">=1.0.0" - }, - "peerDependenciesMeta": { - "aws-crt": { - "optional": true - } - } - }, - "node_modules/@aws-sdk/client-sso": { - "version": "3.485.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso/-/client-sso-3.485.0.tgz", - "integrity": "sha512-apN2bEn0PZs0jD4jAfvwO3dlWqw9YIQJ6TAudM1bd3S5vzWqlBBcLfQpK6taHoQaI+WqgUWXLuOf7gRFbGXKPg==", - "optional": true, - "dependencies": { - "@aws-crypto/sha256-browser": "3.0.0", - "@aws-crypto/sha256-js": "3.0.0", - "@aws-sdk/core": "3.485.0", - "@aws-sdk/middleware-host-header": "3.485.0", - "@aws-sdk/middleware-logger": "3.485.0", - "@aws-sdk/middleware-recursion-detection": "3.485.0", - "@aws-sdk/middleware-user-agent": "3.485.0", - "@aws-sdk/region-config-resolver": "3.485.0", - "@aws-sdk/types": "3.485.0", - "@aws-sdk/util-endpoints": "3.485.0", - "@aws-sdk/util-user-agent-browser": "3.485.0", - "@aws-sdk/util-user-agent-node": "3.485.0", - "@smithy/config-resolver": "^2.0.23", - "@smithy/core": "^1.2.2", - "@smithy/fetch-http-handler": "^2.3.2", - "@smithy/hash-node": "^2.0.18", - "@smithy/invalid-dependency": "^2.0.16", - "@smithy/middleware-content-length": "^2.0.18", - "@smithy/middleware-endpoint": "^2.3.0", - "@smithy/middleware-retry": "^2.0.26", - "@smithy/middleware-serde": "^2.0.16", - "@smithy/middleware-stack": "^2.0.10", - "@smithy/node-config-provider": "^2.1.9", - "@smithy/node-http-handler": "^2.2.2", - "@smithy/protocol-http": "^3.0.12", - "@smithy/smithy-client": "^2.2.1", - "@smithy/types": "^2.8.0", - "@smithy/url-parser": "^2.0.16", - "@smithy/util-base64": "^2.0.1", - "@smithy/util-body-length-browser": "^2.0.1", - "@smithy/util-body-length-node": "^2.1.0", - "@smithy/util-defaults-mode-browser": "^2.0.24", - "@smithy/util-defaults-mode-node": "^2.0.32", - "@smithy/util-endpoints": "^1.0.8", - "@smithy/util-retry": "^2.0.9", - "@smithy/util-utf8": "^2.0.2", - "tslib": "^2.5.0" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-sdk/client-sts": { - "version": "3.485.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-sts/-/client-sts-3.485.0.tgz", - "integrity": "sha512-PI4q36kVF0fpIPZyeQhrwwJZ6SRkOGvU3rX5Qn4b5UY5X+Ct1aLhqSX8/OB372UZIcnh6eSvERu8POHleDO7Jw==", - "optional": true, - "dependencies": { - "@aws-crypto/sha256-browser": "3.0.0", - "@aws-crypto/sha256-js": "3.0.0", - "@aws-sdk/core": "3.485.0", - "@aws-sdk/credential-provider-node": "3.485.0", - "@aws-sdk/middleware-host-header": "3.485.0", - "@aws-sdk/middleware-logger": "3.485.0", - "@aws-sdk/middleware-recursion-detection": "3.485.0", - "@aws-sdk/middleware-user-agent": "3.485.0", - "@aws-sdk/region-config-resolver": "3.485.0", - "@aws-sdk/types": "3.485.0", - "@aws-sdk/util-endpoints": "3.485.0", - "@aws-sdk/util-user-agent-browser": "3.485.0", - "@aws-sdk/util-user-agent-node": "3.485.0", - "@smithy/config-resolver": "^2.0.23", - "@smithy/core": "^1.2.2", - "@smithy/fetch-http-handler": "^2.3.2", - "@smithy/hash-node": "^2.0.18", - "@smithy/invalid-dependency": "^2.0.16", - "@smithy/middleware-content-length": "^2.0.18", - "@smithy/middleware-endpoint": "^2.3.0", - "@smithy/middleware-retry": "^2.0.26", - "@smithy/middleware-serde": "^2.0.16", - "@smithy/middleware-stack": "^2.0.10", - "@smithy/node-config-provider": "^2.1.9", - "@smithy/node-http-handler": "^2.2.2", - "@smithy/protocol-http": "^3.0.12", - "@smithy/smithy-client": "^2.2.1", - "@smithy/types": "^2.8.0", - "@smithy/url-parser": "^2.0.16", - "@smithy/util-base64": "^2.0.1", - "@smithy/util-body-length-browser": "^2.0.1", - "@smithy/util-body-length-node": "^2.1.0", - "@smithy/util-defaults-mode-browser": "^2.0.24", - "@smithy/util-defaults-mode-node": "^2.0.32", - "@smithy/util-endpoints": "^1.0.8", - "@smithy/util-middleware": "^2.0.9", - "@smithy/util-retry": "^2.0.9", - "@smithy/util-utf8": "^2.0.2", - "fast-xml-parser": "4.2.5", - "tslib": "^2.5.0" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-sdk/core": { - "version": "3.485.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/core/-/core-3.485.0.tgz", - "integrity": "sha512-Yvi80DQcbjkYCft471ClE3HuetuNVqntCs6eFOomDcrJaqdOFrXv2kJAxky84MRA/xb7bGlDGAPbTuj1ICputg==", - "optional": true, - "dependencies": { - "@smithy/core": "^1.2.2", - "@smithy/protocol-http": "^3.0.12", - "@smithy/signature-v4": "^2.0.0", - "@smithy/smithy-client": "^2.2.1", - "@smithy/types": "^2.8.0", - "tslib": "^2.5.0" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-sdk/credential-provider-cognito-identity": { - "version": "3.485.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-cognito-identity/-/credential-provider-cognito-identity-3.485.0.tgz", - "integrity": "sha512-XIy5h1AcDiY3V286X7KrLA5HAxLfzLGrUGBPFY+GTJGYetDhlJwFz12q6BOkIfeAhUbT2Umb4ptujX9eqpZJHQ==", - "optional": true, - "dependencies": { - "@aws-sdk/client-cognito-identity": "3.485.0", - "@aws-sdk/types": "3.485.0", - "@smithy/property-provider": "^2.0.0", - "@smithy/types": "^2.8.0", - "tslib": "^2.5.0" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-sdk/credential-provider-env": { - "version": "3.485.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-env/-/credential-provider-env-3.485.0.tgz", - "integrity": "sha512-3XkFgwVU1XOB33dV7t9BKJ/ptdl2iS+0dxE7ecq8aqT2/gsfKmLCae1G17P8WmdD3z0kMDTvnqM2aWgUnSOkmg==", - "optional": true, - "dependencies": { - "@aws-sdk/types": "3.485.0", - "@smithy/property-provider": "^2.0.0", - "@smithy/types": "^2.8.0", - "tslib": "^2.5.0" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-sdk/credential-provider-http": { - "version": "3.485.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-http/-/credential-provider-http-3.485.0.tgz", - "integrity": "sha512-2/2Y3Z7cpKf8vbQ+FzoBPxRyb0hGJZB1YrnH7hptVi5gSVe1NiwV5ZtsDnv4cwUfOBqEu97nMXw5IrRO26S0DA==", - "optional": true, - "dependencies": { - "@aws-sdk/types": "3.485.0", - "@smithy/fetch-http-handler": "^2.3.2", - "@smithy/node-http-handler": "^2.2.2", - "@smithy/property-provider": "^2.0.0", - "@smithy/protocol-http": "^3.0.12", - "@smithy/smithy-client": "^2.2.1", - "@smithy/types": "^2.8.0", - "@smithy/util-stream": "^2.0.24", - "tslib": "^2.5.0" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-sdk/credential-provider-ini": { - "version": "3.485.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-ini/-/credential-provider-ini-3.485.0.tgz", - "integrity": "sha512-cFYF/Bdw7EnT4viSxYpNIv3IBkri/Yb+JpQXl8uDq7bfVJfAN5qZmK07vRkg08xL6TC4F41wshhMSAucGdTwIw==", - "optional": true, - "dependencies": { - "@aws-sdk/credential-provider-env": "3.485.0", - "@aws-sdk/credential-provider-process": "3.485.0", - "@aws-sdk/credential-provider-sso": "3.485.0", - "@aws-sdk/credential-provider-web-identity": "3.485.0", - "@aws-sdk/types": "3.485.0", - "@smithy/credential-provider-imds": "^2.0.0", - "@smithy/property-provider": "^2.0.0", - "@smithy/shared-ini-file-loader": "^2.0.6", - "@smithy/types": "^2.8.0", - "tslib": "^2.5.0" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-sdk/credential-provider-node": { - "version": "3.485.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-node/-/credential-provider-node-3.485.0.tgz", - "integrity": "sha512-2DwzO2azkSzngifKDT61W/DL0tSzewuaFHiLJWdfc8Et3mdAQJ9x3KAj8u7XFpjIcGNqk7FiKjN+zeGUuNiEhA==", - "optional": true, - "dependencies": { - "@aws-sdk/credential-provider-env": "3.485.0", - "@aws-sdk/credential-provider-ini": "3.485.0", - "@aws-sdk/credential-provider-process": "3.485.0", - "@aws-sdk/credential-provider-sso": "3.485.0", - "@aws-sdk/credential-provider-web-identity": "3.485.0", - "@aws-sdk/types": "3.485.0", - "@smithy/credential-provider-imds": "^2.0.0", - "@smithy/property-provider": "^2.0.0", - "@smithy/shared-ini-file-loader": "^2.0.6", - "@smithy/types": "^2.8.0", - "tslib": "^2.5.0" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-sdk/credential-provider-process": { - "version": "3.485.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-process/-/credential-provider-process-3.485.0.tgz", - "integrity": "sha512-X9qS6ZO/rDKYDgWqD1YmSX7sAUUHax9HbXlgGiTTdtfhZvQh1ZmnH6wiPu5WNliafHZFtZT2W07kgrDLPld/Ug==", - "optional": true, - "dependencies": { - "@aws-sdk/types": "3.485.0", - "@smithy/property-provider": "^2.0.0", - "@smithy/shared-ini-file-loader": "^2.0.6", - "@smithy/types": "^2.8.0", - "tslib": "^2.5.0" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-sdk/credential-provider-sso": { - "version": "3.485.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-sso/-/credential-provider-sso-3.485.0.tgz", - "integrity": "sha512-l0oC8GTrWh+LFQQfSmG1Jai1PX7Mhj9arb/CaS1/tmeZE0hgIXW++tvljYs/Dds4LGXUlaWG+P7BrObf6OyIXA==", - "optional": true, - "dependencies": { - "@aws-sdk/client-sso": "3.485.0", - "@aws-sdk/token-providers": "3.485.0", - "@aws-sdk/types": "3.485.0", - "@smithy/property-provider": "^2.0.0", - "@smithy/shared-ini-file-loader": "^2.0.6", - "@smithy/types": "^2.8.0", - "tslib": "^2.5.0" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-sdk/credential-provider-web-identity": { - "version": "3.485.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-web-identity/-/credential-provider-web-identity-3.485.0.tgz", - "integrity": "sha512-WpBFZFE0iXtnibH5POMEKITj/hR0YV5l2n9p8BEvKjdJ63s3Xke1RN20ZdIyKDaRDwj8adnKDgNPEnAKdS4kLw==", - "optional": true, - "dependencies": { - "@aws-sdk/types": "3.485.0", - "@smithy/property-provider": "^2.0.0", - "@smithy/types": "^2.8.0", - "tslib": "^2.5.0" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-sdk/credential-providers": { - "version": "3.485.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-providers/-/credential-providers-3.485.0.tgz", - "integrity": "sha512-SpGEmiVr+C9Dtc5tZFfFYXSNxbl1jShLlyZPWERHBn4QwGvdXcgPB96I0yvUuitBKrM0winHsCWH7CR/z24kmg==", - "optional": true, - "dependencies": { - "@aws-sdk/client-cognito-identity": "3.485.0", - "@aws-sdk/client-sso": "3.485.0", - "@aws-sdk/client-sts": "3.485.0", - "@aws-sdk/credential-provider-cognito-identity": "3.485.0", - "@aws-sdk/credential-provider-env": "3.485.0", - "@aws-sdk/credential-provider-http": "3.485.0", - "@aws-sdk/credential-provider-ini": "3.485.0", - "@aws-sdk/credential-provider-node": "3.485.0", - "@aws-sdk/credential-provider-process": "3.485.0", - "@aws-sdk/credential-provider-sso": "3.485.0", - "@aws-sdk/credential-provider-web-identity": "3.485.0", - "@aws-sdk/types": "3.485.0", - "@smithy/credential-provider-imds": "^2.0.0", - "@smithy/property-provider": "^2.0.0", - "@smithy/types": "^2.8.0", - "tslib": "^2.5.0" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-sdk/lib-storage": { - "version": "3.499.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/lib-storage/-/lib-storage-3.499.0.tgz", - "integrity": "sha512-rL++Re7Oed8uwkMSafpeG6ryB1vzW0dQLi5L3IWPhllWaokrXiEJ1lT1sg8vtyoMaZ4HNGE9jeyxMCRIa52Enw==", - "dependencies": { - "@smithy/abort-controller": "^2.1.1", - "@smithy/middleware-endpoint": "^2.4.1", - "@smithy/smithy-client": "^2.3.1", - "buffer": "5.6.0", - "events": "3.3.0", - "stream-browserify": "3.0.0", - "tslib": "^2.5.0" - }, - "engines": { - "node": ">=14.0.0" - }, - "peerDependencies": { - "@aws-sdk/client-s3": "^3.0.0" - } - }, - "node_modules/@aws-sdk/lib-storage/node_modules/buffer": { - "version": "5.6.0", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.6.0.tgz", - "integrity": "sha512-/gDYp/UtU0eA1ys8bOs9J6a+E/KWIY+DZ+Q2WESNUA0jFRsJOc0SNUO6xJ5SGA1xueg3NL65W6s+NY5l9cunuw==", - "dependencies": { - "base64-js": "^1.0.2", - "ieee754": "^1.1.4" - } - }, - "node_modules/@aws-sdk/middleware-bucket-endpoint": { - "version": "3.496.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-bucket-endpoint/-/middleware-bucket-endpoint-3.496.0.tgz", - "integrity": "sha512-B+ilBMSs3+LJuo2bl2KB8GFdu+8PPVtYEWtwhNkmnaU8iMisgMBp5uuM8sUDvJX7I4iSF0WbgnhguX4cJqfAew==", - "dependencies": { - "@aws-sdk/types": "3.496.0", - "@aws-sdk/util-arn-parser": "3.495.0", - "@smithy/node-config-provider": "^2.2.1", - "@smithy/protocol-http": "^3.1.1", - "@smithy/types": "^2.9.1", - "@smithy/util-config-provider": "^2.2.1", - "tslib": "^2.5.0" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-sdk/middleware-bucket-endpoint/node_modules/@aws-sdk/types": { - "version": "3.496.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.496.0.tgz", - "integrity": "sha512-umkGadK4QuNQaMoDICMm7NKRI/mYSXiyPjcn3d53BhsuArYU/52CebGQKdt4At7SwwsiVJZw9RNBHyN5Mm0HVw==", - "dependencies": { - "@smithy/types": "^2.9.1", - "tslib": "^2.5.0" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-sdk/middleware-expect-continue": { - "version": "3.496.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-expect-continue/-/middleware-expect-continue-3.496.0.tgz", - "integrity": "sha512-+exo5DVc+BeDus2iI6Fz1thefHGDXxUhHZ+4VHQ6HkStMy3Y22HugyEGHSQZmtRL86Hjr7dFbEWFsC47a2ItGA==", - "dependencies": { - "@aws-sdk/types": "3.496.0", - "@smithy/protocol-http": "^3.1.1", - "@smithy/types": "^2.9.1", - "tslib": "^2.5.0" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-sdk/middleware-expect-continue/node_modules/@aws-sdk/types": { - "version": "3.496.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.496.0.tgz", - "integrity": "sha512-umkGadK4QuNQaMoDICMm7NKRI/mYSXiyPjcn3d53BhsuArYU/52CebGQKdt4At7SwwsiVJZw9RNBHyN5Mm0HVw==", - "dependencies": { - "@smithy/types": "^2.9.1", - "tslib": "^2.5.0" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-sdk/middleware-flexible-checksums": { - "version": "3.496.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-flexible-checksums/-/middleware-flexible-checksums-3.496.0.tgz", - "integrity": "sha512-yQIWfjEMvgsAJ7ku224vXDjXPD+f9zfKZFialJva8VUlEr7hQp4CQ0rxV3YThSaixKEDDs5k6kOjWAd2BPGr2A==", - "dependencies": { - "@aws-crypto/crc32": "3.0.0", - "@aws-crypto/crc32c": "3.0.0", - "@aws-sdk/types": "3.496.0", - "@smithy/is-array-buffer": "^2.1.1", - "@smithy/protocol-http": "^3.1.1", - "@smithy/types": "^2.9.1", - "@smithy/util-utf8": "^2.1.1", - "tslib": "^2.5.0" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-sdk/middleware-flexible-checksums/node_modules/@aws-sdk/types": { - "version": "3.496.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.496.0.tgz", - "integrity": "sha512-umkGadK4QuNQaMoDICMm7NKRI/mYSXiyPjcn3d53BhsuArYU/52CebGQKdt4At7SwwsiVJZw9RNBHyN5Mm0HVw==", - "dependencies": { - "@smithy/types": "^2.9.1", - "tslib": "^2.5.0" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-sdk/middleware-host-header": { - "version": "3.485.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-host-header/-/middleware-host-header-3.485.0.tgz", - "integrity": "sha512-1mAUX9dQNGo2RIKseVj7SI/D5abQJQ/Os8hQ0NyVAyyVYF+Yjx5PphKgfhM5yoBwuwZUl6q71XPYEGNx7be6SA==", - "optional": true, - "dependencies": { - "@aws-sdk/types": "3.485.0", - "@smithy/protocol-http": "^3.0.12", - "@smithy/types": "^2.8.0", - "tslib": "^2.5.0" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-sdk/middleware-location-constraint": { - "version": "3.496.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-location-constraint/-/middleware-location-constraint-3.496.0.tgz", - "integrity": "sha512-i4ocJ2Zs86OtPREbB18InFukhqg2qtBxb5gywv79IHDPVmpOYE4m/3v3yGUrkjfF2GTlUL0k5FskNNqw41yfng==", - "dependencies": { - "@aws-sdk/types": "3.496.0", - "@smithy/types": "^2.9.1", - "tslib": "^2.5.0" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-sdk/middleware-location-constraint/node_modules/@aws-sdk/types": { - "version": "3.496.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.496.0.tgz", - "integrity": "sha512-umkGadK4QuNQaMoDICMm7NKRI/mYSXiyPjcn3d53BhsuArYU/52CebGQKdt4At7SwwsiVJZw9RNBHyN5Mm0HVw==", - "dependencies": { - "@smithy/types": "^2.9.1", - "tslib": "^2.5.0" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-sdk/middleware-logger": { - "version": "3.485.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-logger/-/middleware-logger-3.485.0.tgz", - "integrity": "sha512-O8IgJ0LHi5wTs5GlpI7nqmmSSagkVdd1shpGgQWY2h0kMSCII8CJZHBG97dlFFpGTvx5EDlhPNek7rl/6F4dRw==", - "optional": true, - "dependencies": { - "@aws-sdk/types": "3.485.0", - "@smithy/types": "^2.8.0", - "tslib": "^2.5.0" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-sdk/middleware-recursion-detection": { - "version": "3.485.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-recursion-detection/-/middleware-recursion-detection-3.485.0.tgz", - "integrity": "sha512-ZeVNATGNFcqkWDut3luVszROTUzkU5u+rJpB/xmeMoenlDAjPRiHt/ca3WkI5wAnIJ1VSNGpD2sOFLMCH+EWag==", - "optional": true, - "dependencies": { - "@aws-sdk/types": "3.485.0", - "@smithy/protocol-http": "^3.0.12", - "@smithy/types": "^2.8.0", - "tslib": "^2.5.0" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-sdk/middleware-sdk-s3": { - "version": "3.499.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-sdk-s3/-/middleware-sdk-s3-3.499.0.tgz", - "integrity": "sha512-thTb47U1hYHk5ei+yO0D0aehbgQXeAcgvyyxOID9/HDuRfWuTvKdclWh/goIeDfvSS87VBukEAjnCa5JYBwzug==", - "dependencies": { - "@aws-sdk/types": "3.496.0", - "@aws-sdk/util-arn-parser": "3.495.0", - "@smithy/node-config-provider": "^2.2.1", - "@smithy/protocol-http": "^3.1.1", - "@smithy/signature-v4": "^2.1.1", - "@smithy/smithy-client": "^2.3.1", - "@smithy/types": "^2.9.1", - "@smithy/util-config-provider": "^2.2.1", - "tslib": "^2.5.0" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-sdk/middleware-sdk-s3/node_modules/@aws-sdk/types": { - "version": "3.496.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.496.0.tgz", - "integrity": "sha512-umkGadK4QuNQaMoDICMm7NKRI/mYSXiyPjcn3d53BhsuArYU/52CebGQKdt4At7SwwsiVJZw9RNBHyN5Mm0HVw==", - "dependencies": { - "@smithy/types": "^2.9.1", - "tslib": "^2.5.0" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-sdk/middleware-signing": { - "version": "3.485.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-signing/-/middleware-signing-3.485.0.tgz", - "integrity": "sha512-41xzT2p1sOibhsLkdE5rwPJkNbBtKD8Gp36/ySfu0KE415wfXKacElSVxAaBw39/j7iSWDYqqybeEYbAzk+3GQ==", - "optional": true, - "dependencies": { - "@aws-sdk/types": "3.485.0", - "@smithy/property-provider": "^2.0.0", - "@smithy/protocol-http": "^3.0.12", - "@smithy/signature-v4": "^2.0.0", - "@smithy/types": "^2.8.0", - "@smithy/util-middleware": "^2.0.9", - "tslib": "^2.5.0" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-sdk/middleware-ssec": { - "version": "3.498.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-ssec/-/middleware-ssec-3.498.0.tgz", - "integrity": "sha512-sWujXgzeTqMZzj/pRYEnnEbSzhBosqw9DXHOY1Mg2igI9NEfGlB7lPARp6aKmCaYlP3Bcj2X86vKCqF53mbyig==", - "dependencies": { - "@aws-sdk/types": "3.496.0", - "@smithy/types": "^2.9.1", - "tslib": "^2.5.0" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-sdk/middleware-ssec/node_modules/@aws-sdk/types": { - "version": "3.496.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.496.0.tgz", - "integrity": "sha512-umkGadK4QuNQaMoDICMm7NKRI/mYSXiyPjcn3d53BhsuArYU/52CebGQKdt4At7SwwsiVJZw9RNBHyN5Mm0HVw==", - "dependencies": { - "@smithy/types": "^2.9.1", - "tslib": "^2.5.0" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-sdk/middleware-user-agent": { - "version": "3.485.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-user-agent/-/middleware-user-agent-3.485.0.tgz", - "integrity": "sha512-CddCVOn+OPQ0CcchketIg+WF6v+MDLAf3GOYTR2htUxxIm7HABuRd6R3kvQ5Jny9CV8gMt22G1UZITsFexSJlQ==", - "optional": true, - "dependencies": { - "@aws-sdk/types": "3.485.0", - "@aws-sdk/util-endpoints": "3.485.0", - "@smithy/protocol-http": "^3.0.12", - "@smithy/types": "^2.8.0", - "tslib": "^2.5.0" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-sdk/region-config-resolver": { - "version": "3.485.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/region-config-resolver/-/region-config-resolver-3.485.0.tgz", - "integrity": "sha512-2FB2EQ0sIE+YgFqGtkE1lDIMIL6nYe6MkOHBwBM7bommadKIrbbr2L22bPZGs3ReTsxiJabjzxbuCAVhrpHmhg==", - "optional": true, - "dependencies": { - "@smithy/node-config-provider": "^2.1.9", - "@smithy/types": "^2.8.0", - "@smithy/util-config-provider": "^2.1.0", - "@smithy/util-middleware": "^2.0.9", - "tslib": "^2.5.0" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-sdk/signature-v4-multi-region": { - "version": "3.499.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/signature-v4-multi-region/-/signature-v4-multi-region-3.499.0.tgz", - "integrity": "sha512-8HSFnZErRm7lAfk+Epxrf4QNdQEamg1CnbLybtKQQEjmvxLuXYvj16KlpYEZIwEENOMEvnCqMc7syTPkmjVhJA==", - "dependencies": { - "@aws-sdk/middleware-sdk-s3": "3.499.0", - "@aws-sdk/types": "3.496.0", - "@smithy/protocol-http": "^3.1.1", - "@smithy/signature-v4": "^2.1.1", - "@smithy/types": "^2.9.1", - "tslib": "^2.5.0" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-sdk/signature-v4-multi-region/node_modules/@aws-sdk/types": { - "version": "3.496.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.496.0.tgz", - "integrity": "sha512-umkGadK4QuNQaMoDICMm7NKRI/mYSXiyPjcn3d53BhsuArYU/52CebGQKdt4At7SwwsiVJZw9RNBHyN5Mm0HVw==", - "dependencies": { - "@smithy/types": "^2.9.1", - "tslib": "^2.5.0" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-sdk/token-providers": { - "version": "3.485.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/token-providers/-/token-providers-3.485.0.tgz", - "integrity": "sha512-kOXA1WKIVIFNRqHL8ynVZ3hCKLsgnEmGr2iDR6agDNw5fYIlCO/6N2xR6QdGcLTvUUbwOlz4OvKLUQnWMKAnnA==", - "optional": true, - "dependencies": { - "@aws-crypto/sha256-browser": "3.0.0", - "@aws-crypto/sha256-js": "3.0.0", - "@aws-sdk/middleware-host-header": "3.485.0", - "@aws-sdk/middleware-logger": "3.485.0", - "@aws-sdk/middleware-recursion-detection": "3.485.0", - "@aws-sdk/middleware-user-agent": "3.485.0", - "@aws-sdk/region-config-resolver": "3.485.0", - "@aws-sdk/types": "3.485.0", - "@aws-sdk/util-endpoints": "3.485.0", - "@aws-sdk/util-user-agent-browser": "3.485.0", - "@aws-sdk/util-user-agent-node": "3.485.0", - "@smithy/config-resolver": "^2.0.23", - "@smithy/fetch-http-handler": "^2.3.2", - "@smithy/hash-node": "^2.0.18", - "@smithy/invalid-dependency": "^2.0.16", - "@smithy/middleware-content-length": "^2.0.18", - "@smithy/middleware-endpoint": "^2.3.0", - "@smithy/middleware-retry": "^2.0.26", - "@smithy/middleware-serde": "^2.0.16", - "@smithy/middleware-stack": "^2.0.10", - "@smithy/node-config-provider": "^2.1.9", - "@smithy/node-http-handler": "^2.2.2", - "@smithy/property-provider": "^2.0.0", - "@smithy/protocol-http": "^3.0.12", - "@smithy/shared-ini-file-loader": "^2.0.6", - "@smithy/smithy-client": "^2.2.1", - "@smithy/types": "^2.8.0", - "@smithy/url-parser": "^2.0.16", - "@smithy/util-base64": "^2.0.1", - "@smithy/util-body-length-browser": "^2.0.1", - "@smithy/util-body-length-node": "^2.1.0", - "@smithy/util-defaults-mode-browser": "^2.0.24", - "@smithy/util-defaults-mode-node": "^2.0.32", - "@smithy/util-endpoints": "^1.0.8", - "@smithy/util-retry": "^2.0.9", - "@smithy/util-utf8": "^2.0.2", - "tslib": "^2.5.0" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-sdk/types": { - "version": "3.485.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.485.0.tgz", - "integrity": "sha512-+QW32YQdvZRDOwrAQPo/qCyXoSjgXB6RwJwCwkd8ebJXRXw6tmGKIHaZqYHt/LtBymvnaBgBBADNa4+qFvlOFw==", - "dependencies": { - "@smithy/types": "^2.8.0", - "tslib": "^2.5.0" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-sdk/util-arn-parser": { - "version": "3.495.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-arn-parser/-/util-arn-parser-3.495.0.tgz", - "integrity": "sha512-hwdA3XAippSEUxs7jpznwD63YYFR+LtQvlEcebPTgWR9oQgG9TfS+39PUfbnEeje1ICuOrN3lrFqFbmP9uzbMg==", - "dependencies": { - "tslib": "^2.5.0" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-sdk/util-endpoints": { - "version": "3.485.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-endpoints/-/util-endpoints-3.485.0.tgz", - "integrity": "sha512-dTd642F7nJisApF8YjniqQ6U59CP/DCtar11fXf1nG9YNBCBsNNVw5ZfZb5nSNzaIdy27mQioWTCV18JEj1mxg==", - "optional": true, - "dependencies": { - "@aws-sdk/types": "3.485.0", - "@smithy/util-endpoints": "^1.0.8", - "tslib": "^2.5.0" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-sdk/util-locate-window": { - "version": "3.465.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-locate-window/-/util-locate-window-3.465.0.tgz", - "integrity": "sha512-f+QNcWGswredzC1ExNAB/QzODlxwaTdXkNT5cvke2RLX8SFU5pYk6h4uCtWC0vWPELzOfMfloBrJefBzlarhsw==", - "dependencies": { - "tslib": "^2.5.0" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-sdk/util-user-agent-browser": { - "version": "3.485.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-browser/-/util-user-agent-browser-3.485.0.tgz", - "integrity": "sha512-QliWbjg0uOhGTcWgWTKPMY0SBi07g253DjwrCINT1auqDrdQPxa10xozpZExBYjAK2KuhYDNUzni127ae6MHOw==", - "optional": true, - "dependencies": { - "@aws-sdk/types": "3.485.0", - "@smithy/types": "^2.8.0", - "bowser": "^2.11.0", - "tslib": "^2.5.0" - } - }, - "node_modules/@aws-sdk/util-user-agent-node": { - "version": "3.485.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-node/-/util-user-agent-node-3.485.0.tgz", - "integrity": "sha512-QF+aQ9jnDlPUlFBxBRqOylPf86xQuD3aEPpOErR+50qJawVvKa94uiAFdvtI9jv6hnRZmuFsTj2rsyytnbAYBA==", - "optional": true, - "dependencies": { - "@aws-sdk/types": "3.485.0", - "@smithy/node-config-provider": "^2.1.9", - "@smithy/types": "^2.8.0", - "tslib": "^2.5.0" - }, - "engines": { - "node": ">=14.0.0" - }, - "peerDependencies": { - "aws-crt": ">=1.0.0" - }, - "peerDependenciesMeta": { - "aws-crt": { - "optional": true - } - } - }, - "node_modules/@aws-sdk/util-utf8-browser": { - "version": "3.259.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-utf8-browser/-/util-utf8-browser-3.259.0.tgz", - "integrity": "sha512-UvFa/vR+e19XookZF8RzFZBrw2EUkQWxiBW0yYQAhvk3C+QVGl0H3ouca8LDBlBfQKXwmW3huo/59H8rwb1wJw==", - "dependencies": { - "tslib": "^2.3.1" - } - }, - "node_modules/@aws-sdk/xml-builder": { - "version": "3.496.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/xml-builder/-/xml-builder-3.496.0.tgz", - "integrity": "sha512-GvEjh537IIeOw1ZkZuB37sV12u+ipS5Z1dwjEC/HAvhl5ac23ULtTr1/n+U1gLNN+BAKSWjKiQ2ksj8DiUzeyw==", - "dependencies": { - "@smithy/types": "^2.9.1", - "tslib": "^2.5.0" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@colors/colors": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.6.0.tgz", - "integrity": "sha512-Ir+AOibqzrIsL6ajt3Rz3LskB7OiMVHqltZmspbW/TJuTVuyOMirVqAkjfY6JISiLHgyNqicAC8AyHHGzNd/dA==", - "engines": { - "node": ">=0.1.90" - } - }, - "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", - "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", - "dev": true, - "dependencies": { - "@jridgewell/trace-mapping": "0.3.9" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/@dabh/diagnostics": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/@dabh/diagnostics/-/diagnostics-2.0.3.tgz", - "integrity": "sha512-hrlQOIi7hAfzsMqlGSFyVucrx38O+j6wiGOf//H2ecvIEqYN4ADBSS2iLMh5UFyDunCNniUIPk/q3riFv45xRA==", - "dependencies": { - "colorspace": "1.1.x", - "enabled": "2.0.x", - "kuler": "^2.0.0" - } - }, - "node_modules/@discordjs/builders": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/@discordjs/builders/-/builders-1.7.0.tgz", - "integrity": "sha512-GDtbKMkg433cOZur8Dv6c25EHxduNIBsxeHrsRoIM8+AwmEZ8r0tEpckx/sHwTLwQPOF3e2JWloZh9ofCaMfAw==", - "dependencies": { - "@discordjs/formatters": "^0.3.3", - "@discordjs/util": "^1.0.2", - "@sapphire/shapeshift": "^3.9.3", - "discord-api-types": "0.37.61", - "fast-deep-equal": "^3.1.3", - "ts-mixer": "^6.0.3", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.11.0" - } - }, - "node_modules/@discordjs/collection": { - "version": "1.5.3", - "resolved": "https://registry.npmjs.org/@discordjs/collection/-/collection-1.5.3.tgz", - "integrity": "sha512-SVb428OMd3WO1paV3rm6tSjM4wC+Kecaa1EUGX7vc6/fddvw/6lg90z4QtCqm21zvVe92vMMDt9+DkIvjXImQQ==", - "engines": { - "node": ">=16.11.0" - } - }, - "node_modules/@discordjs/formatters": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/@discordjs/formatters/-/formatters-0.3.3.tgz", - "integrity": "sha512-wTcI1Q5cps1eSGhl6+6AzzZkBBlVrBdc9IUhJbijRgVjCNIIIZPgqnUj3ntFODsHrdbGU8BEG9XmDQmgEEYn3w==", - "dependencies": { - "discord-api-types": "0.37.61" - }, - "engines": { - "node": ">=16.11.0" - } - }, - "node_modules/@discordjs/rest": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@discordjs/rest/-/rest-2.2.0.tgz", - "integrity": "sha512-nXm9wT8oqrYFRMEqTXQx9DUTeEtXUDMmnUKIhZn6O2EeDY9VCdwj23XCPq7fkqMPKdF7ldAfeVKyxxFdbZl59A==", - "dependencies": { - "@discordjs/collection": "^2.0.0", - "@discordjs/util": "^1.0.2", - "@sapphire/async-queue": "^1.5.0", - "@sapphire/snowflake": "^3.5.1", - "@vladfrangu/async_event_emitter": "^2.2.2", - "discord-api-types": "0.37.61", - "magic-bytes.js": "^1.5.0", - "tslib": "^2.6.2", - "undici": "5.27.2" - }, - "engines": { - "node": ">=16.11.0" - } - }, - "node_modules/@discordjs/rest/node_modules/@discordjs/collection": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@discordjs/collection/-/collection-2.0.0.tgz", - "integrity": "sha512-YTWIXLrf5FsrLMycpMM9Q6vnZoR/lN2AWX23/Cuo8uOOtS8eHB2dyQaaGnaF8aZPYnttf2bkLMcXn/j6JUOi3w==", - "engines": { - "node": ">=18" - } - }, - "node_modules/@discordjs/util": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@discordjs/util/-/util-1.0.2.tgz", - "integrity": "sha512-IRNbimrmfb75GMNEjyznqM1tkI7HrZOf14njX7tCAAUetyZM1Pr8hX/EK2lxBCOgWDRmigbp24fD1hdMfQK5lw==", - "engines": { - "node": ">=16.11.0" - } - }, - "node_modules/@discordjs/ws": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@discordjs/ws/-/ws-1.0.2.tgz", - "integrity": "sha512-+XI82Rm2hKnFwAySXEep4A7Kfoowt6weO6381jgW+wVdTpMS/56qCvoXyFRY0slcv7c/U8My2PwIB2/wEaAh7Q==", - "dependencies": { - "@discordjs/collection": "^2.0.0", - "@discordjs/rest": "^2.1.0", - "@discordjs/util": "^1.0.2", - "@sapphire/async-queue": "^1.5.0", - "@types/ws": "^8.5.9", - "@vladfrangu/async_event_emitter": "^2.2.2", - "discord-api-types": "0.37.61", - "tslib": "^2.6.2", - "ws": "^8.14.2" - }, - "engines": { - "node": ">=16.11.0" - } - }, - "node_modules/@discordjs/ws/node_modules/@discordjs/collection": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@discordjs/collection/-/collection-2.0.0.tgz", - "integrity": "sha512-YTWIXLrf5FsrLMycpMM9Q6vnZoR/lN2AWX23/Cuo8uOOtS8eHB2dyQaaGnaF8aZPYnttf2bkLMcXn/j6JUOi3w==", - "engines": { - "node": ">=18" - } - }, - "node_modules/@eslint-community/eslint-utils": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", - "integrity": "sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==", - "dev": true, - "dependencies": { - "eslint-visitor-keys": "^3.3.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "peerDependencies": { - "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" - } - }, - "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==", - "dev": true, - "engines": { - "node": "^12.0.0 || ^14.0.0 || >=16.0.0" - } - }, - "node_modules/@eslint/config-array": { - "version": "0.15.1", - "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.15.1.tgz", - "integrity": "sha512-K4gzNq+yymn/EVsXYmf+SBcBro8MTf+aXJZUphM96CdzUEr+ClGDvAbpmaEK+cGVigVXIgs9gNmvHAlrzzY5JQ==", - "dev": true, - "dependencies": { - "@eslint/object-schema": "^2.1.3", - "debug": "^4.3.1", - "minimatch": "^3.0.5" - }, - "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, - "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, - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/@eslint/eslintrc": { - "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, - "dependencies": { - "ajv": "^6.12.4", - "debug": "^4.3.2", - "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" - }, - "engines": { - "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, - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "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, - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/@eslint/js": { - "version": "9.4.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.4.0.tgz", - "integrity": "sha512-fdI7VJjP3Rvc70lC4xkFXHB0fiPeojiL1PxVG6t1ZvXQrarj893PweuBTujxDUFk0Fxj4R7PIIAZ/aiiyZPZcg==", - "dev": true, - "engines": { - "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, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - } - }, - "node_modules/@fastify/busboy": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/@fastify/busboy/-/busboy-2.1.0.tgz", - "integrity": "sha512-+KpH+QxZU7O4675t3mnkQKcZZg56u+K/Ct2K+N2AZYNVK8kyeo/bI18tI8aPm3tvNNRyTWfj6s5tnGNlcbQRsA==", - "engines": { - "node": ">=14" - } - }, - "node_modules/@hokify/agenda": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/@hokify/agenda/-/agenda-6.3.0.tgz", - "integrity": "sha512-fWrKMDe/8QHJXLOdEsMogb6cb213Z82iNsnU7nFrSIMFifEXSkXNTyCZ99FV3KLf+Du1gS/M9/8uTC6FHyWRZQ==", - "dependencies": { - "cron-parser": "^4", - "date.js": "~0.3.3", - "debug": "~4", - "human-interval": "~2", - "luxon": "^3", - "mongodb": "^4" - }, - "engines": { - "node": ">=14.0.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, - "engines": { - "node": ">=12.22" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/nzakas" - } - }, - "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, - "engines": { - "node": ">=18.18" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/nzakas" - } - }, - "node_modules/@jridgewell/resolve-uri": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.1.tgz", - "integrity": "sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA==", - "dev": true, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.4.15", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", - "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==", - "dev": true - }, - "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.9", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", - "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", - "dev": true, - "dependencies": { - "@jridgewell/resolve-uri": "^3.0.3", - "@jridgewell/sourcemap-codec": "^1.4.10" - } - }, - "node_modules/@mongodb-js/saslprep": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/@mongodb-js/saslprep/-/saslprep-1.1.3.tgz", - "integrity": "sha512-SyCxhJfmK6MoLNV5SbDpNdUy9SDv5H7y9/9rl3KpnwgTHWuNNMc87zWqbcIZXNWY+aUjxLGLEcvHoLagG4tWCg==", - "dependencies": { - "sparse-bitfield": "^3.0.3" - } - }, - "node_modules/@nodelib/fs.scandir": { - "version": "2.1.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", - "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", - "dev": true, - "dependencies": { - "@nodelib/fs.stat": "2.0.5", - "run-parallel": "^1.1.9" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@nodelib/fs.stat": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", - "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", - "dev": true, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@nodelib/fs.walk": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", - "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", - "dev": true, - "dependencies": { - "@nodelib/fs.scandir": "2.1.5", - "fastq": "^1.6.0" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@octokit/endpoint": { - "version": "9.0.4", - "resolved": "https://registry.npmjs.org/@octokit/endpoint/-/endpoint-9.0.4.tgz", - "integrity": "sha512-DWPLtr1Kz3tv8L0UvXTDP1fNwM0S+z6EJpRcvH66orY6Eld4XBMCSYsaWp4xIm61jTWxK68BrR7ibO+vSDnZqw==", - "dependencies": { - "@octokit/types": "^12.0.0", - "universal-user-agent": "^6.0.0" - }, - "engines": { - "node": ">= 18" - } - }, - "node_modules/@octokit/openapi-types": { - "version": "19.1.0", - "resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-19.1.0.tgz", - "integrity": "sha512-6G+ywGClliGQwRsjvqVYpklIfa7oRPA0vyhPQG/1Feh+B+wU0vGH1JiJ5T25d3g1JZYBHzR2qefLi9x8Gt+cpw==" - }, - "node_modules/@octokit/request": { - "version": "8.1.6", - "resolved": "https://registry.npmjs.org/@octokit/request/-/request-8.1.6.tgz", - "integrity": "sha512-YhPaGml3ncZC1NfXpP3WZ7iliL1ap6tLkAp6MvbK2fTTPytzVUyUesBBogcdMm86uRYO5rHaM1xIWxigWZ17MQ==", - "dependencies": { - "@octokit/endpoint": "^9.0.0", - "@octokit/request-error": "^5.0.0", - "@octokit/types": "^12.0.0", - "universal-user-agent": "^6.0.0" - }, - "engines": { - "node": ">= 18" - } - }, - "node_modules/@octokit/request-error": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/@octokit/request-error/-/request-error-5.0.1.tgz", - "integrity": "sha512-X7pnyTMV7MgtGmiXBwmO6M5kIPrntOXdyKZLigNfQWSEQzVxR4a4vo49vJjTWX70mPndj8KhfT4Dx+2Ng3vnBQ==", - "dependencies": { - "@octokit/types": "^12.0.0", - "deprecation": "^2.0.0", - "once": "^1.4.0" - }, - "engines": { - "node": ">= 18" - } - }, - "node_modules/@octokit/types": { - "version": "12.4.0", - "resolved": "https://registry.npmjs.org/@octokit/types/-/types-12.4.0.tgz", - "integrity": "sha512-FLWs/AvZllw/AGVs+nJ+ELCDZZJk+kY0zMen118xhL2zD0s1etIUHm1odgjP7epxYU1ln7SZxEUWYop5bhsdgQ==", - "dependencies": { - "@octokit/openapi-types": "^19.1.0" - } - }, - "node_modules/@pkgr/core": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/@pkgr/core/-/core-0.1.1.tgz", - "integrity": "sha512-cq8o4cWH0ibXh9VGi5P20Tu9XF/0fFXl9EUinr9QfTM7a7p0oTA4iJRCQWppXR1Pg8dSM0UCItCkPwsk9qWWYA==", - "dev": true, - "engines": { - "node": "^12.20.0 || ^14.18.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/unts" - } - }, - "node_modules/@sapphire/async-queue": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/@sapphire/async-queue/-/async-queue-1.5.1.tgz", - "integrity": "sha512-1RdpsmDQR/aWfp8oJzPtn4dNQrbpqSL5PIA0uAB/XwerPXUf994Ug1au1e7uGcD7ei8/F63UDjr5GWps1g/HxQ==", - "engines": { - "node": ">=v14.0.0", - "npm": ">=7.0.0" - } - }, - "node_modules/@sapphire/shapeshift": { - "version": "3.9.5", - "resolved": "https://registry.npmjs.org/@sapphire/shapeshift/-/shapeshift-3.9.5.tgz", - "integrity": "sha512-AGdHe+51gF7D3W8hBfuSFLBocURDCXVQczScTHXDS3RpNjNgrktIx/amlz5y8nHhm8SAdFt/X8EF8ZSfjJ0tnA==", - "dependencies": { - "fast-deep-equal": "^3.1.3", - "lodash": "^4.17.21" - }, - "engines": { - "node": ">=v18" - } - }, - "node_modules/@sapphire/snowflake": { - "version": "3.5.1", - "resolved": "https://registry.npmjs.org/@sapphire/snowflake/-/snowflake-3.5.1.tgz", - "integrity": "sha512-BxcYGzgEsdlG0dKAyOm0ehLGm2CafIrfQTZGWgkfKYbj+pNNsorZ7EotuZukc2MT70E0UbppVbtpBrqpzVzjNA==", - "engines": { - "node": ">=v14.0.0", - "npm": ">=7.0.0" - } - }, - "node_modules/@smithy/abort-controller": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/@smithy/abort-controller/-/abort-controller-2.1.1.tgz", - "integrity": "sha512-1+qdrUqLhaALYL0iOcN43EP6yAXXQ2wWZ6taf4S2pNGowmOc5gx+iMQv+E42JizNJjB0+gEadOXeV1Bf7JWL1Q==", - "dependencies": { - "@smithy/types": "^2.9.1", - "tslib": "^2.5.0" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@smithy/chunked-blob-reader": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/@smithy/chunked-blob-reader/-/chunked-blob-reader-2.1.1.tgz", - "integrity": "sha512-NjNFCKxC4jVvn+lUr3Yo4/PmUJj3tbyqH6GNHueyTGS5Q27vlEJ1MkNhUDV8QGxJI7Bodnc2pD18lU2zRfhHlQ==", - "dependencies": { - "tslib": "^2.5.0" - } - }, - "node_modules/@smithy/chunked-blob-reader-native": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/@smithy/chunked-blob-reader-native/-/chunked-blob-reader-native-2.1.1.tgz", - "integrity": "sha512-zNW+43dltfNMUrBEYLMWgI8lQr0uhtTcUyxkgC9EP4j17WREzgSFMPUFVrVV6Rc2+QtWERYjb4tzZnQGa7R9fQ==", - "dependencies": { - "@smithy/util-base64": "^2.1.1", - "tslib": "^2.5.0" - } - }, - "node_modules/@smithy/config-resolver": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/@smithy/config-resolver/-/config-resolver-2.1.1.tgz", - "integrity": "sha512-lxfLDpZm+AWAHPFZps5JfDoO9Ux1764fOgvRUBpHIO8HWHcSN1dkgsago1qLRVgm1BZ8RCm8cgv99QvtaOWIhw==", - "dependencies": { - "@smithy/node-config-provider": "^2.2.1", - "@smithy/types": "^2.9.1", - "@smithy/util-config-provider": "^2.2.1", - "@smithy/util-middleware": "^2.1.1", - "tslib": "^2.5.0" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@smithy/core": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/@smithy/core/-/core-1.3.1.tgz", - "integrity": "sha512-tf+NIu9FkOh312b6M9G4D68is4Xr7qptzaZGZUREELF8ysE1yLKphqt7nsomjKZVwW7WE5pDDex9idowNGRQ/Q==", - "dependencies": { - "@smithy/middleware-endpoint": "^2.4.1", - "@smithy/middleware-retry": "^2.1.1", - "@smithy/middleware-serde": "^2.1.1", - "@smithy/protocol-http": "^3.1.1", - "@smithy/smithy-client": "^2.3.1", - "@smithy/types": "^2.9.1", - "@smithy/util-middleware": "^2.1.1", - "tslib": "^2.5.0" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@smithy/credential-provider-imds": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/@smithy/credential-provider-imds/-/credential-provider-imds-2.2.1.tgz", - "integrity": "sha512-7XHjZUxmZYnONheVQL7j5zvZXga+EWNgwEAP6OPZTi7l8J4JTeNh9aIOfE5fKHZ/ee2IeNOh54ZrSna+Vc6TFA==", - "dependencies": { - "@smithy/node-config-provider": "^2.2.1", - "@smithy/property-provider": "^2.1.1", - "@smithy/types": "^2.9.1", - "@smithy/url-parser": "^2.1.1", - "tslib": "^2.5.0" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@smithy/eventstream-codec": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/@smithy/eventstream-codec/-/eventstream-codec-2.1.1.tgz", - "integrity": "sha512-E8KYBxBIuU4c+zrpR22VsVrOPoEDzk35bQR3E+xm4k6Pa6JqzkDOdMyf9Atac5GPNKHJBdVaQ4JtjdWX2rl/nw==", - "dependencies": { - "@aws-crypto/crc32": "3.0.0", - "@smithy/types": "^2.9.1", - "@smithy/util-hex-encoding": "^2.1.1", - "tslib": "^2.5.0" - } - }, - "node_modules/@smithy/eventstream-serde-browser": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/@smithy/eventstream-serde-browser/-/eventstream-serde-browser-2.1.1.tgz", - "integrity": "sha512-JvEdCmGlZUay5VtlT8/kdR6FlvqTDUiJecMjXsBb0+k1H/qc9ME5n2XKPo8q/MZwEIA1GmGgYMokKGjVvMiDow==", - "dependencies": { - "@smithy/eventstream-serde-universal": "^2.1.1", - "@smithy/types": "^2.9.1", - "tslib": "^2.5.0" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@smithy/eventstream-serde-config-resolver": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/@smithy/eventstream-serde-config-resolver/-/eventstream-serde-config-resolver-2.1.1.tgz", - "integrity": "sha512-EqNqXYp3+dk//NmW3NAgQr9bEQ7fsu/CcxQmTiq07JlaIcne/CBWpMZETyXm9w5LXkhduBsdXdlMscfDUDn2fA==", - "dependencies": { - "@smithy/types": "^2.9.1", - "tslib": "^2.5.0" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@smithy/eventstream-serde-node": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/@smithy/eventstream-serde-node/-/eventstream-serde-node-2.1.1.tgz", - "integrity": "sha512-LF882q/aFidFNDX7uROAGxq3H0B7rjyPkV6QDn6/KDQ+CG7AFkRccjxRf1xqajq/Pe4bMGGr+VKAaoF6lELIQw==", - "dependencies": { - "@smithy/eventstream-serde-universal": "^2.1.1", - "@smithy/types": "^2.9.1", - "tslib": "^2.5.0" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@smithy/eventstream-serde-universal": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/@smithy/eventstream-serde-universal/-/eventstream-serde-universal-2.1.1.tgz", - "integrity": "sha512-LR0mMT+XIYTxk4k2fIxEA1BPtW3685QlqufUEUAX1AJcfFfxNDKEvuCRZbO8ntJb10DrIFVJR9vb0MhDCi0sAQ==", - "dependencies": { - "@smithy/eventstream-codec": "^2.1.1", - "@smithy/types": "^2.9.1", - "tslib": "^2.5.0" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@smithy/fetch-http-handler": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/@smithy/fetch-http-handler/-/fetch-http-handler-2.4.1.tgz", - "integrity": "sha512-VYGLinPsFqH68lxfRhjQaSkjXM7JysUOJDTNjHBuN/ykyRb2f1gyavN9+VhhPTWCy32L4yZ2fdhpCs/nStEicg==", - "dependencies": { - "@smithy/protocol-http": "^3.1.1", - "@smithy/querystring-builder": "^2.1.1", - "@smithy/types": "^2.9.1", - "@smithy/util-base64": "^2.1.1", - "tslib": "^2.5.0" - } - }, - "node_modules/@smithy/hash-blob-browser": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/@smithy/hash-blob-browser/-/hash-blob-browser-2.1.1.tgz", - "integrity": "sha512-jizu1+2PAUjiGIfRtlPEU8Yo6zn+d78ti/ZHDesdf1SUn2BuZW433JlPoCOLH3dBoEEvTgLvQ8tUGSoTTALA+A==", - "dependencies": { - "@smithy/chunked-blob-reader": "^2.1.1", - "@smithy/chunked-blob-reader-native": "^2.1.1", - "@smithy/types": "^2.9.1", - "tslib": "^2.5.0" - } - }, - "node_modules/@smithy/hash-node": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/@smithy/hash-node/-/hash-node-2.1.1.tgz", - "integrity": "sha512-Qhoq0N8f2OtCnvUpCf+g1vSyhYQrZjhSwvJ9qvR8BUGOtTXiyv2x1OD2e6jVGmlpC4E4ax1USHoyGfV9JFsACg==", - "dependencies": { - "@smithy/types": "^2.9.1", - "@smithy/util-buffer-from": "^2.1.1", - "@smithy/util-utf8": "^2.1.1", - "tslib": "^2.5.0" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@smithy/hash-stream-node": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/@smithy/hash-stream-node/-/hash-stream-node-2.1.1.tgz", - "integrity": "sha512-VgDaKcfCy0iHcmtAZgZ3Yw9g37Gkn2JsQiMtFQXUh8Wmo3GfNgDwLOtdhJ272pOT7DStzpe9cNr+eV5Au8KfQA==", - "dependencies": { - "@smithy/types": "^2.9.1", - "@smithy/util-utf8": "^2.1.1", - "tslib": "^2.5.0" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@smithy/invalid-dependency": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/@smithy/invalid-dependency/-/invalid-dependency-2.1.1.tgz", - "integrity": "sha512-7WTgnKw+VPg8fxu2v9AlNOQ5yaz6RA54zOVB4f6vQuR0xFKd+RzlCpt0WidYTsye7F+FYDIaS/RnJW4pxjNInw==", - "dependencies": { - "@smithy/types": "^2.9.1", - "tslib": "^2.5.0" - } - }, - "node_modules/@smithy/is-array-buffer": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/@smithy/is-array-buffer/-/is-array-buffer-2.1.1.tgz", - "integrity": "sha512-xozSQrcUinPpNPNPds4S7z/FakDTh1MZWtRP/2vQtYB/u3HYrX2UXuZs+VhaKBd6Vc7g2XPr2ZtwGBNDN6fNKQ==", - "dependencies": { - "tslib": "^2.5.0" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@smithy/md5-js": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/@smithy/md5-js/-/md5-js-2.1.1.tgz", - "integrity": "sha512-L3MbIYBIdLlT+MWTYrdVSv/dow1+6iZ1Ad7xS0OHxTTs17d753ZcpOV4Ro7M7tRAVWML/sg2IAp/zzCb6aAttg==", - "dependencies": { - "@smithy/types": "^2.9.1", - "@smithy/util-utf8": "^2.1.1", - "tslib": "^2.5.0" - } - }, - "node_modules/@smithy/middleware-content-length": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/@smithy/middleware-content-length/-/middleware-content-length-2.1.1.tgz", - "integrity": "sha512-rSr9ezUl9qMgiJR0UVtVOGEZElMdGFyl8FzWEF5iEKTlcWxGr2wTqGfDwtH3LAB7h+FPkxqv4ZU4cpuCN9Kf/g==", - "dependencies": { - "@smithy/protocol-http": "^3.1.1", - "@smithy/types": "^2.9.1", - "tslib": "^2.5.0" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@smithy/middleware-endpoint": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/@smithy/middleware-endpoint/-/middleware-endpoint-2.4.1.tgz", - "integrity": "sha512-XPZTb1E2Oav60Ven3n2PFx+rX9EDsU/jSTA8VDamt7FXks67ekjPY/XrmmPDQaFJOTUHJNKjd8+kZxVO5Ael4Q==", - "dependencies": { - "@smithy/middleware-serde": "^2.1.1", - "@smithy/node-config-provider": "^2.2.1", - "@smithy/shared-ini-file-loader": "^2.3.1", - "@smithy/types": "^2.9.1", - "@smithy/url-parser": "^2.1.1", - "@smithy/util-middleware": "^2.1.1", - "tslib": "^2.5.0" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@smithy/middleware-retry": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/@smithy/middleware-retry/-/middleware-retry-2.1.1.tgz", - "integrity": "sha512-eMIHOBTXro6JZ+WWzZWd/8fS8ht5nS5KDQjzhNMHNRcG5FkNTqcKpYhw7TETMYzbLfhO5FYghHy1vqDWM4FLDA==", - "dependencies": { - "@smithy/node-config-provider": "^2.2.1", - "@smithy/protocol-http": "^3.1.1", - "@smithy/service-error-classification": "^2.1.1", - "@smithy/smithy-client": "^2.3.1", - "@smithy/types": "^2.9.1", - "@smithy/util-middleware": "^2.1.1", - "@smithy/util-retry": "^2.1.1", - "tslib": "^2.5.0", - "uuid": "^8.3.2" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@smithy/middleware-serde": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/@smithy/middleware-serde/-/middleware-serde-2.1.1.tgz", - "integrity": "sha512-D8Gq0aQBeE1pxf3cjWVkRr2W54t+cdM2zx78tNrVhqrDykRA7asq8yVJij1u5NDtKzKqzBSPYh7iW0svUKg76g==", - "dependencies": { - "@smithy/types": "^2.9.1", - "tslib": "^2.5.0" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@smithy/middleware-stack": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/@smithy/middleware-stack/-/middleware-stack-2.1.1.tgz", - "integrity": "sha512-KPJhRlhsl8CjgGXK/DoDcrFGfAqoqvuwlbxy+uOO4g2Azn1dhH+GVfC3RAp+6PoL5PWPb+vt6Z23FP+Mr6qeCw==", - "dependencies": { - "@smithy/types": "^2.9.1", - "tslib": "^2.5.0" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@smithy/node-config-provider": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/@smithy/node-config-provider/-/node-config-provider-2.2.1.tgz", - "integrity": "sha512-epzK3x1xNxA9oJgHQ5nz+2j6DsJKdHfieb+YgJ7ATWxzNcB7Hc+Uya2TUck5MicOPhDV8HZImND7ZOecVr+OWg==", - "dependencies": { - "@smithy/property-provider": "^2.1.1", - "@smithy/shared-ini-file-loader": "^2.3.1", - "@smithy/types": "^2.9.1", - "tslib": "^2.5.0" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@smithy/node-http-handler": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/@smithy/node-http-handler/-/node-http-handler-2.3.1.tgz", - "integrity": "sha512-gLA8qK2nL9J0Rk/WEZSvgin4AppvuCYRYg61dcUo/uKxvMZsMInL5I5ZdJTogOvdfVug3N2dgI5ffcUfS4S9PA==", - "dependencies": { - "@smithy/abort-controller": "^2.1.1", - "@smithy/protocol-http": "^3.1.1", - "@smithy/querystring-builder": "^2.1.1", - "@smithy/types": "^2.9.1", - "tslib": "^2.5.0" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@smithy/property-provider": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/@smithy/property-provider/-/property-provider-2.1.1.tgz", - "integrity": "sha512-FX7JhhD/o5HwSwg6GLK9zxrMUrGnb3PzNBrcthqHKBc3dH0UfgEAU24xnJ8F0uow5mj17UeBEOI6o3CF2k7Mhw==", - "dependencies": { - "@smithy/types": "^2.9.1", - "tslib": "^2.5.0" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@smithy/protocol-http": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/@smithy/protocol-http/-/protocol-http-3.1.1.tgz", - "integrity": "sha512-6ZRTSsaXuSL9++qEwH851hJjUA0OgXdQFCs+VDw4tGH256jQ3TjYY/i34N4vd24RV3nrjNsgd1yhb57uMoKbzQ==", - "dependencies": { - "@smithy/types": "^2.9.1", - "tslib": "^2.5.0" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@smithy/querystring-builder": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/@smithy/querystring-builder/-/querystring-builder-2.1.1.tgz", - "integrity": "sha512-C/ko/CeEa8jdYE4gt6nHO5XDrlSJ3vdCG0ZAc6nD5ZIE7LBp0jCx4qoqp7eoutBu7VrGMXERSRoPqwi1WjCPbg==", - "dependencies": { - "@smithy/types": "^2.9.1", - "@smithy/util-uri-escape": "^2.1.1", - "tslib": "^2.5.0" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@smithy/querystring-parser": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/@smithy/querystring-parser/-/querystring-parser-2.1.1.tgz", - "integrity": "sha512-H4+6jKGVhG1W4CIxfBaSsbm98lOO88tpDWmZLgkJpt8Zkk/+uG0FmmqMuCAc3HNM2ZDV+JbErxr0l5BcuIf/XQ==", - "dependencies": { - "@smithy/types": "^2.9.1", - "tslib": "^2.5.0" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@smithy/service-error-classification": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/@smithy/service-error-classification/-/service-error-classification-2.1.1.tgz", - "integrity": "sha512-txEdZxPUgM1PwGvDvHzqhXisrc5LlRWYCf2yyHfvITWioAKat7srQvpjMAvgzf0t6t7j8yHrryXU9xt7RZqFpw==", - "dependencies": { - "@smithy/types": "^2.9.1" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@smithy/shared-ini-file-loader": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/@smithy/shared-ini-file-loader/-/shared-ini-file-loader-2.3.1.tgz", - "integrity": "sha512-2E2kh24igmIznHLB6H05Na4OgIEilRu0oQpYXo3LCNRrawHAcfDKq9004zJs+sAMt2X5AbY87CUCJ7IpqpSgdw==", - "dependencies": { - "@smithy/types": "^2.9.1", - "tslib": "^2.5.0" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@smithy/signature-v4": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/@smithy/signature-v4/-/signature-v4-2.1.1.tgz", - "integrity": "sha512-Hb7xub0NHuvvQD3YwDSdanBmYukoEkhqBjqoxo+bSdC0ryV9cTfgmNjuAQhTPYB6yeU7hTR+sPRiFMlxqv6kmg==", - "dependencies": { - "@smithy/eventstream-codec": "^2.1.1", - "@smithy/is-array-buffer": "^2.1.1", - "@smithy/types": "^2.9.1", - "@smithy/util-hex-encoding": "^2.1.1", - "@smithy/util-middleware": "^2.1.1", - "@smithy/util-uri-escape": "^2.1.1", - "@smithy/util-utf8": "^2.1.1", - "tslib": "^2.5.0" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@smithy/smithy-client": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/@smithy/smithy-client/-/smithy-client-2.3.1.tgz", - "integrity": "sha512-YsTdU8xVD64r2pLEwmltrNvZV6XIAC50LN6ivDopdt+YiF/jGH6PY9zUOu0CXD/d8GMB8gbhnpPsdrjAXHS9QA==", - "dependencies": { - "@smithy/middleware-endpoint": "^2.4.1", - "@smithy/middleware-stack": "^2.1.1", - "@smithy/protocol-http": "^3.1.1", - "@smithy/types": "^2.9.1", - "@smithy/util-stream": "^2.1.1", - "tslib": "^2.5.0" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@smithy/types": { - "version": "2.9.1", - "resolved": "https://registry.npmjs.org/@smithy/types/-/types-2.9.1.tgz", - "integrity": "sha512-vjXlKNXyprDYDuJ7UW5iobdmyDm6g8dDG+BFUncAg/3XJaN45Gy5RWWWUVgrzIK7S4R1KWgIX5LeJcfvSI24bw==", - "dependencies": { - "tslib": "^2.5.0" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@smithy/url-parser": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/@smithy/url-parser/-/url-parser-2.1.1.tgz", - "integrity": "sha512-qC9Bv8f/vvFIEkHsiNrUKYNl8uKQnn4BdhXl7VzQRP774AwIjiSMMwkbT+L7Fk8W8rzYVifzJNYxv1HwvfBo3Q==", - "dependencies": { - "@smithy/querystring-parser": "^2.1.1", - "@smithy/types": "^2.9.1", - "tslib": "^2.5.0" - } - }, - "node_modules/@smithy/util-base64": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/@smithy/util-base64/-/util-base64-2.1.1.tgz", - "integrity": "sha512-UfHVpY7qfF/MrgndI5PexSKVTxSZIdz9InghTFa49QOvuu9I52zLPLUHXvHpNuMb1iD2vmc6R+zbv/bdMipR/g==", - "dependencies": { - "@smithy/util-buffer-from": "^2.1.1", - "tslib": "^2.5.0" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@smithy/util-body-length-browser": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/@smithy/util-body-length-browser/-/util-body-length-browser-2.1.1.tgz", - "integrity": "sha512-ekOGBLvs1VS2d1zM2ER4JEeBWAvIOUKeaFch29UjjJsxmZ/f0L3K3x0dEETgh3Q9bkZNHgT+rkdl/J/VUqSRag==", - "dependencies": { - "tslib": "^2.5.0" - } - }, - "node_modules/@smithy/util-body-length-node": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/@smithy/util-body-length-node/-/util-body-length-node-2.2.1.tgz", - "integrity": "sha512-/ggJG+ta3IDtpNVq4ktmEUtOkH1LW64RHB5B0hcr5ZaWBmo96UX2cIOVbjCqqDickTXqBWZ4ZO0APuaPrD7Abg==", - "dependencies": { - "tslib": "^2.5.0" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@smithy/util-buffer-from": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/@smithy/util-buffer-from/-/util-buffer-from-2.1.1.tgz", - "integrity": "sha512-clhNjbyfqIv9Md2Mg6FffGVrJxw7bgK7s3Iax36xnfVj6cg0fUG7I4RH0XgXJF8bxi+saY5HR21g2UPKSxVCXg==", - "dependencies": { - "@smithy/is-array-buffer": "^2.1.1", - "tslib": "^2.5.0" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@smithy/util-config-provider": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/@smithy/util-config-provider/-/util-config-provider-2.2.1.tgz", - "integrity": "sha512-50VL/tx9oYYcjJn/qKqNy7sCtpD0+s8XEBamIFo4mFFTclKMNp+rsnymD796uybjiIquB7VCB/DeafduL0y2kw==", - "dependencies": { - "tslib": "^2.5.0" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@smithy/util-defaults-mode-browser": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-browser/-/util-defaults-mode-browser-2.1.1.tgz", - "integrity": "sha512-lqLz/9aWRO6mosnXkArtRuQqqZBhNpgI65YDpww4rVQBuUT7qzKbDLG5AmnQTCiU4rOquaZO/Kt0J7q9Uic7MA==", - "dependencies": { - "@smithy/property-provider": "^2.1.1", - "@smithy/smithy-client": "^2.3.1", - "@smithy/types": "^2.9.1", - "bowser": "^2.11.0", - "tslib": "^2.5.0" - }, - "engines": { - "node": ">= 10.0.0" - } - }, - "node_modules/@smithy/util-defaults-mode-node": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-node/-/util-defaults-mode-node-2.1.1.tgz", - "integrity": "sha512-tYVrc+w+jSBfBd267KDnvSGOh4NMz+wVH7v4CClDbkdPfnjvImBZsOURncT5jsFwR9KCuDyPoSZq4Pa6+eCUrA==", - "dependencies": { - "@smithy/config-resolver": "^2.1.1", - "@smithy/credential-provider-imds": "^2.2.1", - "@smithy/node-config-provider": "^2.2.1", - "@smithy/property-provider": "^2.1.1", - "@smithy/smithy-client": "^2.3.1", - "@smithy/types": "^2.9.1", - "tslib": "^2.5.0" - }, - "engines": { - "node": ">= 10.0.0" - } - }, - "node_modules/@smithy/util-endpoints": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@smithy/util-endpoints/-/util-endpoints-1.1.1.tgz", - "integrity": "sha512-sI4d9rjoaekSGEtq3xSb2nMjHMx8QXcz2cexnVyRWsy4yQ9z3kbDpX+7fN0jnbdOp0b3KSTZJZ2Yb92JWSanLw==", - "dependencies": { - "@smithy/node-config-provider": "^2.2.1", - "@smithy/types": "^2.9.1", - "tslib": "^2.5.0" - }, - "engines": { - "node": ">= 14.0.0" - } - }, - "node_modules/@smithy/util-hex-encoding": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/@smithy/util-hex-encoding/-/util-hex-encoding-2.1.1.tgz", - "integrity": "sha512-3UNdP2pkYUUBGEXzQI9ODTDK+Tcu1BlCyDBaRHwyxhA+8xLP8agEKQq4MGmpjqb4VQAjq9TwlCQX0kP6XDKYLg==", - "dependencies": { - "tslib": "^2.5.0" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@smithy/util-middleware": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/@smithy/util-middleware/-/util-middleware-2.1.1.tgz", - "integrity": "sha512-mKNrk8oz5zqkNcbcgAAepeJbmfUW6ogrT2Z2gDbIUzVzNAHKJQTYmH9jcy0jbWb+m7ubrvXKb6uMjkSgAqqsFA==", - "dependencies": { - "@smithy/types": "^2.9.1", - "tslib": "^2.5.0" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@smithy/util-retry": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/@smithy/util-retry/-/util-retry-2.1.1.tgz", - "integrity": "sha512-Mg+xxWPTeSPrthpC5WAamJ6PW4Kbo01Fm7lWM1jmGRvmrRdsd3192Gz2fBXAMURyXpaNxyZf6Hr/nQ4q70oVEA==", - "dependencies": { - "@smithy/service-error-classification": "^2.1.1", - "@smithy/types": "^2.9.1", - "tslib": "^2.5.0" - }, - "engines": { - "node": ">= 14.0.0" - } - }, - "node_modules/@smithy/util-stream": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/@smithy/util-stream/-/util-stream-2.1.1.tgz", - "integrity": "sha512-J7SMIpUYvU4DQN55KmBtvaMc7NM3CZ2iWICdcgaovtLzseVhAqFRYqloT3mh0esrFw+3VEK6nQFteFsTqZSECQ==", - "dependencies": { - "@smithy/fetch-http-handler": "^2.4.1", - "@smithy/node-http-handler": "^2.3.1", - "@smithy/types": "^2.9.1", - "@smithy/util-base64": "^2.1.1", - "@smithy/util-buffer-from": "^2.1.1", - "@smithy/util-hex-encoding": "^2.1.1", - "@smithy/util-utf8": "^2.1.1", - "tslib": "^2.5.0" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@smithy/util-uri-escape": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/@smithy/util-uri-escape/-/util-uri-escape-2.1.1.tgz", - "integrity": "sha512-saVzI1h6iRBUVSqtnlOnc9ssU09ypo7n+shdQ8hBTZno/9rZ3AuRYvoHInV57VF7Qn7B+pFJG7qTzFiHxWlWBw==", - "dependencies": { - "tslib": "^2.5.0" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@smithy/util-utf8": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/@smithy/util-utf8/-/util-utf8-2.1.1.tgz", - "integrity": "sha512-BqTpzYEcUMDwAKr7/mVRUtHDhs6ZoXDi9NypMvMfOr/+u1NW7JgqodPDECiiLboEm6bobcPcECxzjtQh865e9A==", - "dependencies": { - "@smithy/util-buffer-from": "^2.1.1", - "tslib": "^2.5.0" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@smithy/util-waiter": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/@smithy/util-waiter/-/util-waiter-2.1.1.tgz", - "integrity": "sha512-kYy6BLJJNif+uqNENtJqWdXcpqo1LS+nj1AfXcDhOpqpSHJSAkVySLyZV9fkmuVO21lzGoxjvd1imGGJHph/IA==", - "dependencies": { - "@smithy/abort-controller": "^2.1.1", - "@smithy/types": "^2.9.1", - "tslib": "^2.5.0" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@tsconfig/node10": { - "version": "1.0.9", - "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.9.tgz", - "integrity": "sha512-jNsYVVxU8v5g43Erja32laIDHXeoNvFEpX33OK4d6hljo3jDhCBDhx5dhCCTMWUojscpAagGiRkBKxpdl9fxqA==", - "dev": true - }, - "node_modules/@tsconfig/node12": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz", - "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==", - "dev": true - }, - "node_modules/@tsconfig/node14": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz", - "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==", - "dev": true - }, - "node_modules/@tsconfig/node16": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.4.tgz", - "integrity": "sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==", - "dev": true - }, - "node_modules/@types/bad-words": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@types/bad-words/-/bad-words-3.0.3.tgz", - "integrity": "sha512-jYdpTxDOJ+EENnsCwt8cOZhV/+4+qcwhks1igrOSg4zwwA17rsPqLsZpTo1l+OwViNu+5SPus0v5g7iGx+ofzA==", - "dev": true - }, - "node_modules/@types/config": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/@types/config/-/config-3.3.3.tgz", - "integrity": "sha512-BB8DBAud88EgiAKlz8WQStzI771Kb6F3j4dioRJ4GD+tP4tzcZyMlz86aXuZT4s9hyesFORehMQE6eqtA5O+Vg==", - "dev": true - }, - "node_modules/@types/jsdom": { - "version": "21.1.6", - "resolved": "https://registry.npmjs.org/@types/jsdom/-/jsdom-21.1.6.tgz", - "integrity": "sha512-/7kkMsC+/kMs7gAYmmBR9P0vGTnOoLhQhyhQJSlXGI5bzTHp6xdo0TtKWQAsz6pmSAeVqKSbqeyP6hytqr9FDw==", - "dev": true, - "dependencies": { - "@types/node": "*", - "@types/tough-cookie": "*", - "parse5": "^7.0.0" - } - }, - "node_modules/@types/node": { - "version": "18.19.6", - "resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.6.tgz", - "integrity": "sha512-X36s5CXMrrJOs2lQCdDF68apW4Rfx9ixYMawlepwmE4Anezv/AV2LSpKD1Ub8DAc+urp5bk0BGZ6NtmBitfnsg==", - "dependencies": { - "undici-types": "~5.26.4" - } - }, - "node_modules/@types/node-fetch": { - "version": "2.6.10", - "resolved": "https://registry.npmjs.org/@types/node-fetch/-/node-fetch-2.6.10.tgz", - "integrity": "sha512-PPpPK6F9ALFTn59Ka3BaL+qGuipRfxNE8qVgkp0bVixeiR2c2/L+IVOiBdu9JhhT22sWnQEp6YyHGI2b2+CMcA==", - "dev": true, - "dependencies": { - "@types/node": "*", - "form-data": "^4.0.0" - } - }, - "node_modules/@types/tough-cookie": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/@types/tough-cookie/-/tough-cookie-4.0.5.tgz", - "integrity": "sha512-/Ad8+nIOV7Rl++6f1BdKxFSMgmoqEoYbHRpPcx3JEfv8VRsQe9Z4mCXeJBzxs7mbHY/XOZZuXlRNfhpVPbs6ZA==", - "dev": true - }, - "node_modules/@types/triple-beam": { - "version": "1.3.5", - "resolved": "https://registry.npmjs.org/@types/triple-beam/-/triple-beam-1.3.5.tgz", - "integrity": "sha512-6WaYesThRMCl19iryMYP7/x2OVgCtbIVflDGFpWnb9irXI3UjYE4AzmYuiUKY1AJstGijoY+MgUszMgRxIYTYw==" - }, - "node_modules/@types/webidl-conversions": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/@types/webidl-conversions/-/webidl-conversions-7.0.3.tgz", - "integrity": "sha512-CiJJvcRtIgzadHCYXw7dqEnMNRjhGZlYK05Mj9OyktqV8uVT8fD2BFOB7S1uwBE3Kj2Z+4UyPmFw/Ixgw/LAlA==" - }, - "node_modules/@types/whatwg-url": { - "version": "8.2.2", - "resolved": "https://registry.npmjs.org/@types/whatwg-url/-/whatwg-url-8.2.2.tgz", - "integrity": "sha512-FtQu10RWgn3D9U4aazdwIE2yzphmTJREDqNdODHrbrZmmMqI0vMheC/6NE/J1Yveaj8H+ela+YwWTjq5PGmuhA==", - "dependencies": { - "@types/node": "*", - "@types/webidl-conversions": "*" - } - }, - "node_modules/@types/ws": { - "version": "8.5.9", - "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.9.tgz", - "integrity": "sha512-jbdrY0a8lxfdTp/+r7Z4CkycbOFN8WX+IOchLJr3juT/xzbJ8URyTVSJ/hvNdadTgM1mnedb47n+Y31GsFnQlg==", - "dependencies": { - "@types/node": "*" - } - }, - "node_modules/@typescript-eslint/type-utils": { - "version": "8.0.0-alpha.30", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.0.0-alpha.30.tgz", - "integrity": "sha512-FrnhlCKEKZKRbpDviHkIU9tayIUGTOfa+SjvrRv6p/AJIUv6QT8oRboRjLH/cCuwUEbM0k5UtRWYug4albHUqQ==", - "dev": true, - "dependencies": { - "@typescript-eslint/typescript-estree": "8.0.0-alpha.30", - "@typescript-eslint/utils": "8.0.0-alpha.30", - "debug": "^4.3.4", - "ts-api-utils": "^1.3.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/@typescript-eslint/type-utils/node_modules/@typescript-eslint/types": { - "version": "8.0.0-alpha.30", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.0.0-alpha.30.tgz", - "integrity": "sha512-4WzLlw27SO9pK9UFj/Hu7WGo8WveT0SEiIpFVsV2WwtQmLps6kouwtVCB8GJPZKJyurhZhcqCoQVQFmpv441Vg==", - "dev": true, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/typescript-estree": { - "version": "8.0.0-alpha.30", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.0.0-alpha.30.tgz", - "integrity": "sha512-WSXbc9ZcXI+7yC+6q95u77i8FXz6HOLsw3ST+vMUlFy1lFbXyFL/3e6HDKQCm2Clt0krnoCPiTGvIn+GkYPn4Q==", - "dev": true, - "dependencies": { - "@typescript-eslint/types": "8.0.0-alpha.30", - "@typescript-eslint/visitor-keys": "8.0.0-alpha.30", - "debug": "^4.3.4", - "globby": "^11.1.0", - "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.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/visitor-keys": { - "version": "8.0.0-alpha.30", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.0.0-alpha.30.tgz", - "integrity": "sha512-XZuNurZxBqmr6ZIRIwWFq7j5RZd6ZlkId/HZEWyfciK+CWoyOxSF9Pv2VXH9Rlu2ZG2PfbhLz2Veszl4Pfn7yA==", - "dev": true, - "dependencies": { - "@typescript-eslint/types": "8.0.0-alpha.30", - "eslint-visitor-keys": "^3.4.3" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@typescript-eslint/type-utils/node_modules/minimatch": { - "version": "9.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.4.tgz", - "integrity": "sha512-KqWh+VchfxcMNRAJjj2tnsSJdNbHsVgnkBhTNrW7AjVo6OvLtxw8zfT9oLw1JSohlFzJ8jCoTgaoXvJ+kHt6fw==", - "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": "8.0.0-alpha.30", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.0.0-alpha.30.tgz", - "integrity": "sha512-rfhqfLqFyXhHNDwMnHiVGxl/Z2q/3guQ1jLlGQ0hi9Rb7inmwz42crM+NnLPR+2vEnwyw1P/g7fnQgQ3qvFx4g==", - "dev": true, - "dependencies": { - "@eslint-community/eslint-utils": "^4.4.0", - "@typescript-eslint/scope-manager": "8.0.0-alpha.30", - "@typescript-eslint/types": "8.0.0-alpha.30", - "@typescript-eslint/typescript-estree": "8.0.0-alpha.30" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^8.57.0 || ^9.0.0" - } - }, - "node_modules/@typescript-eslint/utils/node_modules/@typescript-eslint/scope-manager": { - "version": "8.0.0-alpha.30", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.0.0-alpha.30.tgz", - "integrity": "sha512-FGW/iPWGyPFamAVZ60oCAthMqQrqafUGebF8UKuq/ha+e9SVG6YhJoRzurlQXOVf8dHfOhJ0ADMXyFnMc53clg==", - "dev": true, - "dependencies": { - "@typescript-eslint/types": "8.0.0-alpha.30", - "@typescript-eslint/visitor-keys": "8.0.0-alpha.30" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@typescript-eslint/utils/node_modules/@typescript-eslint/types": { - "version": "8.0.0-alpha.30", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.0.0-alpha.30.tgz", - "integrity": "sha512-4WzLlw27SO9pK9UFj/Hu7WGo8WveT0SEiIpFVsV2WwtQmLps6kouwtVCB8GJPZKJyurhZhcqCoQVQFmpv441Vg==", - "dev": true, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@typescript-eslint/utils/node_modules/@typescript-eslint/typescript-estree": { - "version": "8.0.0-alpha.30", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.0.0-alpha.30.tgz", - "integrity": "sha512-WSXbc9ZcXI+7yC+6q95u77i8FXz6HOLsw3ST+vMUlFy1lFbXyFL/3e6HDKQCm2Clt0krnoCPiTGvIn+GkYPn4Q==", - "dev": true, - "dependencies": { - "@typescript-eslint/types": "8.0.0-alpha.30", - "@typescript-eslint/visitor-keys": "8.0.0-alpha.30", - "debug": "^4.3.4", - "globby": "^11.1.0", - "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.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@typescript-eslint/utils/node_modules/@typescript-eslint/visitor-keys": { - "version": "8.0.0-alpha.30", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.0.0-alpha.30.tgz", - "integrity": "sha512-XZuNurZxBqmr6ZIRIwWFq7j5RZd6ZlkId/HZEWyfciK+CWoyOxSF9Pv2VXH9Rlu2ZG2PfbhLz2Veszl4Pfn7yA==", - "dev": true, - "dependencies": { - "@typescript-eslint/types": "8.0.0-alpha.30", - "eslint-visitor-keys": "^3.4.3" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@typescript-eslint/utils/node_modules/minimatch": { - "version": "9.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.4.tgz", - "integrity": "sha512-KqWh+VchfxcMNRAJjj2tnsSJdNbHsVgnkBhTNrW7AjVo6OvLtxw8zfT9oLw1JSohlFzJ8jCoTgaoXvJ+kHt6fw==", - "dev": true, - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/@vladfrangu/async_event_emitter": { - "version": "2.2.4", - "resolved": "https://registry.npmjs.org/@vladfrangu/async_event_emitter/-/async_event_emitter-2.2.4.tgz", - "integrity": "sha512-ButUPz9E9cXMLgvAW8aLAKKJJsPu1dY1/l/E8xzLFuysowXygs6GBcyunK9rnGC4zTsnIc2mQo71rGw9U+Ykug==", - "engines": { - "node": ">=v14.0.0", - "npm": ">=7.0.0" - } - }, - "node_modules/abbrev": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", - "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", - "dev": true - }, - "node_modules/acorn": { - "version": "8.11.3", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.3.tgz", - "integrity": "sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==", - "dev": true, - "bin": { - "acorn": "bin/acorn" - }, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/acorn-jsx": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", - "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", - "dev": true, - "peerDependencies": { - "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" - } - }, - "node_modules/acorn-walk": { - "version": "8.3.1", - "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.1.tgz", - "integrity": "sha512-TgUZgYvqZprrl7YldZNoa9OciCAyZR+Ejm9eXzKCmjsF5IKp/wgQ7Z/ZpjpGTIUPwrHQIcYeI8qDh4PsEwxMbw==", - "dev": true, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/agent-base": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.0.tgz", - "integrity": "sha512-o/zjMZRhJxny7OyEF+Op8X+efiELC7k7yOjMzgfzVqOzXqkBkWI79YoTdOtsuWd5BWhAGAuOY/Xa6xpiaWXiNg==", - "dependencies": { - "debug": "^4.3.4" - }, - "engines": { - "node": ">= 14" - } - }, - "node_modules/ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", - "dev": true, - "dependencies": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/anymatch": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", - "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", - "dev": true, - "dependencies": { - "normalize-path": "^3.0.0", - "picomatch": "^2.0.4" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/arg": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", - "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", - "dev": true - }, - "node_modules/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 - }, - "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/async": { - "version": "3.2.5", - "resolved": "https://registry.npmjs.org/async/-/async-3.2.5.tgz", - "integrity": "sha512-baNZyqaaLhyLVKm/DlvdW051MSgO6b8eVfIezl9E5PqWxFgzLm/wQntEW4zOytVburDEr0JlALEpdOFwvErLsg==" - }, - "node_modules/asynckit": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" - }, - "node_modules/bad-words": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/bad-words/-/bad-words-3.0.4.tgz", - "integrity": "sha512-v/Q9uRPH4+yzDVLL4vR1+S9KoFgOEUl5s4axd6NIAq8SV2mradgi4E8lma/Y0cw1ltVdvyegCQQKffCPRCp8fg==", - "dependencies": { - "badwords-list": "^1.0.0" - }, - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/badwords-list": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/badwords-list/-/badwords-list-1.0.0.tgz", - "integrity": "sha512-oWhaSG67e+HQj3OGHQt2ucP+vAPm1wTbdp2aDHeuh4xlGXBdWwzZ//pfu6swf5gZ8iX0b7JgmSo8BhgybbqszA==" - }, - "node_modules/balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "dev": true - }, - "node_modules/base64-js": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", - "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] - }, - "node_modules/bidi-js": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/bidi-js/-/bidi-js-1.0.3.tgz", - "integrity": "sha512-RKshQI1R3YQ+n9YJz2QQ147P66ELpa1FQEg20Dk8oW9t2KgLbpDLLp9aGZ7y8WHSshDknG0bknqGw5/tyCs5tw==", - "dependencies": { - "require-from-string": "^2.0.2" - } - }, - "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==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/bowser": { - "version": "2.11.0", - "resolved": "https://registry.npmjs.org/bowser/-/bowser-2.11.0.tgz", - "integrity": "sha512-AlcaJBi/pqqJBIQ8U9Mcpc9i8Aqxn88Skv5d+xBX006BY5u8N3mGLHa5Lgppa7L/HfwgwLgZ6NYs+Ag6uUmJRA==" - }, - "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/braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", - "dev": true, - "dependencies": { - "fill-range": "^7.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/bson": { - "version": "4.7.2", - "resolved": "https://registry.npmjs.org/bson/-/bson-4.7.2.tgz", - "integrity": "sha512-Ry9wCtIZ5kGqkJoi6aD8KjxFZEx78guTQDnpXWiNthsxzrxAK/i8E6pCHAIZTbaEFWcOCvbecMukfK7XUvyLpQ==", - "dependencies": { - "buffer": "^5.6.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/buffer": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", - "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "dependencies": { - "base64-js": "^1.3.1", - "ieee754": "^1.1.13" - } - }, - "node_modules/callsites": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", - "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/chokidar": { - "version": "3.5.3", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", - "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", - "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://paulmillr.com/funding/" - } - ], - "dependencies": { - "anymatch": "~3.1.2", - "braces": "~3.0.2", - "glob-parent": "~5.1.2", - "is-binary-path": "~2.1.0", - "is-glob": "~4.0.1", - "normalize-path": "~3.0.0", - "readdirp": "~3.6.0" - }, - "engines": { - "node": ">= 8.10.0" - }, - "optionalDependencies": { - "fsevents": "~2.3.2" - } - }, - "node_modules/color": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/color/-/color-3.2.1.tgz", - "integrity": "sha512-aBl7dZI9ENN6fUGC7mWpMTPNHmWUSNan9tuWN6ahh5ZLNk9baLJOnSMlrQkHcrfFgz2/RigjUVAjdx36VcemKA==", - "dependencies": { - "color-convert": "^1.9.3", - "color-string": "^1.6.0" - } - }, - "node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" - }, - "node_modules/color-string": { - "version": "1.9.1", - "resolved": "https://registry.npmjs.org/color-string/-/color-string-1.9.1.tgz", - "integrity": "sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==", - "dependencies": { - "color-name": "^1.0.0", - "simple-swizzle": "^0.2.2" - } - }, - "node_modules/color/node_modules/color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dependencies": { - "color-name": "1.1.3" - } - }, - "node_modules/color/node_modules/color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==" - }, - "node_modules/colorspace": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/colorspace/-/colorspace-1.1.4.tgz", - "integrity": "sha512-BgvKJiuVu1igBUF2kEjRCZXol6wiiGbY5ipL/oVPwm0BL9sIpMIzM8IK7vwuxIIzOXMV3Ey5w+vxhm0rR/TN8w==", - "dependencies": { - "color": "^3.1.3", - "text-hex": "1.0.x" - } - }, - "node_modules/combined-stream": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", - "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", - "dependencies": { - "delayed-stream": "~1.0.0" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", - "dev": true - }, - "node_modules/config": { - "version": "3.3.10", - "resolved": "https://registry.npmjs.org/config/-/config-3.3.10.tgz", - "integrity": "sha512-9Kl3LpQ6zj93KaqgfIMTcpwTpgozFOqNl/Dk7mjras1BgGIOlqxWkyIGeU1my+sRuskRYwrCATgCk1RjAnRPGA==", - "dependencies": { - "json5": "^2.2.3" - }, - "engines": { - "node": ">= 10.0.0" - } - }, - "node_modules/create-require": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", - "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", - "dev": true - }, - "node_modules/cron-parser": { - "version": "4.9.0", - "resolved": "https://registry.npmjs.org/cron-parser/-/cron-parser-4.9.0.tgz", - "integrity": "sha512-p0SaNjrHOnQeR8/VnfGbmg9te2kfyYSQ7Sc/j/6DtPL3JQvKxmjO9TSjNFpujqV3vEYYBvNNvXSxzyksBWAx1Q==", - "dependencies": { - "luxon": "^3.2.1" - }, - "engines": { - "node": ">=12.0.0" - } - }, - "node_modules/cross-spawn": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", - "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", - "dev": true, - "dependencies": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/css-tree": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-2.3.1.tgz", - "integrity": "sha512-6Fv1DV/TYw//QF5IzQdqsNDjx/wc8TrMBZsqjL9eW01tWb7R7k/mq+/VXfJCl7SoD5emsJop9cOByJZfs8hYIw==", - "dependencies": { - "mdn-data": "2.0.30", - "source-map-js": "^1.0.1" - }, - "engines": { - "node": "^10 || ^12.20.0 || ^14.13.0 || >=15.0.0" - } - }, - "node_modules/cssstyle": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-4.0.1.tgz", - "integrity": "sha512-8ZYiJ3A/3OkDd093CBT/0UKDWry7ak4BdPTFP2+QEP7cmhouyq/Up709ASSj2cK02BbZiMgk7kYjZNS4QP5qrQ==", - "dependencies": { - "rrweb-cssom": "^0.6.0" - }, - "engines": { - "node": ">=18" - } - }, - "node_modules/data-urls": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-5.0.0.tgz", - "integrity": "sha512-ZYP5VBHshaDAiVZxjbRVcFJpc+4xGgT0bK3vzy1HLN8jTO975HEbuYzZJcHoQEY5K1a0z8YayJkyVETa08eNTg==", - "dependencies": { - "whatwg-mimetype": "^4.0.0", - "whatwg-url": "^14.0.0" - }, - "engines": { - "node": ">=18" - } - }, - "node_modules/data-urls/node_modules/tr46": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-5.0.0.tgz", - "integrity": "sha512-tk2G5R2KRwBd+ZN0zaEXpmzdKyOYksXwywulIX95MBODjSzMIuQnQ3m8JxgbhnL1LeVo7lqQKsYa1O3Htl7K5g==", - "dependencies": { - "punycode": "^2.3.1" - }, - "engines": { - "node": ">=18" - } - }, - "node_modules/data-urls/node_modules/whatwg-url": { - "version": "14.0.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-14.0.0.tgz", - "integrity": "sha512-1lfMEm2IEr7RIV+f4lUNPOqfFL+pO+Xw3fJSqmjX9AbXcXcYOkCe1P6+9VBZB6n94af16NfZf+sSk0JCBZC9aw==", - "dependencies": { - "tr46": "^5.0.0", - "webidl-conversions": "^7.0.0" - }, - "engines": { - "node": ">=18" - } - }, - "node_modules/date.js": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/date.js/-/date.js-0.3.3.tgz", - "integrity": "sha512-HgigOS3h3k6HnW011nAb43c5xx5rBXk8P2v/WIT9Zv4koIaVXiH2BURguI78VVp+5Qc076T7OR378JViCnZtBw==", - "dependencies": { - "debug": "~3.1.0" - } - }, - "node_modules/date.js/node_modules/debug": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", - "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", - "dependencies": { - "ms": "2.0.0" - } - }, - "node_modules/date.js/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" - }, - "node_modules/debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/decimal.js": { - "version": "10.4.3", - "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.4.3.tgz", - "integrity": "sha512-VBBaLc1MgL5XpzgIP7ny5Z6Nx3UrRkIViUkPUdtl9aya5amy3De1gsUUSB1g3+3sExYNjCAsAznmukyxCb1GRA==" - }, - "node_modules/deep-is": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", - "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", - "dev": true - }, - "node_modules/delayed-stream": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", - "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/deprecation": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/deprecation/-/deprecation-2.3.1.tgz", - "integrity": "sha512-xmHIy4F3scKVwMsQ4WnVaS8bHOx0DmVwRywosKhaILI0ywMDWPtBSku2HNxRvF7jtwDRsoEwYQSfbxj8b7RlJQ==" - }, - "node_modules/diff": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", - "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", - "dev": true, - "engines": { - "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.61", - "resolved": "https://registry.npmjs.org/discord-api-types/-/discord-api-types-0.37.61.tgz", - "integrity": "sha512-o/dXNFfhBpYHpQFdT6FWzeO7pKc838QeeZ9d91CfVAtpr5XLK4B/zYxQbYgPdoMiTDvJfzcsLW5naXgmHGDNXw==" - }, - "node_modules/discord.js": { - "version": "14.14.1", - "resolved": "https://registry.npmjs.org/discord.js/-/discord.js-14.14.1.tgz", - "integrity": "sha512-/hUVzkIerxKHyRKopJy5xejp4MYKDPTszAnpYxzVVv4qJYf+Tkt+jnT2N29PIPschicaEEpXwF2ARrTYHYwQ5w==", - "dependencies": { - "@discordjs/builders": "^1.7.0", - "@discordjs/collection": "1.5.3", - "@discordjs/formatters": "^0.3.3", - "@discordjs/rest": "^2.1.0", - "@discordjs/util": "^1.0.2", - "@discordjs/ws": "^1.0.2", - "@sapphire/snowflake": "3.5.1", - "@types/ws": "8.5.9", - "discord-api-types": "0.37.61", - "fast-deep-equal": "3.1.3", - "lodash.snakecase": "4.1.1", - "tslib": "2.6.2", - "undici": "5.27.2", - "ws": "8.14.2" - }, - "engines": { - "node": ">=16.11.0" - } - }, - "node_modules/dotenv": { - "version": "16.3.1", - "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.3.1.tgz", - "integrity": "sha512-IPzF4w4/Rd94bA9imS68tZBaYyBWSCE47V1RGuMrB94iyTOIEwRmVL2x/4An+6mETpLrKJ5hQkB8W4kFAadeIQ==", - "dev": true, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/motdotla/dotenv?sponsor=1" - } - }, - "node_modules/enabled": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/enabled/-/enabled-2.0.0.tgz", - "integrity": "sha512-AKrN98kuwOzMIdAizXGI86UFBoo26CL21UM763y1h/GMSJ4/OHU9k2YlsmBpyScFo/wbLzWQJBMCW4+IO3/+OQ==" - }, - "node_modules/entities": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", - "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", - "engines": { - "node": ">=0.12" - }, - "funding": { - "url": "https://github.com/fb55/entities?sponsor=1" - } - }, - "node_modules/escape-string-regexp": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", - "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/eslint": { - "version": "9.4.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.4.0.tgz", - "integrity": "sha512-sjc7Y8cUD1IlwYcTS9qPSvGjAC8Ne9LctpxKKu3x/1IC9bnOg98Zy6GxEJUfr1NojMgVPlyANXYns8oE2c1TAA==", - "dev": true, - "dependencies": { - "@eslint-community/eslint-utils": "^4.2.0", - "@eslint-community/regexpp": "^4.6.1", - "@eslint/config-array": "^0.15.1", - "@eslint/eslintrc": "^3.1.0", - "@eslint/js": "9.4.0", - "@humanwhocodes/module-importer": "^1.0.1", - "@humanwhocodes/retry": "^0.3.0", - "@nodelib/fs.walk": "^1.2.8", - "ajv": "^6.12.4", - "chalk": "^4.0.0", - "cross-spawn": "^7.0.2", - "debug": "^4.3.2", - "escape-string-regexp": "^4.0.0", - "eslint-scope": "^8.0.1", - "eslint-visitor-keys": "^4.0.0", - "espree": "^10.0.1", - "esquery": "^1.4.2", - "esutils": "^2.0.2", - "fast-deep-equal": "^3.1.3", - "file-entry-cache": "^8.0.0", - "find-up": "^5.0.0", - "glob-parent": "^6.0.2", - "ignore": "^5.2.0", - "imurmurhash": "^0.1.4", - "is-glob": "^4.0.0", - "is-path-inside": "^3.0.3", - "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" - }, - "bin": { - "eslint": "bin/eslint.js" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/eslint-config-prettier": { - "version": "9.1.0", - "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-9.1.0.tgz", - "integrity": "sha512-NSWl5BFQWEPi1j4TjVNItzYV7dZXZ+wP6I6ZhrBGpChQhZRUaElihE9uRRkcbRnNb76UMKDF3r+WTmNcGPKsqw==", - "dev": true, - "bin": { - "eslint-config-prettier": "bin/cli.js" - }, - "peerDependencies": { - "eslint": ">=7.0.0" - } - }, - "node_modules/eslint-plugin-prettier": { - "version": "5.1.3", - "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-5.1.3.tgz", - "integrity": "sha512-C9GCVAs4Eq7ZC/XFQHITLiHJxQngdtraXaM+LoUFoFp/lHNl2Zn8f3WQbe9HvTBBQ9YnKFB0/2Ajdqwo5D1EAw==", - "dev": true, - "dependencies": { - "prettier-linter-helpers": "^1.0.0", - "synckit": "^0.8.6" - }, - "engines": { - "node": "^14.18.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint-plugin-prettier" - }, - "peerDependencies": { - "@types/eslint": ">=8.0.0", - "eslint": ">=8.0.0", - "eslint-config-prettier": "*", - "prettier": ">=3.0.0" - }, - "peerDependenciesMeta": { - "@types/eslint": { - "optional": true - }, - "eslint-config-prettier": { - "optional": true - } - } - }, - "node_modules/eslint-scope": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.0.1.tgz", - "integrity": "sha512-pL8XjgP4ZOmmwfFE8mEhSxA7ZY4C+LWyqjQ3o4yWkkmD0qcMT9kkW3zWHOczhWcjTSgqycYAgwSlXvZltv65og==", - "dev": true, - "dependencies": { - "esrecurse": "^4.3.0", - "estraverse": "^5.2.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/eslint-visitor-keys": { - "version": "3.4.3", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", - "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", - "dev": true, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "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, - "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, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/eslint/node_modules/glob-parent": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", - "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", - "dev": true, - "dependencies": { - "is-glob": "^4.0.3" - }, - "engines": { - "node": ">=10.13.0" - } - }, - "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, - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/espree": { - "version": "10.0.1", - "resolved": "https://registry.npmjs.org/espree/-/espree-10.0.1.tgz", - "integrity": "sha512-MWkrWZbJsL2UwnjxTX3gG8FneachS/Mwg7tdGXce011sJd5b0JG54vat5KHnfSBODZ3Wvzd2WnjxyzsRoVv+ww==", - "dev": true, - "dependencies": { - "acorn": "^8.11.3", - "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/espree/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, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/esquery": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.5.0.tgz", - "integrity": "sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==", - "dev": true, - "dependencies": { - "estraverse": "^5.1.0" - }, - "engines": { - "node": ">=0.10" - } - }, - "node_modules/esrecurse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", - "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", - "dev": true, - "dependencies": { - "estraverse": "^5.2.0" - }, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/esutils": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", - "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/events": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", - "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", - "engines": { - "node": ">=0.8.x" - } - }, - "node_modules/fast-deep-equal": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" - }, - "node_modules/fast-diff": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.3.0.tgz", - "integrity": "sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw==", - "dev": true - }, - "node_modules/fast-glob": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz", - "integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==", - "dev": true, - "dependencies": { - "@nodelib/fs.stat": "^2.0.2", - "@nodelib/fs.walk": "^1.2.3", - "glob-parent": "^5.1.2", - "merge2": "^1.3.0", - "micromatch": "^4.0.4" - }, - "engines": { - "node": ">=8.6.0" - } - }, - "node_modules/fast-json-stable-stringify": { - "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 - }, - "node_modules/fast-levenshtein": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", - "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", - "dev": true - }, - "node_modules/fast-xml-parser": { - "version": "4.2.5", - "resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-4.2.5.tgz", - "integrity": "sha512-B9/wizE4WngqQftFPmdaMYlXoJlJOYxGQOanC77fq9k8+Z0v5dDSVh+3glErdIROP//s/jgb7ZuxKfB8nVyo0g==", - "funding": [ - { - "type": "paypal", - "url": "https://paypal.me/naturalintelligence" - }, - { - "type": "github", - "url": "https://github.com/sponsors/NaturalIntelligence" - } - ], - "dependencies": { - "strnum": "^1.0.5" - }, - "bin": { - "fxparser": "src/cli/cli.js" - } - }, - "node_modules/fastq": { - "version": "1.16.0", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.16.0.tgz", - "integrity": "sha512-ifCoaXsDrsdkWTtiNJX5uzHDsrck5TzfKKDcuFFTIrrc/BS076qgEIfoIy1VeZqViznfKiysPYTh/QeHtnIsYA==", - "dev": true, - "dependencies": { - "reusify": "^1.0.4" - } - }, - "node_modules/fecha": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/fecha/-/fecha-4.2.3.tgz", - "integrity": "sha512-OP2IUU6HeYKJi3i0z4A19kHMQoLVs4Hc+DPqqxI2h/DPZHTm/vjsfC6P0b4jCMy14XizLBqvndQ+UilD7707Jw==" - }, - "node_modules/file-entry-cache": { - "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, - "dependencies": { - "flat-cache": "^4.0.0" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", - "dev": true, - "dependencies": { - "to-regex-range": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/find-up": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", - "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", - "dev": true, - "dependencies": { - "locate-path": "^6.0.0", - "path-exists": "^4.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/flat-cache": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz", - "integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==", - "dev": true, - "dependencies": { - "flatted": "^3.2.9", - "keyv": "^4.5.4" - }, - "engines": { - "node": ">=16" - } - }, - "node_modules/flatted": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.1.tgz", - "integrity": "sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==", - "dev": true - }, - "node_modules/fn.name": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/fn.name/-/fn.name-1.1.0.tgz", - "integrity": "sha512-GRnmB5gPyJpAhTQdSZTSp9uaPSvl09KoYcMQtsB9rQoOmzs9dH6ffeccH+Z+cv6P68Hu5bC6JjRh4Ah/mHSNRw==" - }, - "node_modules/form-data": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", - "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", - "dependencies": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.8", - "mime-types": "^2.1.12" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "dev": true, - "dependencies": { - "is-glob": "^4.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/globals": { - "version": "14.0.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz", - "integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==", - "dev": true, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "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/graphemer": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", - "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", - "dev": true - }, - "node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/html-encoding-sniffer": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-4.0.0.tgz", - "integrity": "sha512-Y22oTqIU4uuPgEemfz7NDJz6OeKf12Lsu+QC+s3BVpda64lTiMYCyGwg5ki4vFxkMwQdeZDl2adZoqUgdFuTgQ==", - "dependencies": { - "whatwg-encoding": "^3.1.1" - }, - "engines": { - "node": ">=18" - } - }, - "node_modules/http-proxy-agent": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.0.tgz", - "integrity": "sha512-+ZT+iBxVUQ1asugqnD6oWoRiS25AkjNfG085dKJGtGxkdwLQrMKU5wJr2bOOFAXzKcTuqq+7fZlTMgG3SRfIYQ==", - "dependencies": { - "agent-base": "^7.1.0", - "debug": "^4.3.4" - }, - "engines": { - "node": ">= 14" - } - }, - "node_modules/https-proxy-agent": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.2.tgz", - "integrity": "sha512-NmLNjm6ucYwtcUmL7JQC1ZQ57LmHP4lT15FQ8D61nak1rO6DH+fz5qNK2Ap5UN4ZapYICE3/0KodcLYSPsPbaA==", - "dependencies": { - "agent-base": "^7.0.2", - "debug": "4" - }, - "engines": { - "node": ">= 14" - } - }, - "node_modules/human-interval": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/human-interval/-/human-interval-2.0.1.tgz", - "integrity": "sha512-r4Aotzf+OtKIGQCB3odUowy4GfUDTy3aTWTfLd7ZF2gBCy3XW3v/dJLRefZnOFFnjqs5B1TypvS8WarpBkYUNQ==", - "dependencies": { - "numbered": "^1.1.0" - } - }, - "node_modules/iconv-lite": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", - "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", - "dependencies": { - "safer-buffer": ">= 2.1.2 < 3.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/ieee754": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", - "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] - }, - "node_modules/ignore": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.1.tgz", - "integrity": "sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw==", - "dev": true, - "engines": { - "node": ">= 4" - } - }, - "node_modules/ignore-by-default": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/ignore-by-default/-/ignore-by-default-1.0.1.tgz", - "integrity": "sha512-Ius2VYcGNk7T90CppJqcIkS5ooHUZyIQK+ClZfMfMNFEF9VSE73Fq+906u/CWu92x4gzZMWOwfFYckPObzdEbA==", - "dev": true - }, - "node_modules/import-fresh": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", - "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", - "dev": true, - "dependencies": { - "parent-module": "^1.0.0", - "resolve-from": "^4.0.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/imurmurhash": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", - "dev": true, - "engines": { - "node": ">=0.8.19" - } - }, - "node_modules/inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" - }, - "node_modules/ip": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ip/-/ip-2.0.0.tgz", - "integrity": "sha512-WKa+XuLG1A1R0UWhl2+1XQSi+fZWMsYKffMZTTYsiZaUD8k2yDAj5atimTUD2TZkyCkNEeYE5NhFZmupOGtjYQ==" - }, - "node_modules/is-arrayish": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz", - "integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==" - }, - "node_modules/is-binary-path": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", - "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", - "dev": true, - "dependencies": { - "binary-extensions": "^2.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/is-extglob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-glob": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", - "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", - "dev": true, - "dependencies": { - "is-extglob": "^2.1.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "dev": true, - "engines": { - "node": ">=0.12.0" - } - }, - "node_modules/is-path-inside": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", - "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/is-potential-custom-element-name": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz", - "integrity": "sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==" - }, - "node_modules/is-stream": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", - "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", - "dev": true - }, - "node_modules/js-yaml": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", - "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", - "dev": true, - "dependencies": { - "argparse": "^2.0.1" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, - "node_modules/jsdom": { - "version": "23.2.0", - "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-23.2.0.tgz", - "integrity": "sha512-L88oL7D/8ufIES+Zjz7v0aes+oBMh2Xnh3ygWvL0OaICOomKEPKuPnIfBJekiXr+BHbbMjrWn/xqrDQuxFTeyA==", - "dependencies": { - "@asamuzakjp/dom-selector": "^2.0.1", - "cssstyle": "^4.0.1", - "data-urls": "^5.0.0", - "decimal.js": "^10.4.3", - "form-data": "^4.0.0", - "html-encoding-sniffer": "^4.0.0", - "http-proxy-agent": "^7.0.0", - "https-proxy-agent": "^7.0.2", - "is-potential-custom-element-name": "^1.0.1", - "parse5": "^7.1.2", - "rrweb-cssom": "^0.6.0", - "saxes": "^6.0.0", - "symbol-tree": "^3.2.4", - "tough-cookie": "^4.1.3", - "w3c-xmlserializer": "^5.0.0", - "webidl-conversions": "^7.0.0", - "whatwg-encoding": "^3.1.1", - "whatwg-mimetype": "^4.0.0", - "whatwg-url": "^14.0.0", - "ws": "^8.16.0", - "xml-name-validator": "^5.0.0" - }, - "engines": { - "node": ">=18" - }, - "peerDependencies": { - "canvas": "^2.11.2" - }, - "peerDependenciesMeta": { - "canvas": { - "optional": true - } - } - }, - "node_modules/jsdom/node_modules/tr46": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-5.0.0.tgz", - "integrity": "sha512-tk2G5R2KRwBd+ZN0zaEXpmzdKyOYksXwywulIX95MBODjSzMIuQnQ3m8JxgbhnL1LeVo7lqQKsYa1O3Htl7K5g==", - "dependencies": { - "punycode": "^2.3.1" - }, - "engines": { - "node": ">=18" - } - }, - "node_modules/jsdom/node_modules/whatwg-url": { - "version": "14.0.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-14.0.0.tgz", - "integrity": "sha512-1lfMEm2IEr7RIV+f4lUNPOqfFL+pO+Xw3fJSqmjX9AbXcXcYOkCe1P6+9VBZB6n94af16NfZf+sSk0JCBZC9aw==", - "dependencies": { - "tr46": "^5.0.0", - "webidl-conversions": "^7.0.0" - }, - "engines": { - "node": ">=18" - } - }, - "node_modules/jsdom/node_modules/ws": { - "version": "8.16.0", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.16.0.tgz", - "integrity": "sha512-HS0c//TP7Ina87TfiPUz1rQzMhHrl/SG2guqRcTOIUYD2q8uhUdNHZYJUaQ8aTGPzCh+c6oawMKW35nFl1dxyQ==", - "engines": { - "node": ">=10.0.0" - }, - "peerDependencies": { - "bufferutil": "^4.0.1", - "utf-8-validate": ">=5.0.2" - }, - "peerDependenciesMeta": { - "bufferutil": { - "optional": true - }, - "utf-8-validate": { - "optional": true - } - } - }, - "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 - }, - "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 - }, - "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 - }, - "node_modules/json5": { - "version": "2.2.3", - "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", - "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", - "bin": { - "json5": "lib/cli.js" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/kareem": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/kareem/-/kareem-2.5.1.tgz", - "integrity": "sha512-7jFxRVm+jD+rkq3kY0iZDJfsO2/t4BBPeEb2qKn2lR/9KhuksYk5hxzfRYWMPV8P/x2d0kHD306YyWLzjjH+uA==", - "engines": { - "node": ">=12.0.0" - } - }, - "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, - "dependencies": { - "json-buffer": "3.0.1" - } - }, - "node_modules/kuler": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/kuler/-/kuler-2.0.0.tgz", - "integrity": "sha512-Xq9nH7KlWZmXAtodXDDRE7vs6DU1gTU8zYDHDiWLSip45Egwq3plLHzPn27NgvzL2r1LMPC1vdqh98sQxtqj4A==" - }, - "node_modules/levn": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", - "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", - "dev": true, - "dependencies": { - "prelude-ls": "^1.2.1", - "type-check": "~0.4.0" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/locate-path": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", - "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", - "dev": true, - "dependencies": { - "p-locate": "^5.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/lodash": { - "version": "4.17.21", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" - }, - "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 - }, - "node_modules/lodash.snakecase": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/lodash.snakecase/-/lodash.snakecase-4.1.1.tgz", - "integrity": "sha512-QZ1d4xoBHYUeuouhEq3lk3Uq7ldgyFXGBhg04+oRLnIz8o9T65Eh+8YdroUwn846zchkA9yDsDl5CVVaV2nqYw==" - }, - "node_modules/logform": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/logform/-/logform-2.6.0.tgz", - "integrity": "sha512-1ulHeNPp6k/LD8H91o7VYFBng5i1BDE7HoKxVbZiGFidS1Rj65qcywLxX+pVfAPoQJEjRdvKcusKwOupHCVOVQ==", - "dependencies": { - "@colors/colors": "1.6.0", - "@types/triple-beam": "^1.3.2", - "fecha": "^4.2.0", - "ms": "^2.1.1", - "safe-stable-stringify": "^2.3.1", - "triple-beam": "^1.3.0" - }, - "engines": { - "node": ">= 12.0.0" - } - }, - "node_modules/luxon": { - "version": "3.4.4", - "resolved": "https://registry.npmjs.org/luxon/-/luxon-3.4.4.tgz", - "integrity": "sha512-zobTr7akeGHnv7eBOXcRgMeCP6+uyYsczwmeRCauvpvaAltgNyTbLH/+VaEAPUeWBT+1GuNmz4wC/6jtQzbbVA==", - "engines": { - "node": ">=12" - } - }, - "node_modules/magic-bytes.js": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/magic-bytes.js/-/magic-bytes.js-1.7.0.tgz", - "integrity": "sha512-YzVU2+/hrjwx8xcgAw+ffNq3jkactpj+f1iSL4LonrFKhvnwDzHSqtFdk/MMRP53y9ScouJ7cKEnqYsJwsHoYA==" - }, - "node_modules/make-error": { - "version": "1.3.6", - "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", - "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", - "dev": true - }, - "node_modules/mdn-data": { - "version": "2.0.30", - "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.30.tgz", - "integrity": "sha512-GaqWWShW4kv/G9IEucWScBx9G1/vsFZZJUO+tD26M8J8z3Kw5RDQjaoZe03YAClgeS/SWPOcb4nkFBTEi5DUEA==" - }, - "node_modules/memory-pager": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/memory-pager/-/memory-pager-1.5.0.tgz", - "integrity": "sha512-ZS4Bp4r/Zoeq6+NLJpP+0Zzm0pR8whtGPf1XExKLJBAczGMnSi3It14OiNCStjQjM6NU1okjQGSxgEZN8eBYKg==" - }, - "node_modules/merge2": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", - "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", - "dev": true, - "engines": { - "node": ">= 8" - } - }, - "node_modules/micromatch": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", - "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", - "dev": true, - "dependencies": { - "braces": "^3.0.2", - "picomatch": "^2.3.1" - }, - "engines": { - "node": ">=8.6" - } - }, - "node_modules/mime-db": { - "version": "1.52.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", - "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/mime-types": { - "version": "2.1.35", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", - "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", - "dependencies": { - "mime-db": "1.52.0" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/moment": { - "version": "2.30.1", - "resolved": "https://registry.npmjs.org/moment/-/moment-2.30.1.tgz", - "integrity": "sha512-uEmtNhbDOrWPFS+hdjFCBfy9f2YoyzRpwcl+DqpC6taX21FzsTLQVbMV/W7PzNSX6x/bhC1zA3c2UQ5NzH6how==", - "engines": { - "node": "*" - } - }, - "node_modules/mongodb": { - "version": "4.17.2", - "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-4.17.2.tgz", - "integrity": "sha512-mLV7SEiov2LHleRJPMPrK2PMyhXFZt2UQLC4VD4pnth3jMjYKHhtqfwwkkvS/NXuo/Fp3vbhaNcXrIDaLRb9Tg==", - "dependencies": { - "bson": "^4.7.2", - "mongodb-connection-string-url": "^2.6.0", - "socks": "^2.7.1" - }, - "engines": { - "node": ">=12.9.0" - }, - "optionalDependencies": { - "@aws-sdk/credential-providers": "^3.186.0", - "@mongodb-js/saslprep": "^1.1.0" - } - }, - "node_modules/mongodb-connection-string-url": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/mongodb-connection-string-url/-/mongodb-connection-string-url-2.6.0.tgz", - "integrity": "sha512-WvTZlI9ab0QYtTYnuMLgobULWhokRjtC7db9LtcVfJ+Hsnyr5eo6ZtNAt3Ly24XZScGMelOcGtm7lSn0332tPQ==", - "dependencies": { - "@types/whatwg-url": "^8.2.1", - "whatwg-url": "^11.0.0" - } - }, - "node_modules/mongoose": { - "version": "8.0.4", - "resolved": "https://registry.npmjs.org/mongoose/-/mongoose-8.0.4.tgz", - "integrity": "sha512-wN9qvdevX3+922VnLT7CpaZRT3jmVCBOK2QMHMGeScQxDRnFMPpkuI9StEPpZo/3x8t+kbzH7F8RMPsyNwyM4w==", - "dependencies": { - "bson": "^6.2.0", - "kareem": "2.5.1", - "mongodb": "6.2.0", - "mpath": "0.9.0", - "mquery": "5.0.0", - "ms": "2.1.3", - "sift": "16.0.1" - }, - "engines": { - "node": ">=16.20.1" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/mongoose" - } - }, - "node_modules/mongoose/node_modules/bson": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/bson/-/bson-6.2.0.tgz", - "integrity": "sha512-ID1cI+7bazPDyL9wYy9GaQ8gEEohWvcUl/Yf0dIdutJxnmInEEyCsb4awy/OiBfall7zBA179Pahi3vCdFze3Q==", - "engines": { - "node": ">=16.20.1" - } - }, - "node_modules/mongoose/node_modules/mongodb": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-6.2.0.tgz", - "integrity": "sha512-d7OSuGjGWDZ5usZPqfvb36laQ9CPhnWkAGHT61x5P95p/8nMVeH8asloMwW6GcYFeB0Vj4CB/1wOTDG2RA9BFA==", - "dependencies": { - "@mongodb-js/saslprep": "^1.1.0", - "bson": "^6.2.0", - "mongodb-connection-string-url": "^2.6.0" - }, - "engines": { - "node": ">=16.20.1" - }, - "peerDependencies": { - "@aws-sdk/credential-providers": "^3.188.0", - "@mongodb-js/zstd": "^1.1.0", - "gcp-metadata": "^5.2.0", - "kerberos": "^2.0.1", - "mongodb-client-encryption": ">=6.0.0 <7", - "snappy": "^7.2.2", - "socks": "^2.7.1" - }, - "peerDependenciesMeta": { - "@aws-sdk/credential-providers": { - "optional": true - }, - "@mongodb-js/zstd": { - "optional": true - }, - "gcp-metadata": { - "optional": true - }, - "kerberos": { - "optional": true - }, - "mongodb-client-encryption": { - "optional": true - }, - "snappy": { - "optional": true - }, - "socks": { - "optional": true - } - } - }, - "node_modules/mongoose/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==" - }, - "node_modules/mpath": { - "version": "0.9.0", - "resolved": "https://registry.npmjs.org/mpath/-/mpath-0.9.0.tgz", - "integrity": "sha512-ikJRQTk8hw5DEoFVxHG1Gn9T/xcjtdnOKIU1JTmGjZZlg9LST2mBLmcX3/ICIbgJydT2GOc15RnNy5mHmzfSew==", - "engines": { - "node": ">=4.0.0" - } - }, - "node_modules/mquery": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/mquery/-/mquery-5.0.0.tgz", - "integrity": "sha512-iQMncpmEK8R8ncT8HJGsGc9Dsp8xcgYMVSbs5jgnm1lFHTZqMJTUWTDx1LBO8+mK3tPNZWFLBghQEIOULSTHZg==", - "dependencies": { - "debug": "4.x" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "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==" - }, - "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 - }, - "node_modules/node-fetch": { - "version": "2.7.0", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", - "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", - "dependencies": { - "whatwg-url": "^5.0.0" - }, - "engines": { - "node": "4.x || >=6.0.0" - }, - "peerDependencies": { - "encoding": "^0.1.0" - }, - "peerDependenciesMeta": { - "encoding": { - "optional": true - } - } - }, - "node_modules/node-fetch/node_modules/tr46": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", - "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" - }, - "node_modules/node-fetch/node_modules/webidl-conversions": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", - "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==" - }, - "node_modules/node-fetch/node_modules/whatwg-url": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", - "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", - "dependencies": { - "tr46": "~0.0.3", - "webidl-conversions": "^3.0.0" - } - }, - "node_modules/nodemon": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-3.0.2.tgz", - "integrity": "sha512-9qIN2LNTrEzpOPBaWHTm4Asy1LxXLSickZStAQ4IZe7zsoIpD/A7LWxhZV3t4Zu352uBcqVnRsDXSMR2Sc3lTA==", - "dev": true, - "dependencies": { - "chokidar": "^3.5.2", - "debug": "^4", - "ignore-by-default": "^1.0.1", - "minimatch": "^3.1.2", - "pstree.remy": "^1.1.8", - "semver": "^7.5.3", - "simple-update-notifier": "^2.0.0", - "supports-color": "^5.5.0", - "touch": "^3.1.0", - "undefsafe": "^2.0.5" - }, - "bin": { - "nodemon": "bin/nodemon.js" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/nodemon" - } - }, - "node_modules/nodemon/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, - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/nodemon/node_modules/has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/nodemon/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, - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/nodemon/node_modules/supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/nopt": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/nopt/-/nopt-1.0.10.tgz", - "integrity": "sha512-NWmpvLSqUrgrAC9HCuxEvb+PSloHpqVu+FqcO4eeF2h5qYRhA7ev6KvelyQAKtegUbC6RypJnlEOhd8vloNKYg==", - "dev": true, - "dependencies": { - "abbrev": "1" - }, - "bin": { - "nopt": "bin/nopt.js" - }, - "engines": { - "node": "*" - } - }, - "node_modules/normalize-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", - "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/numbered": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/numbered/-/numbered-1.1.0.tgz", - "integrity": "sha512-pv/ue2Odr7IfYOO0byC1KgBI10wo5YDauLhxY6/saNzAdAs0r1SotGCPzzCLNPL0xtrAwWRialLu23AAu9xO1g==" - }, - "node_modules/once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", - "dependencies": { - "wrappy": "1" - } - }, - "node_modules/one-time": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/one-time/-/one-time-1.0.0.tgz", - "integrity": "sha512-5DXOiRKwuSEcQ/l0kGCF6Q3jcADFv5tSmRaJck/OqkVFcOzutB134KRSfF0xDrL39MNnqxbHBbUUcjZIhTgb2g==", - "dependencies": { - "fn.name": "1.x.x" - } - }, - "node_modules/optionator": { - "version": "0.9.3", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.3.tgz", - "integrity": "sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg==", - "dev": true, - "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" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/p-limit": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", - "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", - "dev": true, - "dependencies": { - "yocto-queue": "^0.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/p-locate": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", - "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", - "dev": true, - "dependencies": { - "p-limit": "^3.0.2" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "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, - "dependencies": { - "callsites": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/parse5": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.1.2.tgz", - "integrity": "sha512-Czj1WaSVpaoj0wbhMzLmWD69anp2WH7FXMB9n1Sy8/ZFF9jolSQVMu1Ij5WIyGmcBmhk7EOndpO4mIpihVqAXw==", - "dependencies": { - "entities": "^4.4.0" - }, - "funding": { - "url": "https://github.com/inikulin/parse5?sponsor=1" - } - }, - "node_modules/path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/path-key": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", - "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "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==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/picomatch": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", - "dev": true, - "engines": { - "node": ">=8.6" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, - "node_modules/prelude-ls": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", - "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", - "dev": true, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/prettier": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.3.2.tgz", - "integrity": "sha512-rAVeHYMcv8ATV5d508CFdn+8/pHPpXeIid1DdrPwXnaAdH7cqjVbpJaT5eq4yRAFU/lsbwYwSF/n5iNrdJHPQA==", - "dev": true, - "bin": { - "prettier": "bin/prettier.cjs" - }, - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/prettier/prettier?sponsor=1" - } - }, - "node_modules/prettier-linter-helpers": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz", - "integrity": "sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==", - "dev": true, - "dependencies": { - "fast-diff": "^1.1.2" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/psl": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/psl/-/psl-1.9.0.tgz", - "integrity": "sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag==" - }, - "node_modules/pstree.remy": { - "version": "1.1.8", - "resolved": "https://registry.npmjs.org/pstree.remy/-/pstree.remy-1.1.8.tgz", - "integrity": "sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w==", - "dev": true - }, - "node_modules/punycode": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", - "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", - "engines": { - "node": ">=6" - } - }, - "node_modules/querystringify": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz", - "integrity": "sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==" - }, - "node_modules/queue-microtask": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", - "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] - }, - "node_modules/readable-stream": { - "version": "3.6.2", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", - "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", - "dependencies": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/readdirp": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", - "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", - "dev": true, - "dependencies": { - "picomatch": "^2.2.1" - }, - "engines": { - "node": ">=8.10.0" - } - }, - "node_modules/require-from-string": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", - "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/requires-port": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", - "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==" - }, - "node_modules/resolve-from": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", - "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/reusify": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", - "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", - "dev": true, - "engines": { - "iojs": ">=1.0.0", - "node": ">=0.10.0" - } - }, - "node_modules/rrweb-cssom": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/rrweb-cssom/-/rrweb-cssom-0.6.0.tgz", - "integrity": "sha512-APM0Gt1KoXBz0iIkkdB/kfvGOwC4UuJFeG/c+yV7wSc7q96cG/kJ0HiYCnzivD9SB53cLV1MlHFNfOuPaadYSw==" - }, - "node_modules/run-parallel": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", - "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "dependencies": { - "queue-microtask": "^1.2.2" - } - }, - "node_modules/safe-buffer": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] - }, - "node_modules/safe-stable-stringify": { - "version": "2.4.3", - "resolved": "https://registry.npmjs.org/safe-stable-stringify/-/safe-stable-stringify-2.4.3.tgz", - "integrity": "sha512-e2bDA2WJT0wxseVd4lsDP4+3ONX6HpMXQa1ZhFQ7SU+GjvORCmShbCMltrtIDfkYhVHrOcPtj+KhmDBdPdZD1g==", - "engines": { - "node": ">=10" - } - }, - "node_modules/safer-buffer": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" - }, - "node_modules/saxes": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/saxes/-/saxes-6.0.0.tgz", - "integrity": "sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA==", - "dependencies": { - "xmlchars": "^2.2.0" - }, - "engines": { - "node": ">=v12.22.7" - } - }, - "node_modules/semver": { - "version": "7.6.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.2.tgz", - "integrity": "sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w==", - "dev": true, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/shebang-command": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", - "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", - "dev": true, - "dependencies": { - "shebang-regex": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/shebang-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", - "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/sift": { - "version": "16.0.1", - "resolved": "https://registry.npmjs.org/sift/-/sift-16.0.1.tgz", - "integrity": "sha512-Wv6BjQ5zbhW7VFefWusVP33T/EM0vYikCaQ2qR8yULbsilAT8/wQaXvuQ3ptGLpoKx+lihJE3y2UTgKDyyNHZQ==" - }, - "node_modules/simple-swizzle": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz", - "integrity": "sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==", - "dependencies": { - "is-arrayish": "^0.3.1" - } - }, - "node_modules/simple-update-notifier": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/simple-update-notifier/-/simple-update-notifier-2.0.0.tgz", - "integrity": "sha512-a2B9Y0KlNXl9u/vsW6sTIu9vGEpfKu2wRV6l1H3XEas/0gUIzGzBoP/IouTcUQbm9JWZLH3COxyn03TYlFax6w==", - "dev": true, - "dependencies": { - "semver": "^7.5.3" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/slash": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/smart-buffer": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz", - "integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==", - "engines": { - "node": ">= 6.0.0", - "npm": ">= 3.0.0" - } - }, - "node_modules/socks": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/socks/-/socks-2.7.1.tgz", - "integrity": "sha512-7maUZy1N7uo6+WVEX6psASxtNlKaNVMlGQKkG/63nEDdLOWNbiUMoLK7X4uYoLhQstau72mLgfEWcXcwsaHbYQ==", - "dependencies": { - "ip": "^2.0.0", - "smart-buffer": "^4.2.0" - }, - "engines": { - "node": ">= 10.13.0", - "npm": ">= 3.0.0" - } - }, - "node_modules/source-map-js": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", - "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/sparse-bitfield": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/sparse-bitfield/-/sparse-bitfield-3.0.3.tgz", - "integrity": "sha512-kvzhi7vqKTfkh0PZU+2D2PIllw2ymqJKujUcyPMd9Y75Nv4nPbGJZXNhxsgdQab2BmlDct1YnfQCguEvHr7VsQ==", - "dependencies": { - "memory-pager": "^1.0.2" - } - }, - "node_modules/stack-trace": { - "version": "0.0.10", - "resolved": "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.10.tgz", - "integrity": "sha512-KGzahc7puUKkzyMt+IqAep+TVNbKP+k2Lmwhub39m1AsTSkaDutx56aDCo+HLDzf/D26BIHTJWNiTG1KAJiQCg==", - "engines": { - "node": "*" - } - }, - "node_modules/stream-browserify": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/stream-browserify/-/stream-browserify-3.0.0.tgz", - "integrity": "sha512-H73RAHsVBapbim0tU2JwwOiXUj+fikfiaoYAKHF3VJfA0pe2BCzkhAHBlLG6REzE+2WNZcxOXjK7lkso+9euLA==", - "dependencies": { - "inherits": "~2.0.4", - "readable-stream": "^3.5.0" - } - }, - "node_modules/string_decoder": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", - "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", - "dependencies": { - "safe-buffer": "~5.2.0" - } - }, - "node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/strip-json-comments": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", - "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", - "dev": true, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/strnum": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/strnum/-/strnum-1.0.5.tgz", - "integrity": "sha512-J8bbNyKKXl5qYcR36TIO8W3mVGVHrmmxsd5PAItGkmyzwJvybiw2IVq5nqd0i4LSNSkB/sx9VHllbfFdr9k1JA==" - }, - "node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/symbol-tree": { - "version": "3.2.4", - "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz", - "integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==" - }, - "node_modules/synckit": { - "version": "0.8.8", - "resolved": "https://registry.npmjs.org/synckit/-/synckit-0.8.8.tgz", - "integrity": "sha512-HwOKAP7Wc5aRGYdKH+dw0PRRpbO841v2DENBtjnR5HFWoiNByAl7vrx3p0G/rCyYXQsrxqtX48TImFtPcIHSpQ==", - "dev": true, - "dependencies": { - "@pkgr/core": "^0.1.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": "^14.18.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/unts" - } - }, - "node_modules/text-hex": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/text-hex/-/text-hex-1.0.0.tgz", - "integrity": "sha512-uuVGNWzgJ4yhRaNSiubPY7OjISw4sw4E5Uv0wbjp+OzcbmVU/rsT8ujgcXJhn9ypzsgr5vlzpPqP+MBBKcGvbg==" - }, - "node_modules/text-table": { - "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 - }, - "node_modules/to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "dev": true, - "dependencies": { - "is-number": "^7.0.0" - }, - "engines": { - "node": ">=8.0" - } - }, - "node_modules/touch": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/touch/-/touch-3.1.0.tgz", - "integrity": "sha512-WBx8Uy5TLtOSRtIq+M03/sKDrXCLHxwDcquSP2c43Le03/9serjQBIztjRz6FkJez9D/hleyAXTBGLwwZUw9lA==", - "dev": true, - "dependencies": { - "nopt": "~1.0.10" - }, - "bin": { - "nodetouch": "bin/nodetouch.js" - } - }, - "node_modules/tough-cookie": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.1.3.tgz", - "integrity": "sha512-aX/y5pVRkfRnfmuX+OdbSdXvPe6ieKX/G2s7e98f4poJHnqH3281gDPm/metm6E/WRamfx7WC4HUqkWHfQHprw==", - "dependencies": { - "psl": "^1.1.33", - "punycode": "^2.1.1", - "universalify": "^0.2.0", - "url-parse": "^1.5.3" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/tr46": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-3.0.0.tgz", - "integrity": "sha512-l7FvfAHlcmulp8kr+flpQZmVwtu7nfRV7NZujtN0OqES8EL4O4e0qqzL0DC5gAvx/ZC/9lk6rhcUwYvkBnBnYA==", - "dependencies": { - "punycode": "^2.1.1" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/triple-beam": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/triple-beam/-/triple-beam-1.4.1.tgz", - "integrity": "sha512-aZbgViZrg1QNcG+LULa7nhZpJTZSLm/mXnHXnbAbjmN5aSa0y7V+wvv6+4WaBtpISJzThKy+PIPxc1Nq1EJ9mg==", - "engines": { - "node": ">= 14.0.0" - } - }, - "node_modules/ts-api-utils": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.3.0.tgz", - "integrity": "sha512-UQMIo7pb8WRomKR1/+MFVLTroIvDVtMX3K6OUir8ynLyzB8Jeriont2bTAtmNPa1ekAgN7YPDyf6V+ygrdU+eQ==", - "dev": true, - "engines": { - "node": ">=16" - }, - "peerDependencies": { - "typescript": ">=4.2.0" - } - }, - "node_modules/ts-mixer": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/ts-mixer/-/ts-mixer-6.0.3.tgz", - "integrity": "sha512-k43M7uCG1AkTyxgnmI5MPwKoUvS/bRvLvUb7+Pgpdlmok8AoqmUaZxUUw8zKM5B1lqZrt41GjYgnvAi0fppqgQ==" - }, - "node_modules/ts-node": { - "version": "10.9.2", - "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.2.tgz", - "integrity": "sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==", - "dev": true, - "dependencies": { - "@cspotcode/source-map-support": "^0.8.0", - "@tsconfig/node10": "^1.0.7", - "@tsconfig/node12": "^1.0.7", - "@tsconfig/node14": "^1.0.0", - "@tsconfig/node16": "^1.0.2", - "acorn": "^8.4.1", - "acorn-walk": "^8.1.1", - "arg": "^4.1.0", - "create-require": "^1.1.0", - "diff": "^4.0.1", - "make-error": "^1.1.1", - "v8-compile-cache-lib": "^3.0.1", - "yn": "3.1.1" - }, - "bin": { - "ts-node": "dist/bin.js", - "ts-node-cwd": "dist/bin-cwd.js", - "ts-node-esm": "dist/bin-esm.js", - "ts-node-script": "dist/bin-script.js", - "ts-node-transpile-only": "dist/bin-transpile.js", - "ts-script": "dist/bin-script-deprecated.js" - }, - "peerDependencies": { - "@swc/core": ">=1.2.50", - "@swc/wasm": ">=1.2.50", - "@types/node": "*", - "typescript": ">=2.7" - }, - "peerDependenciesMeta": { - "@swc/core": { - "optional": true - }, - "@swc/wasm": { - "optional": true - } - } - }, - "node_modules/tslib": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", - "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==" - }, - "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, - "dependencies": { - "prelude-ls": "^1.2.1" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/typescript": { - "version": "5.4.5", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.4.5.tgz", - "integrity": "sha512-vcI4UpRgg81oIRUFwR0WSIHKt11nJ7SAVlYNIu+QpqeyXP+gpQJy/Z4+F0aGxSE4MqwjyXvW/TzgkLAx2AGHwQ==", - "dev": true, - "bin": { - "tsc": "bin/tsc", - "tsserver": "bin/tsserver" - }, - "engines": { - "node": ">=14.17" - } - }, - "node_modules/typescript-eslint": { - "version": "8.0.0-alpha.30", - "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.0.0-alpha.30.tgz", - "integrity": "sha512-/vGhBMsK1TpadQh1eQ02c5pyiPGmKR9cVzX5C9plZ+LC0HPLpWoJbbTVfQN7BkIK7tUxDt2BFr3pFL5hDDrx7g==", - "dev": true, - "dependencies": { - "@typescript-eslint/eslint-plugin": "8.0.0-alpha.30", - "@typescript-eslint/parser": "8.0.0-alpha.30", - "@typescript-eslint/utils": "8.0.0-alpha.30" - }, - "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/typescript-eslint/node_modules/@typescript-eslint/eslint-plugin": { - "version": "8.0.0-alpha.30", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.0.0-alpha.30.tgz", - "integrity": "sha512-2CBUupdkfbE3eATph4QeZejvT+M+1bVur+zXlVx09WN31phap51ps/qemeclnCbGEz6kTgBDmScrr9XmmF8/Pg==", - "dev": true, - "dependencies": { - "@eslint-community/regexpp": "^4.10.0", - "@typescript-eslint/scope-manager": "8.0.0-alpha.30", - "@typescript-eslint/type-utils": "8.0.0-alpha.30", - "@typescript-eslint/utils": "8.0.0-alpha.30", - "@typescript-eslint/visitor-keys": "8.0.0-alpha.30", - "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.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "@typescript-eslint/parser": "^8.0.0 || ^8.0.0-alpha.0", - "eslint": "^8.57.0 || ^9.0.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/typescript-eslint/node_modules/@typescript-eslint/parser": { - "version": "8.0.0-alpha.30", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.0.0-alpha.30.tgz", - "integrity": "sha512-tAYgFmgXU1MlCK3nbblUvJlDSibBvxtAQXGrF3IG0KmnRza9FXILZifHWL0rrwacDn40K53K607Fk2QkMjiGgw==", - "dev": true, - "dependencies": { - "@typescript-eslint/scope-manager": "8.0.0-alpha.30", - "@typescript-eslint/types": "8.0.0-alpha.30", - "@typescript-eslint/typescript-estree": "8.0.0-alpha.30", - "@typescript-eslint/visitor-keys": "8.0.0-alpha.30", - "debug": "^4.3.4" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^8.57.0 || ^9.0.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/typescript-eslint/node_modules/@typescript-eslint/scope-manager": { - "version": "8.0.0-alpha.30", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.0.0-alpha.30.tgz", - "integrity": "sha512-FGW/iPWGyPFamAVZ60oCAthMqQrqafUGebF8UKuq/ha+e9SVG6YhJoRzurlQXOVf8dHfOhJ0ADMXyFnMc53clg==", - "dev": true, - "dependencies": { - "@typescript-eslint/types": "8.0.0-alpha.30", - "@typescript-eslint/visitor-keys": "8.0.0-alpha.30" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/typescript-eslint/node_modules/@typescript-eslint/types": { - "version": "8.0.0-alpha.30", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.0.0-alpha.30.tgz", - "integrity": "sha512-4WzLlw27SO9pK9UFj/Hu7WGo8WveT0SEiIpFVsV2WwtQmLps6kouwtVCB8GJPZKJyurhZhcqCoQVQFmpv441Vg==", - "dev": true, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/typescript-eslint/node_modules/@typescript-eslint/typescript-estree": { - "version": "8.0.0-alpha.30", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.0.0-alpha.30.tgz", - "integrity": "sha512-WSXbc9ZcXI+7yC+6q95u77i8FXz6HOLsw3ST+vMUlFy1lFbXyFL/3e6HDKQCm2Clt0krnoCPiTGvIn+GkYPn4Q==", - "dev": true, - "dependencies": { - "@typescript-eslint/types": "8.0.0-alpha.30", - "@typescript-eslint/visitor-keys": "8.0.0-alpha.30", - "debug": "^4.3.4", - "globby": "^11.1.0", - "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.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/typescript-eslint/node_modules/@typescript-eslint/visitor-keys": { - "version": "8.0.0-alpha.30", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.0.0-alpha.30.tgz", - "integrity": "sha512-XZuNurZxBqmr6ZIRIwWFq7j5RZd6ZlkId/HZEWyfciK+CWoyOxSF9Pv2VXH9Rlu2ZG2PfbhLz2Veszl4Pfn7yA==", - "dev": true, - "dependencies": { - "@typescript-eslint/types": "8.0.0-alpha.30", - "eslint-visitor-keys": "^3.4.3" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/typescript-eslint/node_modules/minimatch": { - "version": "9.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.4.tgz", - "integrity": "sha512-KqWh+VchfxcMNRAJjj2tnsSJdNbHsVgnkBhTNrW7AjVo6OvLtxw8zfT9oLw1JSohlFzJ8jCoTgaoXvJ+kHt6fw==", - "dev": true, - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/undefsafe": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/undefsafe/-/undefsafe-2.0.5.tgz", - "integrity": "sha512-WxONCrssBM8TSPRqN5EmsjVrsv4A8X12J4ArBiiayv3DyyG3ZlIg6yysuuSYdZsVz3TKcTg2fd//Ujd4CHV1iA==", - "dev": true - }, - "node_modules/undici": { - "version": "5.27.2", - "resolved": "https://registry.npmjs.org/undici/-/undici-5.27.2.tgz", - "integrity": "sha512-iS857PdOEy/y3wlM3yRp+6SNQQ6xU0mmZcwRSriqk+et/cwWAtwmIGf6WkoDN2EK/AMdCO/dfXzIwi+rFMrjjQ==", - "dependencies": { - "@fastify/busboy": "^2.0.0" - }, - "engines": { - "node": ">=14.0" - } - }, - "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==" - }, - "node_modules/universal-user-agent": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/universal-user-agent/-/universal-user-agent-6.0.1.tgz", - "integrity": "sha512-yCzhz6FN2wU1NiiQRogkTQszlQSlpWaw8SvVegAc+bDxbzHgh1vX8uIe8OYyMH6DwH+sdTJsgMl36+mSMdRJIQ==" - }, - "node_modules/universalify": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.2.0.tgz", - "integrity": "sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg==", - "engines": { - "node": ">= 4.0.0" - } - }, - "node_modules/uri-js": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", - "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", - "dev": true, - "dependencies": { - "punycode": "^2.1.0" - } - }, - "node_modules/url-parse": { - "version": "1.5.10", - "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.10.tgz", - "integrity": "sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==", - "dependencies": { - "querystringify": "^2.1.1", - "requires-port": "^1.0.0" - } - }, - "node_modules/util-deprecate": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" - }, - "node_modules/uuid": { - "version": "8.3.2", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", - "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", - "bin": { - "uuid": "dist/bin/uuid" - } - }, - "node_modules/v8-compile-cache-lib": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", - "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==", - "dev": true - }, - "node_modules/w3c-xmlserializer": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-5.0.0.tgz", - "integrity": "sha512-o8qghlI8NZHU1lLPrpi2+Uq7abh4GGPpYANlalzWxyWteJOCsr/P+oPBA49TOLu5FTZO4d3F9MnWJfiMo4BkmA==", - "dependencies": { - "xml-name-validator": "^5.0.0" - }, - "engines": { - "node": ">=18" - } - }, - "node_modules/webidl-conversions": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz", - "integrity": "sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==", - "engines": { - "node": ">=12" - } - }, - "node_modules/whatwg-encoding": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-3.1.1.tgz", - "integrity": "sha512-6qN4hJdMwfYBtE3YBTTHhoeuUrDBPZmbQaxWAqSALV/MeEnR5z1xd8UKud2RAkFoPkmB+hli1TZSnyi84xz1vQ==", - "dependencies": { - "iconv-lite": "0.6.3" - }, - "engines": { - "node": ">=18" - } - }, - "node_modules/whatwg-mimetype": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-4.0.0.tgz", - "integrity": "sha512-QaKxh0eNIi2mE9p2vEdzfagOKHCcj1pJ56EEHGQOVxp8r9/iszLUUV7v89x9O1p/T+NlTM5W7jW6+cz4Fq1YVg==", - "engines": { - "node": ">=18" - } - }, - "node_modules/whatwg-url": { - "version": "11.0.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-11.0.0.tgz", - "integrity": "sha512-RKT8HExMpoYx4igMiVMY83lN6UeITKJlBQ+vR/8ZJ8OCdSiN3RwCq+9gH0+Xzj0+5IrM6i4j/6LuvzbZIQgEcQ==", - "dependencies": { - "tr46": "^3.0.0", - "webidl-conversions": "^7.0.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/which": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "dev": true, - "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "node-which": "bin/node-which" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/winston": { - "version": "3.11.0", - "resolved": "https://registry.npmjs.org/winston/-/winston-3.11.0.tgz", - "integrity": "sha512-L3yR6/MzZAOl0DsysUXHVjOwv8mKZ71TrA/41EIduGpOOV5LQVodqN+QdQ6BS6PJ/RdIshZhq84P/fStEZkk7g==", - "dependencies": { - "@colors/colors": "^1.6.0", - "@dabh/diagnostics": "^2.0.2", - "async": "^3.2.3", - "is-stream": "^2.0.0", - "logform": "^2.4.0", - "one-time": "^1.0.0", - "readable-stream": "^3.4.0", - "safe-stable-stringify": "^2.3.1", - "stack-trace": "0.0.x", - "triple-beam": "^1.3.0", - "winston-transport": "^4.5.0" - }, - "engines": { - "node": ">= 12.0.0" - } - }, - "node_modules/winston-transport": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/winston-transport/-/winston-transport-4.6.0.tgz", - "integrity": "sha512-wbBA9PbPAHxKiygo7ub7BYRiKxms0tpfU2ljtWzb3SjRjv5yl6Ozuy/TkXf00HTAt+Uylo3gSkNwzc4ME0wiIg==", - "dependencies": { - "logform": "^2.3.2", - "readable-stream": "^3.6.0", - "triple-beam": "^1.3.0" - }, - "engines": { - "node": ">= 12.0.0" - } - }, - "node_modules/wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==" - }, - "node_modules/ws": { - "version": "8.14.2", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.14.2.tgz", - "integrity": "sha512-wEBG1ftX4jcglPxgFCMJmZ2PLtSbJ2Peg6TmpJFTbe9GZYOQCDPdMYu/Tm0/bGZkw8paZnJY45J4K2PZrLYq8g==", - "engines": { - "node": ">=10.0.0" - }, - "peerDependencies": { - "bufferutil": "^4.0.1", - "utf-8-validate": ">=5.0.2" - }, - "peerDependenciesMeta": { - "bufferutil": { - "optional": true - }, - "utf-8-validate": { - "optional": true + "name": "fbw-discord-bot", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "fbw-discord-bot", + "version": "1.0.0", + "license": "AGPL-3.0", + "dependencies": { + "@aws-sdk/client-s3": "^3.499.0", + "@aws-sdk/lib-storage": "^3.499.0", + "@hokify/agenda": "^6.0.0", + "@octokit/request": "^8.1.1", + "bad-words": "^3.0.4", + "config": "^3.3.9", + "discord.js": "^14.11.0", + "jsdom": "^23.2.0", + "moment": "^2.29.4", + "mongoose": "^8.0.3", + "node-fetch": "^2.6.10", + "winston": "^3.3.4" + }, + "devDependencies": { + "@eslint/js": "^9.3.0", + "@types/bad-words": "^3.0.3", + "@types/config": "^3.3.1", + "@types/jsdom": "^21.1.6", + "@types/node": "^18.0.0", + "@types/node-fetch": "^2.6.10", + "dotenv": "^16.0.0", + "eslint": "^9.4.0", + "eslint-config-prettier": "^9.1.0", + "eslint-plugin-prettier": "^5.1.3", + "nodemon": "^3.0.2", + "prettier": "^3.3.2", + "ts-node": "^10.4.0", + "typescript": "^5.4.5", + "typescript-eslint": "^8.0.0-alpha.30" + }, + "engines": { + "node": "18.x" + } + }, + "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/@asamuzakjp/dom-selector": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@asamuzakjp/dom-selector/-/dom-selector-2.0.2.tgz", + "integrity": "sha512-x1KXOatwofR6ZAYzXRBL5wrdV0vwNxlTCK9NCuLqAzQYARqGcvFwiJA6A1ERuh+dgeA4Dxm3JBYictIes+SqUQ==", + "dependencies": { + "bidi-js": "^1.0.3", + "css-tree": "^2.3.1", + "is-potential-custom-element-name": "^1.0.1" + } + }, + "node_modules/@aws-crypto/crc32": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@aws-crypto/crc32/-/crc32-3.0.0.tgz", + "integrity": "sha512-IzSgsrxUcsrejQbPVilIKy16kAT52EwB6zSaI+M3xxIhKh5+aldEyvI+z6erM7TCLB2BJsFrtHjp6/4/sr+3dA==", + "dependencies": { + "@aws-crypto/util": "^3.0.0", + "@aws-sdk/types": "^3.222.0", + "tslib": "^1.11.1" + } + }, + "node_modules/@aws-crypto/crc32/node_modules/tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" + }, + "node_modules/@aws-crypto/crc32c": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@aws-crypto/crc32c/-/crc32c-3.0.0.tgz", + "integrity": "sha512-ENNPPManmnVJ4BTXlOjAgD7URidbAznURqD0KvfREyc4o20DPYdEldU1f5cQ7Jbj0CJJSPaMIk/9ZshdB3210w==", + "dependencies": { + "@aws-crypto/util": "^3.0.0", + "@aws-sdk/types": "^3.222.0", + "tslib": "^1.11.1" + } + }, + "node_modules/@aws-crypto/crc32c/node_modules/tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" + }, + "node_modules/@aws-crypto/ie11-detection": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@aws-crypto/ie11-detection/-/ie11-detection-3.0.0.tgz", + "integrity": "sha512-341lBBkiY1DfDNKai/wXM3aujNBkXR7tq1URPQDL9wi3AUbI80NR74uF1TXHMm7po1AcnFk8iu2S2IeU/+/A+Q==", + "dependencies": { + "tslib": "^1.11.1" + } + }, + "node_modules/@aws-crypto/ie11-detection/node_modules/tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" + }, + "node_modules/@aws-crypto/sha1-browser": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@aws-crypto/sha1-browser/-/sha1-browser-3.0.0.tgz", + "integrity": "sha512-NJth5c997GLHs6nOYTzFKTbYdMNA6/1XlKVgnZoaZcQ7z7UJlOgj2JdbHE8tiYLS3fzXNCguct77SPGat2raSw==", + "dependencies": { + "@aws-crypto/ie11-detection": "^3.0.0", + "@aws-crypto/supports-web-crypto": "^3.0.0", + "@aws-crypto/util": "^3.0.0", + "@aws-sdk/types": "^3.222.0", + "@aws-sdk/util-locate-window": "^3.0.0", + "@aws-sdk/util-utf8-browser": "^3.0.0", + "tslib": "^1.11.1" + } + }, + "node_modules/@aws-crypto/sha1-browser/node_modules/tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" + }, + "node_modules/@aws-crypto/sha256-browser": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@aws-crypto/sha256-browser/-/sha256-browser-3.0.0.tgz", + "integrity": "sha512-8VLmW2B+gjFbU5uMeqtQM6Nj0/F1bro80xQXCW6CQBWgosFWXTx77aeOF5CAIAmbOK64SdMBJdNr6J41yP5mvQ==", + "dependencies": { + "@aws-crypto/ie11-detection": "^3.0.0", + "@aws-crypto/sha256-js": "^3.0.0", + "@aws-crypto/supports-web-crypto": "^3.0.0", + "@aws-crypto/util": "^3.0.0", + "@aws-sdk/types": "^3.222.0", + "@aws-sdk/util-locate-window": "^3.0.0", + "@aws-sdk/util-utf8-browser": "^3.0.0", + "tslib": "^1.11.1" + } + }, + "node_modules/@aws-crypto/sha256-browser/node_modules/tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" + }, + "node_modules/@aws-crypto/sha256-js": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@aws-crypto/sha256-js/-/sha256-js-3.0.0.tgz", + "integrity": "sha512-PnNN7os0+yd1XvXAy23CFOmTbMaDxgxXtTKHybrJ39Y8kGzBATgBFibWJKH6BhytLI/Zyszs87xCOBNyBig6vQ==", + "dependencies": { + "@aws-crypto/util": "^3.0.0", + "@aws-sdk/types": "^3.222.0", + "tslib": "^1.11.1" + } + }, + "node_modules/@aws-crypto/sha256-js/node_modules/tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" + }, + "node_modules/@aws-crypto/supports-web-crypto": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@aws-crypto/supports-web-crypto/-/supports-web-crypto-3.0.0.tgz", + "integrity": "sha512-06hBdMwUAb2WFTuGG73LSC0wfPu93xWwo5vL2et9eymgmu3Id5vFAHBbajVWiGhPO37qcsdCap/FqXvJGJWPIg==", + "dependencies": { + "tslib": "^1.11.1" + } + }, + "node_modules/@aws-crypto/supports-web-crypto/node_modules/tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" + }, + "node_modules/@aws-crypto/util": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@aws-crypto/util/-/util-3.0.0.tgz", + "integrity": "sha512-2OJlpeJpCR48CC8r+uKVChzs9Iungj9wkZrl8Z041DWEWvyIHILYKCPNzJghKsivj+S3mLo6BVc7mBNzdxA46w==", + "dependencies": { + "@aws-sdk/types": "^3.222.0", + "@aws-sdk/util-utf8-browser": "^3.0.0", + "tslib": "^1.11.1" + } + }, + "node_modules/@aws-crypto/util/node_modules/tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" + }, + "node_modules/@aws-sdk/client-cognito-identity": { + "version": "3.485.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-cognito-identity/-/client-cognito-identity-3.485.0.tgz", + "integrity": "sha512-1SYhvRu/dNqQ5HcIgm7wIpyn1FsthbgG04o6QyVAnfOxmawFt4nqCEtNCwsmlX7o1ZCTYY+qNrozb7XZy+GKSQ==", + "optional": true, + "dependencies": { + "@aws-crypto/sha256-browser": "3.0.0", + "@aws-crypto/sha256-js": "3.0.0", + "@aws-sdk/client-sts": "3.485.0", + "@aws-sdk/core": "3.485.0", + "@aws-sdk/credential-provider-node": "3.485.0", + "@aws-sdk/middleware-host-header": "3.485.0", + "@aws-sdk/middleware-logger": "3.485.0", + "@aws-sdk/middleware-recursion-detection": "3.485.0", + "@aws-sdk/middleware-signing": "3.485.0", + "@aws-sdk/middleware-user-agent": "3.485.0", + "@aws-sdk/region-config-resolver": "3.485.0", + "@aws-sdk/types": "3.485.0", + "@aws-sdk/util-endpoints": "3.485.0", + "@aws-sdk/util-user-agent-browser": "3.485.0", + "@aws-sdk/util-user-agent-node": "3.485.0", + "@smithy/config-resolver": "^2.0.23", + "@smithy/core": "^1.2.2", + "@smithy/fetch-http-handler": "^2.3.2", + "@smithy/hash-node": "^2.0.18", + "@smithy/invalid-dependency": "^2.0.16", + "@smithy/middleware-content-length": "^2.0.18", + "@smithy/middleware-endpoint": "^2.3.0", + "@smithy/middleware-retry": "^2.0.26", + "@smithy/middleware-serde": "^2.0.16", + "@smithy/middleware-stack": "^2.0.10", + "@smithy/node-config-provider": "^2.1.9", + "@smithy/node-http-handler": "^2.2.2", + "@smithy/protocol-http": "^3.0.12", + "@smithy/smithy-client": "^2.2.1", + "@smithy/types": "^2.8.0", + "@smithy/url-parser": "^2.0.16", + "@smithy/util-base64": "^2.0.1", + "@smithy/util-body-length-browser": "^2.0.1", + "@smithy/util-body-length-node": "^2.1.0", + "@smithy/util-defaults-mode-browser": "^2.0.24", + "@smithy/util-defaults-mode-node": "^2.0.32", + "@smithy/util-endpoints": "^1.0.8", + "@smithy/util-retry": "^2.0.9", + "@smithy/util-utf8": "^2.0.2", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/client-s3": { + "version": "3.499.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-s3/-/client-s3-3.499.0.tgz", + "integrity": "sha512-4ssQqde/iY5fTJbWuFPzPuECtihdCAA9tfluv6fXYCJS3wMLf9x21qp6b7fIbUf6vjOJ2edmYd+DXk+0CMnTFg==", + "dependencies": { + "@aws-crypto/sha1-browser": "3.0.0", + "@aws-crypto/sha256-browser": "3.0.0", + "@aws-crypto/sha256-js": "3.0.0", + "@aws-sdk/client-sts": "3.499.0", + "@aws-sdk/core": "3.496.0", + "@aws-sdk/credential-provider-node": "3.499.0", + "@aws-sdk/middleware-bucket-endpoint": "3.496.0", + "@aws-sdk/middleware-expect-continue": "3.496.0", + "@aws-sdk/middleware-flexible-checksums": "3.496.0", + "@aws-sdk/middleware-host-header": "3.496.0", + "@aws-sdk/middleware-location-constraint": "3.496.0", + "@aws-sdk/middleware-logger": "3.496.0", + "@aws-sdk/middleware-recursion-detection": "3.496.0", + "@aws-sdk/middleware-sdk-s3": "3.499.0", + "@aws-sdk/middleware-signing": "3.496.0", + "@aws-sdk/middleware-ssec": "3.498.0", + "@aws-sdk/middleware-user-agent": "3.496.0", + "@aws-sdk/region-config-resolver": "3.496.0", + "@aws-sdk/signature-v4-multi-region": "3.499.0", + "@aws-sdk/types": "3.496.0", + "@aws-sdk/util-endpoints": "3.496.0", + "@aws-sdk/util-user-agent-browser": "3.496.0", + "@aws-sdk/util-user-agent-node": "3.496.0", + "@aws-sdk/xml-builder": "3.496.0", + "@smithy/config-resolver": "^2.1.1", + "@smithy/core": "^1.3.1", + "@smithy/eventstream-serde-browser": "^2.1.1", + "@smithy/eventstream-serde-config-resolver": "^2.1.1", + "@smithy/eventstream-serde-node": "^2.1.1", + "@smithy/fetch-http-handler": "^2.4.1", + "@smithy/hash-blob-browser": "^2.1.1", + "@smithy/hash-node": "^2.1.1", + "@smithy/hash-stream-node": "^2.1.1", + "@smithy/invalid-dependency": "^2.1.1", + "@smithy/md5-js": "^2.1.1", + "@smithy/middleware-content-length": "^2.1.1", + "@smithy/middleware-endpoint": "^2.4.1", + "@smithy/middleware-retry": "^2.1.1", + "@smithy/middleware-serde": "^2.1.1", + "@smithy/middleware-stack": "^2.1.1", + "@smithy/node-config-provider": "^2.2.1", + "@smithy/node-http-handler": "^2.3.1", + "@smithy/protocol-http": "^3.1.1", + "@smithy/smithy-client": "^2.3.1", + "@smithy/types": "^2.9.1", + "@smithy/url-parser": "^2.1.1", + "@smithy/util-base64": "^2.1.1", + "@smithy/util-body-length-browser": "^2.1.1", + "@smithy/util-body-length-node": "^2.2.1", + "@smithy/util-defaults-mode-browser": "^2.1.1", + "@smithy/util-defaults-mode-node": "^2.1.1", + "@smithy/util-endpoints": "^1.1.1", + "@smithy/util-retry": "^2.1.1", + "@smithy/util-stream": "^2.1.1", + "@smithy/util-utf8": "^2.1.1", + "@smithy/util-waiter": "^2.1.1", + "fast-xml-parser": "4.2.5", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/client-s3/node_modules/@aws-sdk/client-sso": { + "version": "3.496.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso/-/client-sso-3.496.0.tgz", + "integrity": "sha512-fuaMuxKg7CMUsP9l3kxYWCOxFsBjdA0xj5nlikaDm1661/gB4KkAiGqRY8LsQkpNXvXU8Nj+f7oCFADFyGYzyw==", + "dependencies": { + "@aws-crypto/sha256-browser": "3.0.0", + "@aws-crypto/sha256-js": "3.0.0", + "@aws-sdk/core": "3.496.0", + "@aws-sdk/middleware-host-header": "3.496.0", + "@aws-sdk/middleware-logger": "3.496.0", + "@aws-sdk/middleware-recursion-detection": "3.496.0", + "@aws-sdk/middleware-user-agent": "3.496.0", + "@aws-sdk/region-config-resolver": "3.496.0", + "@aws-sdk/types": "3.496.0", + "@aws-sdk/util-endpoints": "3.496.0", + "@aws-sdk/util-user-agent-browser": "3.496.0", + "@aws-sdk/util-user-agent-node": "3.496.0", + "@smithy/config-resolver": "^2.1.1", + "@smithy/core": "^1.3.1", + "@smithy/fetch-http-handler": "^2.4.1", + "@smithy/hash-node": "^2.1.1", + "@smithy/invalid-dependency": "^2.1.1", + "@smithy/middleware-content-length": "^2.1.1", + "@smithy/middleware-endpoint": "^2.4.1", + "@smithy/middleware-retry": "^2.1.1", + "@smithy/middleware-serde": "^2.1.1", + "@smithy/middleware-stack": "^2.1.1", + "@smithy/node-config-provider": "^2.2.1", + "@smithy/node-http-handler": "^2.3.1", + "@smithy/protocol-http": "^3.1.1", + "@smithy/smithy-client": "^2.3.1", + "@smithy/types": "^2.9.1", + "@smithy/url-parser": "^2.1.1", + "@smithy/util-base64": "^2.1.1", + "@smithy/util-body-length-browser": "^2.1.1", + "@smithy/util-body-length-node": "^2.2.1", + "@smithy/util-defaults-mode-browser": "^2.1.1", + "@smithy/util-defaults-mode-node": "^2.1.1", + "@smithy/util-endpoints": "^1.1.1", + "@smithy/util-retry": "^2.1.1", + "@smithy/util-utf8": "^2.1.1", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/client-s3/node_modules/@aws-sdk/client-sts": { + "version": "3.499.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-sts/-/client-sts-3.499.0.tgz", + "integrity": "sha512-Eyj9STw2DXMtXL5V/v0HYHO6+JjGPi257M5IYyxwqlvRchq6jbOsedobfxclB/gBUyBRtZdnyAIS8uCKjb4kpA==", + "dependencies": { + "@aws-crypto/sha256-browser": "3.0.0", + "@aws-crypto/sha256-js": "3.0.0", + "@aws-sdk/core": "3.496.0", + "@aws-sdk/credential-provider-node": "3.499.0", + "@aws-sdk/middleware-host-header": "3.496.0", + "@aws-sdk/middleware-logger": "3.496.0", + "@aws-sdk/middleware-recursion-detection": "3.496.0", + "@aws-sdk/middleware-user-agent": "3.496.0", + "@aws-sdk/region-config-resolver": "3.496.0", + "@aws-sdk/types": "3.496.0", + "@aws-sdk/util-endpoints": "3.496.0", + "@aws-sdk/util-user-agent-browser": "3.496.0", + "@aws-sdk/util-user-agent-node": "3.496.0", + "@smithy/config-resolver": "^2.1.1", + "@smithy/core": "^1.3.1", + "@smithy/fetch-http-handler": "^2.4.1", + "@smithy/hash-node": "^2.1.1", + "@smithy/invalid-dependency": "^2.1.1", + "@smithy/middleware-content-length": "^2.1.1", + "@smithy/middleware-endpoint": "^2.4.1", + "@smithy/middleware-retry": "^2.1.1", + "@smithy/middleware-serde": "^2.1.1", + "@smithy/middleware-stack": "^2.1.1", + "@smithy/node-config-provider": "^2.2.1", + "@smithy/node-http-handler": "^2.3.1", + "@smithy/protocol-http": "^3.1.1", + "@smithy/smithy-client": "^2.3.1", + "@smithy/types": "^2.9.1", + "@smithy/url-parser": "^2.1.1", + "@smithy/util-base64": "^2.1.1", + "@smithy/util-body-length-browser": "^2.1.1", + "@smithy/util-body-length-node": "^2.2.1", + "@smithy/util-defaults-mode-browser": "^2.1.1", + "@smithy/util-defaults-mode-node": "^2.1.1", + "@smithy/util-endpoints": "^1.1.1", + "@smithy/util-middleware": "^2.1.1", + "@smithy/util-retry": "^2.1.1", + "@smithy/util-utf8": "^2.1.1", + "fast-xml-parser": "4.2.5", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/client-s3/node_modules/@aws-sdk/core": { + "version": "3.496.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/core/-/core-3.496.0.tgz", + "integrity": "sha512-yT+ug7Cw/3eJi7x2es0+46x12+cIJm5Xv+GPWsrTFD1TKgqO/VPEgfDtHFagDNbFmjNQA65Ygc/kEdIX9ICX/A==", + "dependencies": { + "@smithy/core": "^1.3.1", + "@smithy/protocol-http": "^3.1.1", + "@smithy/signature-v4": "^2.1.1", + "@smithy/smithy-client": "^2.3.1", + "@smithy/types": "^2.9.1", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/client-s3/node_modules/@aws-sdk/credential-provider-env": { + "version": "3.496.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-env/-/credential-provider-env-3.496.0.tgz", + "integrity": "sha512-lukQMJ8SWWP5RqkRNOHi/H+WMhRvSWa3Fc5Jf/VP6xHiPLfF1XafcvthtV91e0VwPCiseI+HqChrcGq8pvnxHw==", + "dependencies": { + "@aws-sdk/types": "3.496.0", + "@smithy/property-provider": "^2.1.1", + "@smithy/types": "^2.9.1", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/client-s3/node_modules/@aws-sdk/credential-provider-ini": { + "version": "3.496.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-ini/-/credential-provider-ini-3.496.0.tgz", + "integrity": "sha512-2nD1jp1sIwcQaWK1y/9ruQOkW16RUxZpzgjbW/gnK3iiUXwx+/FNQWxshud+GTSx3Q4x6eIhqsbjtP4VVPPuUA==", + "dependencies": { + "@aws-sdk/credential-provider-env": "3.496.0", + "@aws-sdk/credential-provider-process": "3.496.0", + "@aws-sdk/credential-provider-sso": "3.496.0", + "@aws-sdk/credential-provider-web-identity": "3.496.0", + "@aws-sdk/types": "3.496.0", + "@smithy/credential-provider-imds": "^2.2.1", + "@smithy/property-provider": "^2.1.1", + "@smithy/shared-ini-file-loader": "^2.3.1", + "@smithy/types": "^2.9.1", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/client-s3/node_modules/@aws-sdk/credential-provider-node": { + "version": "3.499.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-node/-/credential-provider-node-3.499.0.tgz", + "integrity": "sha512-EsiSevVmcVSMIq7D9siSH/XVc5I0vMntg1rx6KQdng1Fq8X/RBL5t9wSWEwOl7KFo5HlEsWrLWIpo1WHuzIL/w==", + "dependencies": { + "@aws-sdk/credential-provider-env": "3.496.0", + "@aws-sdk/credential-provider-ini": "3.496.0", + "@aws-sdk/credential-provider-process": "3.496.0", + "@aws-sdk/credential-provider-sso": "3.496.0", + "@aws-sdk/credential-provider-web-identity": "3.496.0", + "@aws-sdk/types": "3.496.0", + "@smithy/credential-provider-imds": "^2.2.1", + "@smithy/property-provider": "^2.1.1", + "@smithy/shared-ini-file-loader": "^2.3.1", + "@smithy/types": "^2.9.1", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/client-s3/node_modules/@aws-sdk/credential-provider-process": { + "version": "3.496.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-process/-/credential-provider-process-3.496.0.tgz", + "integrity": "sha512-/YZscCTGOKVmGr916Th4XF8Sz6JDtZ/n2loHG9exok9iy/qIbACsTRNLP9zexPxhPoue/oZqecY5xbVljfY34A==", + "dependencies": { + "@aws-sdk/types": "3.496.0", + "@smithy/property-provider": "^2.1.1", + "@smithy/shared-ini-file-loader": "^2.3.1", + "@smithy/types": "^2.9.1", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/client-s3/node_modules/@aws-sdk/credential-provider-sso": { + "version": "3.496.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-sso/-/credential-provider-sso-3.496.0.tgz", + "integrity": "sha512-eP7GxpT2QYubSDG7uk1GJW4eNymZCq65IxDyEFCXOP/kfqkxriCY+iVEFG6/Mo3LxvgrgHXU4jxrCAXMAWN43g==", + "dependencies": { + "@aws-sdk/client-sso": "3.496.0", + "@aws-sdk/token-providers": "3.496.0", + "@aws-sdk/types": "3.496.0", + "@smithy/property-provider": "^2.1.1", + "@smithy/shared-ini-file-loader": "^2.3.1", + "@smithy/types": "^2.9.1", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/client-s3/node_modules/@aws-sdk/credential-provider-web-identity": { + "version": "3.496.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-web-identity/-/credential-provider-web-identity-3.496.0.tgz", + "integrity": "sha512-IbP+qLlvJSpNPj+zW6TtFuLRTK5Tf0hW+2pom4vFyi5YSH4pn8UOC136UdewX8vhXGS9BJQ5zBDMasIyl5VeGQ==", + "dependencies": { + "@aws-sdk/types": "3.496.0", + "@smithy/property-provider": "^2.1.1", + "@smithy/types": "^2.9.1", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/client-s3/node_modules/@aws-sdk/middleware-host-header": { + "version": "3.496.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-host-header/-/middleware-host-header-3.496.0.tgz", + "integrity": "sha512-jUdPpSJeqCYXf6hSjfwsfHway7peIV8Vz51w/BN91bF4vB/bYwAC5o9/iJiK/EoByp5asxA8fg9wFOyGjzdbLg==", + "dependencies": { + "@aws-sdk/types": "3.496.0", + "@smithy/protocol-http": "^3.1.1", + "@smithy/types": "^2.9.1", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/client-s3/node_modules/@aws-sdk/middleware-logger": { + "version": "3.496.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-logger/-/middleware-logger-3.496.0.tgz", + "integrity": "sha512-EwMVSY6iBMeGbVnvwdaFl/ClMS/YWtxCAo+bcEtgk8ltRuo7qgbJem8Km/fvWC1vdWvIbe4ArdJ8iGzq62ffAw==", + "dependencies": { + "@aws-sdk/types": "3.496.0", + "@smithy/types": "^2.9.1", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/client-s3/node_modules/@aws-sdk/middleware-recursion-detection": { + "version": "3.496.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-recursion-detection/-/middleware-recursion-detection-3.496.0.tgz", + "integrity": "sha512-+IuOcFsfqg2WAnaEzH6KhVbicqCxtOq9w3DH2jwTpddRlCx2Kqf6wCzg8luhHRGyjBZdsbIS+OXwyMevoppawA==", + "dependencies": { + "@aws-sdk/types": "3.496.0", + "@smithy/protocol-http": "^3.1.1", + "@smithy/types": "^2.9.1", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/client-s3/node_modules/@aws-sdk/middleware-signing": { + "version": "3.496.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-signing/-/middleware-signing-3.496.0.tgz", + "integrity": "sha512-Oq73Brs4IConvWnRlh8jM1V7LHoTw9SVQklu/QW2FPlNrB3B8fuTdWHHYIWv7ybw1bykXoCY99v865Mmq/Or/g==", + "dependencies": { + "@aws-sdk/types": "3.496.0", + "@smithy/property-provider": "^2.1.1", + "@smithy/protocol-http": "^3.1.1", + "@smithy/signature-v4": "^2.1.1", + "@smithy/types": "^2.9.1", + "@smithy/util-middleware": "^2.1.1", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/client-s3/node_modules/@aws-sdk/middleware-user-agent": { + "version": "3.496.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-user-agent/-/middleware-user-agent-3.496.0.tgz", + "integrity": "sha512-+iMtRxFk0GmFWNUF4ilxylOQd9PZdR4ZC9jkcPIh1PZlvKtpCyFywKlk5RRZKklSoJ/CttcqwhMvOXTNbWm/0w==", + "dependencies": { + "@aws-sdk/types": "3.496.0", + "@aws-sdk/util-endpoints": "3.496.0", + "@smithy/protocol-http": "^3.1.1", + "@smithy/types": "^2.9.1", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/client-s3/node_modules/@aws-sdk/region-config-resolver": { + "version": "3.496.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/region-config-resolver/-/region-config-resolver-3.496.0.tgz", + "integrity": "sha512-URrNVOPHPgEDm6QFu6lDC2cUFs+Jx23mA3jEwCvoKlXiEY/ZoWjH8wlX3OMUlLrF1qoUTuD03jjrJzF6zoCgug==", + "dependencies": { + "@aws-sdk/types": "3.496.0", + "@smithy/node-config-provider": "^2.2.1", + "@smithy/types": "^2.9.1", + "@smithy/util-config-provider": "^2.2.1", + "@smithy/util-middleware": "^2.1.1", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/client-s3/node_modules/@aws-sdk/token-providers": { + "version": "3.496.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/token-providers/-/token-providers-3.496.0.tgz", + "integrity": "sha512-fyi8RcObEa1jNETJdc2H6q9VHrrdKCj/b6+fbLvymb7mUVRd0aWUn+24SNUImnSOnrwYnwaMfyyEC388X4MbFQ==", + "dependencies": { + "@aws-crypto/sha256-browser": "3.0.0", + "@aws-crypto/sha256-js": "3.0.0", + "@aws-sdk/middleware-host-header": "3.496.0", + "@aws-sdk/middleware-logger": "3.496.0", + "@aws-sdk/middleware-recursion-detection": "3.496.0", + "@aws-sdk/middleware-user-agent": "3.496.0", + "@aws-sdk/region-config-resolver": "3.496.0", + "@aws-sdk/types": "3.496.0", + "@aws-sdk/util-endpoints": "3.496.0", + "@aws-sdk/util-user-agent-browser": "3.496.0", + "@aws-sdk/util-user-agent-node": "3.496.0", + "@smithy/config-resolver": "^2.1.1", + "@smithy/fetch-http-handler": "^2.4.1", + "@smithy/hash-node": "^2.1.1", + "@smithy/invalid-dependency": "^2.1.1", + "@smithy/middleware-content-length": "^2.1.1", + "@smithy/middleware-endpoint": "^2.4.1", + "@smithy/middleware-retry": "^2.1.1", + "@smithy/middleware-serde": "^2.1.1", + "@smithy/middleware-stack": "^2.1.1", + "@smithy/node-config-provider": "^2.2.1", + "@smithy/node-http-handler": "^2.3.1", + "@smithy/property-provider": "^2.1.1", + "@smithy/protocol-http": "^3.1.1", + "@smithy/shared-ini-file-loader": "^2.3.1", + "@smithy/smithy-client": "^2.3.1", + "@smithy/types": "^2.9.1", + "@smithy/url-parser": "^2.1.1", + "@smithy/util-base64": "^2.1.1", + "@smithy/util-body-length-browser": "^2.1.1", + "@smithy/util-body-length-node": "^2.2.1", + "@smithy/util-defaults-mode-browser": "^2.1.1", + "@smithy/util-defaults-mode-node": "^2.1.1", + "@smithy/util-endpoints": "^1.1.1", + "@smithy/util-retry": "^2.1.1", + "@smithy/util-utf8": "^2.1.1", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/client-s3/node_modules/@aws-sdk/types": { + "version": "3.496.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.496.0.tgz", + "integrity": "sha512-umkGadK4QuNQaMoDICMm7NKRI/mYSXiyPjcn3d53BhsuArYU/52CebGQKdt4At7SwwsiVJZw9RNBHyN5Mm0HVw==", + "dependencies": { + "@smithy/types": "^2.9.1", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/client-s3/node_modules/@aws-sdk/util-endpoints": { + "version": "3.496.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-endpoints/-/util-endpoints-3.496.0.tgz", + "integrity": "sha512-1QzOiWHi383ZwqSi/R2KgKCd7M+6DxkxI5acqLPm8mvDRDP2jRjrnVaC0g9/tlttWousGEemDUWStwrD2mVYSw==", + "dependencies": { + "@aws-sdk/types": "3.496.0", + "@smithy/types": "^2.9.1", + "@smithy/util-endpoints": "^1.1.1", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/client-s3/node_modules/@aws-sdk/util-user-agent-browser": { + "version": "3.496.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-browser/-/util-user-agent-browser-3.496.0.tgz", + "integrity": "sha512-4j2spN+h0I0qfSMsGvJXTfQBu1e18rPdekKvzsGJxhaAE1tNgUfUT4nbvc5uVn0sNjZmirskmJ3kfbzVOrqIFg==", + "dependencies": { + "@aws-sdk/types": "3.496.0", + "@smithy/types": "^2.9.1", + "bowser": "^2.11.0", + "tslib": "^2.5.0" + } + }, + "node_modules/@aws-sdk/client-s3/node_modules/@aws-sdk/util-user-agent-node": { + "version": "3.496.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-node/-/util-user-agent-node-3.496.0.tgz", + "integrity": "sha512-h0Ax0jlDc7UIo3KoSI4C4tVLBFoiAdx3+DhTVfgLS7x93d41dMlziPoBX2RgdcFn37qnzw6AQKTVTMwDbRCGpg==", + "dependencies": { + "@aws-sdk/types": "3.496.0", + "@smithy/node-config-provider": "^2.2.1", + "@smithy/types": "^2.9.1", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "aws-crt": ">=1.0.0" + }, + "peerDependenciesMeta": { + "aws-crt": { + "optional": true + } + } + }, + "node_modules/@aws-sdk/client-sso": { + "version": "3.485.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso/-/client-sso-3.485.0.tgz", + "integrity": "sha512-apN2bEn0PZs0jD4jAfvwO3dlWqw9YIQJ6TAudM1bd3S5vzWqlBBcLfQpK6taHoQaI+WqgUWXLuOf7gRFbGXKPg==", + "optional": true, + "dependencies": { + "@aws-crypto/sha256-browser": "3.0.0", + "@aws-crypto/sha256-js": "3.0.0", + "@aws-sdk/core": "3.485.0", + "@aws-sdk/middleware-host-header": "3.485.0", + "@aws-sdk/middleware-logger": "3.485.0", + "@aws-sdk/middleware-recursion-detection": "3.485.0", + "@aws-sdk/middleware-user-agent": "3.485.0", + "@aws-sdk/region-config-resolver": "3.485.0", + "@aws-sdk/types": "3.485.0", + "@aws-sdk/util-endpoints": "3.485.0", + "@aws-sdk/util-user-agent-browser": "3.485.0", + "@aws-sdk/util-user-agent-node": "3.485.0", + "@smithy/config-resolver": "^2.0.23", + "@smithy/core": "^1.2.2", + "@smithy/fetch-http-handler": "^2.3.2", + "@smithy/hash-node": "^2.0.18", + "@smithy/invalid-dependency": "^2.0.16", + "@smithy/middleware-content-length": "^2.0.18", + "@smithy/middleware-endpoint": "^2.3.0", + "@smithy/middleware-retry": "^2.0.26", + "@smithy/middleware-serde": "^2.0.16", + "@smithy/middleware-stack": "^2.0.10", + "@smithy/node-config-provider": "^2.1.9", + "@smithy/node-http-handler": "^2.2.2", + "@smithy/protocol-http": "^3.0.12", + "@smithy/smithy-client": "^2.2.1", + "@smithy/types": "^2.8.0", + "@smithy/url-parser": "^2.0.16", + "@smithy/util-base64": "^2.0.1", + "@smithy/util-body-length-browser": "^2.0.1", + "@smithy/util-body-length-node": "^2.1.0", + "@smithy/util-defaults-mode-browser": "^2.0.24", + "@smithy/util-defaults-mode-node": "^2.0.32", + "@smithy/util-endpoints": "^1.0.8", + "@smithy/util-retry": "^2.0.9", + "@smithy/util-utf8": "^2.0.2", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/client-sts": { + "version": "3.485.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-sts/-/client-sts-3.485.0.tgz", + "integrity": "sha512-PI4q36kVF0fpIPZyeQhrwwJZ6SRkOGvU3rX5Qn4b5UY5X+Ct1aLhqSX8/OB372UZIcnh6eSvERu8POHleDO7Jw==", + "optional": true, + "dependencies": { + "@aws-crypto/sha256-browser": "3.0.0", + "@aws-crypto/sha256-js": "3.0.0", + "@aws-sdk/core": "3.485.0", + "@aws-sdk/credential-provider-node": "3.485.0", + "@aws-sdk/middleware-host-header": "3.485.0", + "@aws-sdk/middleware-logger": "3.485.0", + "@aws-sdk/middleware-recursion-detection": "3.485.0", + "@aws-sdk/middleware-user-agent": "3.485.0", + "@aws-sdk/region-config-resolver": "3.485.0", + "@aws-sdk/types": "3.485.0", + "@aws-sdk/util-endpoints": "3.485.0", + "@aws-sdk/util-user-agent-browser": "3.485.0", + "@aws-sdk/util-user-agent-node": "3.485.0", + "@smithy/config-resolver": "^2.0.23", + "@smithy/core": "^1.2.2", + "@smithy/fetch-http-handler": "^2.3.2", + "@smithy/hash-node": "^2.0.18", + "@smithy/invalid-dependency": "^2.0.16", + "@smithy/middleware-content-length": "^2.0.18", + "@smithy/middleware-endpoint": "^2.3.0", + "@smithy/middleware-retry": "^2.0.26", + "@smithy/middleware-serde": "^2.0.16", + "@smithy/middleware-stack": "^2.0.10", + "@smithy/node-config-provider": "^2.1.9", + "@smithy/node-http-handler": "^2.2.2", + "@smithy/protocol-http": "^3.0.12", + "@smithy/smithy-client": "^2.2.1", + "@smithy/types": "^2.8.0", + "@smithy/url-parser": "^2.0.16", + "@smithy/util-base64": "^2.0.1", + "@smithy/util-body-length-browser": "^2.0.1", + "@smithy/util-body-length-node": "^2.1.0", + "@smithy/util-defaults-mode-browser": "^2.0.24", + "@smithy/util-defaults-mode-node": "^2.0.32", + "@smithy/util-endpoints": "^1.0.8", + "@smithy/util-middleware": "^2.0.9", + "@smithy/util-retry": "^2.0.9", + "@smithy/util-utf8": "^2.0.2", + "fast-xml-parser": "4.2.5", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/core": { + "version": "3.485.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/core/-/core-3.485.0.tgz", + "integrity": "sha512-Yvi80DQcbjkYCft471ClE3HuetuNVqntCs6eFOomDcrJaqdOFrXv2kJAxky84MRA/xb7bGlDGAPbTuj1ICputg==", + "optional": true, + "dependencies": { + "@smithy/core": "^1.2.2", + "@smithy/protocol-http": "^3.0.12", + "@smithy/signature-v4": "^2.0.0", + "@smithy/smithy-client": "^2.2.1", + "@smithy/types": "^2.8.0", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-cognito-identity": { + "version": "3.485.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-cognito-identity/-/credential-provider-cognito-identity-3.485.0.tgz", + "integrity": "sha512-XIy5h1AcDiY3V286X7KrLA5HAxLfzLGrUGBPFY+GTJGYetDhlJwFz12q6BOkIfeAhUbT2Umb4ptujX9eqpZJHQ==", + "optional": true, + "dependencies": { + "@aws-sdk/client-cognito-identity": "3.485.0", + "@aws-sdk/types": "3.485.0", + "@smithy/property-provider": "^2.0.0", + "@smithy/types": "^2.8.0", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-env": { + "version": "3.485.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-env/-/credential-provider-env-3.485.0.tgz", + "integrity": "sha512-3XkFgwVU1XOB33dV7t9BKJ/ptdl2iS+0dxE7ecq8aqT2/gsfKmLCae1G17P8WmdD3z0kMDTvnqM2aWgUnSOkmg==", + "optional": true, + "dependencies": { + "@aws-sdk/types": "3.485.0", + "@smithy/property-provider": "^2.0.0", + "@smithy/types": "^2.8.0", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-http": { + "version": "3.485.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-http/-/credential-provider-http-3.485.0.tgz", + "integrity": "sha512-2/2Y3Z7cpKf8vbQ+FzoBPxRyb0hGJZB1YrnH7hptVi5gSVe1NiwV5ZtsDnv4cwUfOBqEu97nMXw5IrRO26S0DA==", + "optional": true, + "dependencies": { + "@aws-sdk/types": "3.485.0", + "@smithy/fetch-http-handler": "^2.3.2", + "@smithy/node-http-handler": "^2.2.2", + "@smithy/property-provider": "^2.0.0", + "@smithy/protocol-http": "^3.0.12", + "@smithy/smithy-client": "^2.2.1", + "@smithy/types": "^2.8.0", + "@smithy/util-stream": "^2.0.24", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-ini": { + "version": "3.485.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-ini/-/credential-provider-ini-3.485.0.tgz", + "integrity": "sha512-cFYF/Bdw7EnT4viSxYpNIv3IBkri/Yb+JpQXl8uDq7bfVJfAN5qZmK07vRkg08xL6TC4F41wshhMSAucGdTwIw==", + "optional": true, + "dependencies": { + "@aws-sdk/credential-provider-env": "3.485.0", + "@aws-sdk/credential-provider-process": "3.485.0", + "@aws-sdk/credential-provider-sso": "3.485.0", + "@aws-sdk/credential-provider-web-identity": "3.485.0", + "@aws-sdk/types": "3.485.0", + "@smithy/credential-provider-imds": "^2.0.0", + "@smithy/property-provider": "^2.0.0", + "@smithy/shared-ini-file-loader": "^2.0.6", + "@smithy/types": "^2.8.0", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-node": { + "version": "3.485.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-node/-/credential-provider-node-3.485.0.tgz", + "integrity": "sha512-2DwzO2azkSzngifKDT61W/DL0tSzewuaFHiLJWdfc8Et3mdAQJ9x3KAj8u7XFpjIcGNqk7FiKjN+zeGUuNiEhA==", + "optional": true, + "dependencies": { + "@aws-sdk/credential-provider-env": "3.485.0", + "@aws-sdk/credential-provider-ini": "3.485.0", + "@aws-sdk/credential-provider-process": "3.485.0", + "@aws-sdk/credential-provider-sso": "3.485.0", + "@aws-sdk/credential-provider-web-identity": "3.485.0", + "@aws-sdk/types": "3.485.0", + "@smithy/credential-provider-imds": "^2.0.0", + "@smithy/property-provider": "^2.0.0", + "@smithy/shared-ini-file-loader": "^2.0.6", + "@smithy/types": "^2.8.0", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-process": { + "version": "3.485.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-process/-/credential-provider-process-3.485.0.tgz", + "integrity": "sha512-X9qS6ZO/rDKYDgWqD1YmSX7sAUUHax9HbXlgGiTTdtfhZvQh1ZmnH6wiPu5WNliafHZFtZT2W07kgrDLPld/Ug==", + "optional": true, + "dependencies": { + "@aws-sdk/types": "3.485.0", + "@smithy/property-provider": "^2.0.0", + "@smithy/shared-ini-file-loader": "^2.0.6", + "@smithy/types": "^2.8.0", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-sso": { + "version": "3.485.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-sso/-/credential-provider-sso-3.485.0.tgz", + "integrity": "sha512-l0oC8GTrWh+LFQQfSmG1Jai1PX7Mhj9arb/CaS1/tmeZE0hgIXW++tvljYs/Dds4LGXUlaWG+P7BrObf6OyIXA==", + "optional": true, + "dependencies": { + "@aws-sdk/client-sso": "3.485.0", + "@aws-sdk/token-providers": "3.485.0", + "@aws-sdk/types": "3.485.0", + "@smithy/property-provider": "^2.0.0", + "@smithy/shared-ini-file-loader": "^2.0.6", + "@smithy/types": "^2.8.0", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-web-identity": { + "version": "3.485.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-web-identity/-/credential-provider-web-identity-3.485.0.tgz", + "integrity": "sha512-WpBFZFE0iXtnibH5POMEKITj/hR0YV5l2n9p8BEvKjdJ63s3Xke1RN20ZdIyKDaRDwj8adnKDgNPEnAKdS4kLw==", + "optional": true, + "dependencies": { + "@aws-sdk/types": "3.485.0", + "@smithy/property-provider": "^2.0.0", + "@smithy/types": "^2.8.0", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/credential-providers": { + "version": "3.485.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-providers/-/credential-providers-3.485.0.tgz", + "integrity": "sha512-SpGEmiVr+C9Dtc5tZFfFYXSNxbl1jShLlyZPWERHBn4QwGvdXcgPB96I0yvUuitBKrM0winHsCWH7CR/z24kmg==", + "optional": true, + "dependencies": { + "@aws-sdk/client-cognito-identity": "3.485.0", + "@aws-sdk/client-sso": "3.485.0", + "@aws-sdk/client-sts": "3.485.0", + "@aws-sdk/credential-provider-cognito-identity": "3.485.0", + "@aws-sdk/credential-provider-env": "3.485.0", + "@aws-sdk/credential-provider-http": "3.485.0", + "@aws-sdk/credential-provider-ini": "3.485.0", + "@aws-sdk/credential-provider-node": "3.485.0", + "@aws-sdk/credential-provider-process": "3.485.0", + "@aws-sdk/credential-provider-sso": "3.485.0", + "@aws-sdk/credential-provider-web-identity": "3.485.0", + "@aws-sdk/types": "3.485.0", + "@smithy/credential-provider-imds": "^2.0.0", + "@smithy/property-provider": "^2.0.0", + "@smithy/types": "^2.8.0", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/lib-storage": { + "version": "3.499.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/lib-storage/-/lib-storage-3.499.0.tgz", + "integrity": "sha512-rL++Re7Oed8uwkMSafpeG6ryB1vzW0dQLi5L3IWPhllWaokrXiEJ1lT1sg8vtyoMaZ4HNGE9jeyxMCRIa52Enw==", + "dependencies": { + "@smithy/abort-controller": "^2.1.1", + "@smithy/middleware-endpoint": "^2.4.1", + "@smithy/smithy-client": "^2.3.1", + "buffer": "5.6.0", + "events": "3.3.0", + "stream-browserify": "3.0.0", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "@aws-sdk/client-s3": "^3.0.0" + } + }, + "node_modules/@aws-sdk/lib-storage/node_modules/buffer": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.6.0.tgz", + "integrity": "sha512-/gDYp/UtU0eA1ys8bOs9J6a+E/KWIY+DZ+Q2WESNUA0jFRsJOc0SNUO6xJ5SGA1xueg3NL65W6s+NY5l9cunuw==", + "dependencies": { + "base64-js": "^1.0.2", + "ieee754": "^1.1.4" + } + }, + "node_modules/@aws-sdk/middleware-bucket-endpoint": { + "version": "3.496.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-bucket-endpoint/-/middleware-bucket-endpoint-3.496.0.tgz", + "integrity": "sha512-B+ilBMSs3+LJuo2bl2KB8GFdu+8PPVtYEWtwhNkmnaU8iMisgMBp5uuM8sUDvJX7I4iSF0WbgnhguX4cJqfAew==", + "dependencies": { + "@aws-sdk/types": "3.496.0", + "@aws-sdk/util-arn-parser": "3.495.0", + "@smithy/node-config-provider": "^2.2.1", + "@smithy/protocol-http": "^3.1.1", + "@smithy/types": "^2.9.1", + "@smithy/util-config-provider": "^2.2.1", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/middleware-bucket-endpoint/node_modules/@aws-sdk/types": { + "version": "3.496.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.496.0.tgz", + "integrity": "sha512-umkGadK4QuNQaMoDICMm7NKRI/mYSXiyPjcn3d53BhsuArYU/52CebGQKdt4At7SwwsiVJZw9RNBHyN5Mm0HVw==", + "dependencies": { + "@smithy/types": "^2.9.1", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/middleware-expect-continue": { + "version": "3.496.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-expect-continue/-/middleware-expect-continue-3.496.0.tgz", + "integrity": "sha512-+exo5DVc+BeDus2iI6Fz1thefHGDXxUhHZ+4VHQ6HkStMy3Y22HugyEGHSQZmtRL86Hjr7dFbEWFsC47a2ItGA==", + "dependencies": { + "@aws-sdk/types": "3.496.0", + "@smithy/protocol-http": "^3.1.1", + "@smithy/types": "^2.9.1", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/middleware-expect-continue/node_modules/@aws-sdk/types": { + "version": "3.496.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.496.0.tgz", + "integrity": "sha512-umkGadK4QuNQaMoDICMm7NKRI/mYSXiyPjcn3d53BhsuArYU/52CebGQKdt4At7SwwsiVJZw9RNBHyN5Mm0HVw==", + "dependencies": { + "@smithy/types": "^2.9.1", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/middleware-flexible-checksums": { + "version": "3.496.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-flexible-checksums/-/middleware-flexible-checksums-3.496.0.tgz", + "integrity": "sha512-yQIWfjEMvgsAJ7ku224vXDjXPD+f9zfKZFialJva8VUlEr7hQp4CQ0rxV3YThSaixKEDDs5k6kOjWAd2BPGr2A==", + "dependencies": { + "@aws-crypto/crc32": "3.0.0", + "@aws-crypto/crc32c": "3.0.0", + "@aws-sdk/types": "3.496.0", + "@smithy/is-array-buffer": "^2.1.1", + "@smithy/protocol-http": "^3.1.1", + "@smithy/types": "^2.9.1", + "@smithy/util-utf8": "^2.1.1", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/middleware-flexible-checksums/node_modules/@aws-sdk/types": { + "version": "3.496.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.496.0.tgz", + "integrity": "sha512-umkGadK4QuNQaMoDICMm7NKRI/mYSXiyPjcn3d53BhsuArYU/52CebGQKdt4At7SwwsiVJZw9RNBHyN5Mm0HVw==", + "dependencies": { + "@smithy/types": "^2.9.1", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/middleware-host-header": { + "version": "3.485.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-host-header/-/middleware-host-header-3.485.0.tgz", + "integrity": "sha512-1mAUX9dQNGo2RIKseVj7SI/D5abQJQ/Os8hQ0NyVAyyVYF+Yjx5PphKgfhM5yoBwuwZUl6q71XPYEGNx7be6SA==", + "optional": true, + "dependencies": { + "@aws-sdk/types": "3.485.0", + "@smithy/protocol-http": "^3.0.12", + "@smithy/types": "^2.8.0", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/middleware-location-constraint": { + "version": "3.496.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-location-constraint/-/middleware-location-constraint-3.496.0.tgz", + "integrity": "sha512-i4ocJ2Zs86OtPREbB18InFukhqg2qtBxb5gywv79IHDPVmpOYE4m/3v3yGUrkjfF2GTlUL0k5FskNNqw41yfng==", + "dependencies": { + "@aws-sdk/types": "3.496.0", + "@smithy/types": "^2.9.1", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/middleware-location-constraint/node_modules/@aws-sdk/types": { + "version": "3.496.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.496.0.tgz", + "integrity": "sha512-umkGadK4QuNQaMoDICMm7NKRI/mYSXiyPjcn3d53BhsuArYU/52CebGQKdt4At7SwwsiVJZw9RNBHyN5Mm0HVw==", + "dependencies": { + "@smithy/types": "^2.9.1", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/middleware-logger": { + "version": "3.485.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-logger/-/middleware-logger-3.485.0.tgz", + "integrity": "sha512-O8IgJ0LHi5wTs5GlpI7nqmmSSagkVdd1shpGgQWY2h0kMSCII8CJZHBG97dlFFpGTvx5EDlhPNek7rl/6F4dRw==", + "optional": true, + "dependencies": { + "@aws-sdk/types": "3.485.0", + "@smithy/types": "^2.8.0", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/middleware-recursion-detection": { + "version": "3.485.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-recursion-detection/-/middleware-recursion-detection-3.485.0.tgz", + "integrity": "sha512-ZeVNATGNFcqkWDut3luVszROTUzkU5u+rJpB/xmeMoenlDAjPRiHt/ca3WkI5wAnIJ1VSNGpD2sOFLMCH+EWag==", + "optional": true, + "dependencies": { + "@aws-sdk/types": "3.485.0", + "@smithy/protocol-http": "^3.0.12", + "@smithy/types": "^2.8.0", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/middleware-sdk-s3": { + "version": "3.499.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-sdk-s3/-/middleware-sdk-s3-3.499.0.tgz", + "integrity": "sha512-thTb47U1hYHk5ei+yO0D0aehbgQXeAcgvyyxOID9/HDuRfWuTvKdclWh/goIeDfvSS87VBukEAjnCa5JYBwzug==", + "dependencies": { + "@aws-sdk/types": "3.496.0", + "@aws-sdk/util-arn-parser": "3.495.0", + "@smithy/node-config-provider": "^2.2.1", + "@smithy/protocol-http": "^3.1.1", + "@smithy/signature-v4": "^2.1.1", + "@smithy/smithy-client": "^2.3.1", + "@smithy/types": "^2.9.1", + "@smithy/util-config-provider": "^2.2.1", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/middleware-sdk-s3/node_modules/@aws-sdk/types": { + "version": "3.496.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.496.0.tgz", + "integrity": "sha512-umkGadK4QuNQaMoDICMm7NKRI/mYSXiyPjcn3d53BhsuArYU/52CebGQKdt4At7SwwsiVJZw9RNBHyN5Mm0HVw==", + "dependencies": { + "@smithy/types": "^2.9.1", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/middleware-signing": { + "version": "3.485.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-signing/-/middleware-signing-3.485.0.tgz", + "integrity": "sha512-41xzT2p1sOibhsLkdE5rwPJkNbBtKD8Gp36/ySfu0KE415wfXKacElSVxAaBw39/j7iSWDYqqybeEYbAzk+3GQ==", + "optional": true, + "dependencies": { + "@aws-sdk/types": "3.485.0", + "@smithy/property-provider": "^2.0.0", + "@smithy/protocol-http": "^3.0.12", + "@smithy/signature-v4": "^2.0.0", + "@smithy/types": "^2.8.0", + "@smithy/util-middleware": "^2.0.9", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/middleware-ssec": { + "version": "3.498.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-ssec/-/middleware-ssec-3.498.0.tgz", + "integrity": "sha512-sWujXgzeTqMZzj/pRYEnnEbSzhBosqw9DXHOY1Mg2igI9NEfGlB7lPARp6aKmCaYlP3Bcj2X86vKCqF53mbyig==", + "dependencies": { + "@aws-sdk/types": "3.496.0", + "@smithy/types": "^2.9.1", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/middleware-ssec/node_modules/@aws-sdk/types": { + "version": "3.496.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.496.0.tgz", + "integrity": "sha512-umkGadK4QuNQaMoDICMm7NKRI/mYSXiyPjcn3d53BhsuArYU/52CebGQKdt4At7SwwsiVJZw9RNBHyN5Mm0HVw==", + "dependencies": { + "@smithy/types": "^2.9.1", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/middleware-user-agent": { + "version": "3.485.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-user-agent/-/middleware-user-agent-3.485.0.tgz", + "integrity": "sha512-CddCVOn+OPQ0CcchketIg+WF6v+MDLAf3GOYTR2htUxxIm7HABuRd6R3kvQ5Jny9CV8gMt22G1UZITsFexSJlQ==", + "optional": true, + "dependencies": { + "@aws-sdk/types": "3.485.0", + "@aws-sdk/util-endpoints": "3.485.0", + "@smithy/protocol-http": "^3.0.12", + "@smithy/types": "^2.8.0", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/region-config-resolver": { + "version": "3.485.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/region-config-resolver/-/region-config-resolver-3.485.0.tgz", + "integrity": "sha512-2FB2EQ0sIE+YgFqGtkE1lDIMIL6nYe6MkOHBwBM7bommadKIrbbr2L22bPZGs3ReTsxiJabjzxbuCAVhrpHmhg==", + "optional": true, + "dependencies": { + "@smithy/node-config-provider": "^2.1.9", + "@smithy/types": "^2.8.0", + "@smithy/util-config-provider": "^2.1.0", + "@smithy/util-middleware": "^2.0.9", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/signature-v4-multi-region": { + "version": "3.499.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/signature-v4-multi-region/-/signature-v4-multi-region-3.499.0.tgz", + "integrity": "sha512-8HSFnZErRm7lAfk+Epxrf4QNdQEamg1CnbLybtKQQEjmvxLuXYvj16KlpYEZIwEENOMEvnCqMc7syTPkmjVhJA==", + "dependencies": { + "@aws-sdk/middleware-sdk-s3": "3.499.0", + "@aws-sdk/types": "3.496.0", + "@smithy/protocol-http": "^3.1.1", + "@smithy/signature-v4": "^2.1.1", + "@smithy/types": "^2.9.1", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/signature-v4-multi-region/node_modules/@aws-sdk/types": { + "version": "3.496.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.496.0.tgz", + "integrity": "sha512-umkGadK4QuNQaMoDICMm7NKRI/mYSXiyPjcn3d53BhsuArYU/52CebGQKdt4At7SwwsiVJZw9RNBHyN5Mm0HVw==", + "dependencies": { + "@smithy/types": "^2.9.1", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/token-providers": { + "version": "3.485.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/token-providers/-/token-providers-3.485.0.tgz", + "integrity": "sha512-kOXA1WKIVIFNRqHL8ynVZ3hCKLsgnEmGr2iDR6agDNw5fYIlCO/6N2xR6QdGcLTvUUbwOlz4OvKLUQnWMKAnnA==", + "optional": true, + "dependencies": { + "@aws-crypto/sha256-browser": "3.0.0", + "@aws-crypto/sha256-js": "3.0.0", + "@aws-sdk/middleware-host-header": "3.485.0", + "@aws-sdk/middleware-logger": "3.485.0", + "@aws-sdk/middleware-recursion-detection": "3.485.0", + "@aws-sdk/middleware-user-agent": "3.485.0", + "@aws-sdk/region-config-resolver": "3.485.0", + "@aws-sdk/types": "3.485.0", + "@aws-sdk/util-endpoints": "3.485.0", + "@aws-sdk/util-user-agent-browser": "3.485.0", + "@aws-sdk/util-user-agent-node": "3.485.0", + "@smithy/config-resolver": "^2.0.23", + "@smithy/fetch-http-handler": "^2.3.2", + "@smithy/hash-node": "^2.0.18", + "@smithy/invalid-dependency": "^2.0.16", + "@smithy/middleware-content-length": "^2.0.18", + "@smithy/middleware-endpoint": "^2.3.0", + "@smithy/middleware-retry": "^2.0.26", + "@smithy/middleware-serde": "^2.0.16", + "@smithy/middleware-stack": "^2.0.10", + "@smithy/node-config-provider": "^2.1.9", + "@smithy/node-http-handler": "^2.2.2", + "@smithy/property-provider": "^2.0.0", + "@smithy/protocol-http": "^3.0.12", + "@smithy/shared-ini-file-loader": "^2.0.6", + "@smithy/smithy-client": "^2.2.1", + "@smithy/types": "^2.8.0", + "@smithy/url-parser": "^2.0.16", + "@smithy/util-base64": "^2.0.1", + "@smithy/util-body-length-browser": "^2.0.1", + "@smithy/util-body-length-node": "^2.1.0", + "@smithy/util-defaults-mode-browser": "^2.0.24", + "@smithy/util-defaults-mode-node": "^2.0.32", + "@smithy/util-endpoints": "^1.0.8", + "@smithy/util-retry": "^2.0.9", + "@smithy/util-utf8": "^2.0.2", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/types": { + "version": "3.485.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.485.0.tgz", + "integrity": "sha512-+QW32YQdvZRDOwrAQPo/qCyXoSjgXB6RwJwCwkd8ebJXRXw6tmGKIHaZqYHt/LtBymvnaBgBBADNa4+qFvlOFw==", + "dependencies": { + "@smithy/types": "^2.8.0", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/util-arn-parser": { + "version": "3.495.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-arn-parser/-/util-arn-parser-3.495.0.tgz", + "integrity": "sha512-hwdA3XAippSEUxs7jpznwD63YYFR+LtQvlEcebPTgWR9oQgG9TfS+39PUfbnEeje1ICuOrN3lrFqFbmP9uzbMg==", + "dependencies": { + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/util-endpoints": { + "version": "3.485.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-endpoints/-/util-endpoints-3.485.0.tgz", + "integrity": "sha512-dTd642F7nJisApF8YjniqQ6U59CP/DCtar11fXf1nG9YNBCBsNNVw5ZfZb5nSNzaIdy27mQioWTCV18JEj1mxg==", + "optional": true, + "dependencies": { + "@aws-sdk/types": "3.485.0", + "@smithy/util-endpoints": "^1.0.8", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/util-locate-window": { + "version": "3.465.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-locate-window/-/util-locate-window-3.465.0.tgz", + "integrity": "sha512-f+QNcWGswredzC1ExNAB/QzODlxwaTdXkNT5cvke2RLX8SFU5pYk6h4uCtWC0vWPELzOfMfloBrJefBzlarhsw==", + "dependencies": { + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/util-user-agent-browser": { + "version": "3.485.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-browser/-/util-user-agent-browser-3.485.0.tgz", + "integrity": "sha512-QliWbjg0uOhGTcWgWTKPMY0SBi07g253DjwrCINT1auqDrdQPxa10xozpZExBYjAK2KuhYDNUzni127ae6MHOw==", + "optional": true, + "dependencies": { + "@aws-sdk/types": "3.485.0", + "@smithy/types": "^2.8.0", + "bowser": "^2.11.0", + "tslib": "^2.5.0" + } + }, + "node_modules/@aws-sdk/util-user-agent-node": { + "version": "3.485.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-node/-/util-user-agent-node-3.485.0.tgz", + "integrity": "sha512-QF+aQ9jnDlPUlFBxBRqOylPf86xQuD3aEPpOErR+50qJawVvKa94uiAFdvtI9jv6hnRZmuFsTj2rsyytnbAYBA==", + "optional": true, + "dependencies": { + "@aws-sdk/types": "3.485.0", + "@smithy/node-config-provider": "^2.1.9", + "@smithy/types": "^2.8.0", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "aws-crt": ">=1.0.0" + }, + "peerDependenciesMeta": { + "aws-crt": { + "optional": true + } + } + }, + "node_modules/@aws-sdk/util-utf8-browser": { + "version": "3.259.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-utf8-browser/-/util-utf8-browser-3.259.0.tgz", + "integrity": "sha512-UvFa/vR+e19XookZF8RzFZBrw2EUkQWxiBW0yYQAhvk3C+QVGl0H3ouca8LDBlBfQKXwmW3huo/59H8rwb1wJw==", + "dependencies": { + "tslib": "^2.3.1" + } + }, + "node_modules/@aws-sdk/xml-builder": { + "version": "3.496.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/xml-builder/-/xml-builder-3.496.0.tgz", + "integrity": "sha512-GvEjh537IIeOw1ZkZuB37sV12u+ipS5Z1dwjEC/HAvhl5ac23ULtTr1/n+U1gLNN+BAKSWjKiQ2ksj8DiUzeyw==", + "dependencies": { + "@smithy/types": "^2.9.1", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@colors/colors": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.6.0.tgz", + "integrity": "sha512-Ir+AOibqzrIsL6ajt3Rz3LskB7OiMVHqltZmspbW/TJuTVuyOMirVqAkjfY6JISiLHgyNqicAC8AyHHGzNd/dA==", + "engines": { + "node": ">=0.1.90" + } + }, + "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", + "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", + "dev": true, + "dependencies": { + "@jridgewell/trace-mapping": "0.3.9" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@dabh/diagnostics": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@dabh/diagnostics/-/diagnostics-2.0.3.tgz", + "integrity": "sha512-hrlQOIi7hAfzsMqlGSFyVucrx38O+j6wiGOf//H2ecvIEqYN4ADBSS2iLMh5UFyDunCNniUIPk/q3riFv45xRA==", + "dependencies": { + "colorspace": "1.1.x", + "enabled": "2.0.x", + "kuler": "^2.0.0" + } + }, + "node_modules/@discordjs/builders": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/@discordjs/builders/-/builders-1.7.0.tgz", + "integrity": "sha512-GDtbKMkg433cOZur8Dv6c25EHxduNIBsxeHrsRoIM8+AwmEZ8r0tEpckx/sHwTLwQPOF3e2JWloZh9ofCaMfAw==", + "dependencies": { + "@discordjs/formatters": "^0.3.3", + "@discordjs/util": "^1.0.2", + "@sapphire/shapeshift": "^3.9.3", + "discord-api-types": "0.37.61", + "fast-deep-equal": "^3.1.3", + "ts-mixer": "^6.0.3", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.11.0" + } + }, + "node_modules/@discordjs/collection": { + "version": "1.5.3", + "resolved": "https://registry.npmjs.org/@discordjs/collection/-/collection-1.5.3.tgz", + "integrity": "sha512-SVb428OMd3WO1paV3rm6tSjM4wC+Kecaa1EUGX7vc6/fddvw/6lg90z4QtCqm21zvVe92vMMDt9+DkIvjXImQQ==", + "engines": { + "node": ">=16.11.0" + } + }, + "node_modules/@discordjs/formatters": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/@discordjs/formatters/-/formatters-0.3.3.tgz", + "integrity": "sha512-wTcI1Q5cps1eSGhl6+6AzzZkBBlVrBdc9IUhJbijRgVjCNIIIZPgqnUj3ntFODsHrdbGU8BEG9XmDQmgEEYn3w==", + "dependencies": { + "discord-api-types": "0.37.61" + }, + "engines": { + "node": ">=16.11.0" + } + }, + "node_modules/@discordjs/rest": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@discordjs/rest/-/rest-2.2.0.tgz", + "integrity": "sha512-nXm9wT8oqrYFRMEqTXQx9DUTeEtXUDMmnUKIhZn6O2EeDY9VCdwj23XCPq7fkqMPKdF7ldAfeVKyxxFdbZl59A==", + "dependencies": { + "@discordjs/collection": "^2.0.0", + "@discordjs/util": "^1.0.2", + "@sapphire/async-queue": "^1.5.0", + "@sapphire/snowflake": "^3.5.1", + "@vladfrangu/async_event_emitter": "^2.2.2", + "discord-api-types": "0.37.61", + "magic-bytes.js": "^1.5.0", + "tslib": "^2.6.2", + "undici": "5.27.2" + }, + "engines": { + "node": ">=16.11.0" + } + }, + "node_modules/@discordjs/rest/node_modules/@discordjs/collection": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@discordjs/collection/-/collection-2.0.0.tgz", + "integrity": "sha512-YTWIXLrf5FsrLMycpMM9Q6vnZoR/lN2AWX23/Cuo8uOOtS8eHB2dyQaaGnaF8aZPYnttf2bkLMcXn/j6JUOi3w==", + "engines": { + "node": ">=18" + } + }, + "node_modules/@discordjs/util": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@discordjs/util/-/util-1.0.2.tgz", + "integrity": "sha512-IRNbimrmfb75GMNEjyznqM1tkI7HrZOf14njX7tCAAUetyZM1Pr8hX/EK2lxBCOgWDRmigbp24fD1hdMfQK5lw==", + "engines": { + "node": ">=16.11.0" + } + }, + "node_modules/@discordjs/ws": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@discordjs/ws/-/ws-1.0.2.tgz", + "integrity": "sha512-+XI82Rm2hKnFwAySXEep4A7Kfoowt6weO6381jgW+wVdTpMS/56qCvoXyFRY0slcv7c/U8My2PwIB2/wEaAh7Q==", + "dependencies": { + "@discordjs/collection": "^2.0.0", + "@discordjs/rest": "^2.1.0", + "@discordjs/util": "^1.0.2", + "@sapphire/async-queue": "^1.5.0", + "@types/ws": "^8.5.9", + "@vladfrangu/async_event_emitter": "^2.2.2", + "discord-api-types": "0.37.61", + "tslib": "^2.6.2", + "ws": "^8.14.2" + }, + "engines": { + "node": ">=16.11.0" + } + }, + "node_modules/@discordjs/ws/node_modules/@discordjs/collection": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@discordjs/collection/-/collection-2.0.0.tgz", + "integrity": "sha512-YTWIXLrf5FsrLMycpMM9Q6vnZoR/lN2AWX23/Cuo8uOOtS8eHB2dyQaaGnaF8aZPYnttf2bkLMcXn/j6JUOi3w==", + "engines": { + "node": ">=18" + } + }, + "node_modules/@eslint-community/eslint-utils": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", + "integrity": "sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==", + "dev": true, + "dependencies": { + "eslint-visitor-keys": "^3.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" + } + }, + "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==", + "dev": true, + "engines": { + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + } + }, + "node_modules/@eslint/config-array": { + "version": "0.15.1", + "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.15.1.tgz", + "integrity": "sha512-K4gzNq+yymn/EVsXYmf+SBcBro8MTf+aXJZUphM96CdzUEr+ClGDvAbpmaEK+cGVigVXIgs9gNmvHAlrzzY5JQ==", + "dev": true, + "dependencies": { + "@eslint/object-schema": "^2.1.3", + "debug": "^4.3.1", + "minimatch": "^3.0.5" + }, + "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, + "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, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/@eslint/eslintrc": { + "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, + "dependencies": { + "ajv": "^6.12.4", + "debug": "^4.3.2", + "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" + }, + "engines": { + "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, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "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, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/@eslint/js": { + "version": "9.4.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.4.0.tgz", + "integrity": "sha512-fdI7VJjP3Rvc70lC4xkFXHB0fiPeojiL1PxVG6t1ZvXQrarj893PweuBTujxDUFk0Fxj4R7PIIAZ/aiiyZPZcg==", + "dev": true, + "engines": { + "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, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@fastify/busboy": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@fastify/busboy/-/busboy-2.1.0.tgz", + "integrity": "sha512-+KpH+QxZU7O4675t3mnkQKcZZg56u+K/Ct2K+N2AZYNVK8kyeo/bI18tI8aPm3tvNNRyTWfj6s5tnGNlcbQRsA==", + "engines": { + "node": ">=14" + } + }, + "node_modules/@hokify/agenda": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/@hokify/agenda/-/agenda-6.3.0.tgz", + "integrity": "sha512-fWrKMDe/8QHJXLOdEsMogb6cb213Z82iNsnU7nFrSIMFifEXSkXNTyCZ99FV3KLf+Du1gS/M9/8uTC6FHyWRZQ==", + "dependencies": { + "cron-parser": "^4", + "date.js": "~0.3.3", + "debug": "~4", + "human-interval": "~2", + "luxon": "^3", + "mongodb": "^4" + }, + "engines": { + "node": ">=14.0.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, + "engines": { + "node": ">=12.22" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "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, + "engines": { + "node": ">=18.18" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.1.tgz", + "integrity": "sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA==", + "dev": true, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.4.15", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", + "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==", + "dev": true + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", + "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", + "dev": true, + "dependencies": { + "@jridgewell/resolve-uri": "^3.0.3", + "@jridgewell/sourcemap-codec": "^1.4.10" + } + }, + "node_modules/@mongodb-js/saslprep": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@mongodb-js/saslprep/-/saslprep-1.1.3.tgz", + "integrity": "sha512-SyCxhJfmK6MoLNV5SbDpNdUy9SDv5H7y9/9rl3KpnwgTHWuNNMc87zWqbcIZXNWY+aUjxLGLEcvHoLagG4tWCg==", + "dependencies": { + "sparse-bitfield": "^3.0.3" + } + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dev": true, + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dev": true, + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@octokit/endpoint": { + "version": "9.0.4", + "resolved": "https://registry.npmjs.org/@octokit/endpoint/-/endpoint-9.0.4.tgz", + "integrity": "sha512-DWPLtr1Kz3tv8L0UvXTDP1fNwM0S+z6EJpRcvH66orY6Eld4XBMCSYsaWp4xIm61jTWxK68BrR7ibO+vSDnZqw==", + "dependencies": { + "@octokit/types": "^12.0.0", + "universal-user-agent": "^6.0.0" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/@octokit/openapi-types": { + "version": "19.1.0", + "resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-19.1.0.tgz", + "integrity": "sha512-6G+ywGClliGQwRsjvqVYpklIfa7oRPA0vyhPQG/1Feh+B+wU0vGH1JiJ5T25d3g1JZYBHzR2qefLi9x8Gt+cpw==" + }, + "node_modules/@octokit/request": { + "version": "8.1.6", + "resolved": "https://registry.npmjs.org/@octokit/request/-/request-8.1.6.tgz", + "integrity": "sha512-YhPaGml3ncZC1NfXpP3WZ7iliL1ap6tLkAp6MvbK2fTTPytzVUyUesBBogcdMm86uRYO5rHaM1xIWxigWZ17MQ==", + "dependencies": { + "@octokit/endpoint": "^9.0.0", + "@octokit/request-error": "^5.0.0", + "@octokit/types": "^12.0.0", + "universal-user-agent": "^6.0.0" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/@octokit/request-error": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/@octokit/request-error/-/request-error-5.0.1.tgz", + "integrity": "sha512-X7pnyTMV7MgtGmiXBwmO6M5kIPrntOXdyKZLigNfQWSEQzVxR4a4vo49vJjTWX70mPndj8KhfT4Dx+2Ng3vnBQ==", + "dependencies": { + "@octokit/types": "^12.0.0", + "deprecation": "^2.0.0", + "once": "^1.4.0" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/@octokit/types": { + "version": "12.4.0", + "resolved": "https://registry.npmjs.org/@octokit/types/-/types-12.4.0.tgz", + "integrity": "sha512-FLWs/AvZllw/AGVs+nJ+ELCDZZJk+kY0zMen118xhL2zD0s1etIUHm1odgjP7epxYU1ln7SZxEUWYop5bhsdgQ==", + "dependencies": { + "@octokit/openapi-types": "^19.1.0" + } + }, + "node_modules/@pkgr/core": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@pkgr/core/-/core-0.1.1.tgz", + "integrity": "sha512-cq8o4cWH0ibXh9VGi5P20Tu9XF/0fFXl9EUinr9QfTM7a7p0oTA4iJRCQWppXR1Pg8dSM0UCItCkPwsk9qWWYA==", + "dev": true, + "engines": { + "node": "^12.20.0 || ^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/unts" + } + }, + "node_modules/@sapphire/async-queue": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/@sapphire/async-queue/-/async-queue-1.5.1.tgz", + "integrity": "sha512-1RdpsmDQR/aWfp8oJzPtn4dNQrbpqSL5PIA0uAB/XwerPXUf994Ug1au1e7uGcD7ei8/F63UDjr5GWps1g/HxQ==", + "engines": { + "node": ">=v14.0.0", + "npm": ">=7.0.0" + } + }, + "node_modules/@sapphire/shapeshift": { + "version": "3.9.5", + "resolved": "https://registry.npmjs.org/@sapphire/shapeshift/-/shapeshift-3.9.5.tgz", + "integrity": "sha512-AGdHe+51gF7D3W8hBfuSFLBocURDCXVQczScTHXDS3RpNjNgrktIx/amlz5y8nHhm8SAdFt/X8EF8ZSfjJ0tnA==", + "dependencies": { + "fast-deep-equal": "^3.1.3", + "lodash": "^4.17.21" + }, + "engines": { + "node": ">=v18" + } + }, + "node_modules/@sapphire/snowflake": { + "version": "3.5.1", + "resolved": "https://registry.npmjs.org/@sapphire/snowflake/-/snowflake-3.5.1.tgz", + "integrity": "sha512-BxcYGzgEsdlG0dKAyOm0ehLGm2CafIrfQTZGWgkfKYbj+pNNsorZ7EotuZukc2MT70E0UbppVbtpBrqpzVzjNA==", + "engines": { + "node": ">=v14.0.0", + "npm": ">=7.0.0" + } + }, + "node_modules/@smithy/abort-controller": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@smithy/abort-controller/-/abort-controller-2.1.1.tgz", + "integrity": "sha512-1+qdrUqLhaALYL0iOcN43EP6yAXXQ2wWZ6taf4S2pNGowmOc5gx+iMQv+E42JizNJjB0+gEadOXeV1Bf7JWL1Q==", + "dependencies": { + "@smithy/types": "^2.9.1", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/chunked-blob-reader": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@smithy/chunked-blob-reader/-/chunked-blob-reader-2.1.1.tgz", + "integrity": "sha512-NjNFCKxC4jVvn+lUr3Yo4/PmUJj3tbyqH6GNHueyTGS5Q27vlEJ1MkNhUDV8QGxJI7Bodnc2pD18lU2zRfhHlQ==", + "dependencies": { + "tslib": "^2.5.0" + } + }, + "node_modules/@smithy/chunked-blob-reader-native": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@smithy/chunked-blob-reader-native/-/chunked-blob-reader-native-2.1.1.tgz", + "integrity": "sha512-zNW+43dltfNMUrBEYLMWgI8lQr0uhtTcUyxkgC9EP4j17WREzgSFMPUFVrVV6Rc2+QtWERYjb4tzZnQGa7R9fQ==", + "dependencies": { + "@smithy/util-base64": "^2.1.1", + "tslib": "^2.5.0" + } + }, + "node_modules/@smithy/config-resolver": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@smithy/config-resolver/-/config-resolver-2.1.1.tgz", + "integrity": "sha512-lxfLDpZm+AWAHPFZps5JfDoO9Ux1764fOgvRUBpHIO8HWHcSN1dkgsago1qLRVgm1BZ8RCm8cgv99QvtaOWIhw==", + "dependencies": { + "@smithy/node-config-provider": "^2.2.1", + "@smithy/types": "^2.9.1", + "@smithy/util-config-provider": "^2.2.1", + "@smithy/util-middleware": "^2.1.1", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/core": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/@smithy/core/-/core-1.3.1.tgz", + "integrity": "sha512-tf+NIu9FkOh312b6M9G4D68is4Xr7qptzaZGZUREELF8ysE1yLKphqt7nsomjKZVwW7WE5pDDex9idowNGRQ/Q==", + "dependencies": { + "@smithy/middleware-endpoint": "^2.4.1", + "@smithy/middleware-retry": "^2.1.1", + "@smithy/middleware-serde": "^2.1.1", + "@smithy/protocol-http": "^3.1.1", + "@smithy/smithy-client": "^2.3.1", + "@smithy/types": "^2.9.1", + "@smithy/util-middleware": "^2.1.1", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/credential-provider-imds": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/@smithy/credential-provider-imds/-/credential-provider-imds-2.2.1.tgz", + "integrity": "sha512-7XHjZUxmZYnONheVQL7j5zvZXga+EWNgwEAP6OPZTi7l8J4JTeNh9aIOfE5fKHZ/ee2IeNOh54ZrSna+Vc6TFA==", + "dependencies": { + "@smithy/node-config-provider": "^2.2.1", + "@smithy/property-provider": "^2.1.1", + "@smithy/types": "^2.9.1", + "@smithy/url-parser": "^2.1.1", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/eventstream-codec": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@smithy/eventstream-codec/-/eventstream-codec-2.1.1.tgz", + "integrity": "sha512-E8KYBxBIuU4c+zrpR22VsVrOPoEDzk35bQR3E+xm4k6Pa6JqzkDOdMyf9Atac5GPNKHJBdVaQ4JtjdWX2rl/nw==", + "dependencies": { + "@aws-crypto/crc32": "3.0.0", + "@smithy/types": "^2.9.1", + "@smithy/util-hex-encoding": "^2.1.1", + "tslib": "^2.5.0" + } + }, + "node_modules/@smithy/eventstream-serde-browser": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@smithy/eventstream-serde-browser/-/eventstream-serde-browser-2.1.1.tgz", + "integrity": "sha512-JvEdCmGlZUay5VtlT8/kdR6FlvqTDUiJecMjXsBb0+k1H/qc9ME5n2XKPo8q/MZwEIA1GmGgYMokKGjVvMiDow==", + "dependencies": { + "@smithy/eventstream-serde-universal": "^2.1.1", + "@smithy/types": "^2.9.1", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/eventstream-serde-config-resolver": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@smithy/eventstream-serde-config-resolver/-/eventstream-serde-config-resolver-2.1.1.tgz", + "integrity": "sha512-EqNqXYp3+dk//NmW3NAgQr9bEQ7fsu/CcxQmTiq07JlaIcne/CBWpMZETyXm9w5LXkhduBsdXdlMscfDUDn2fA==", + "dependencies": { + "@smithy/types": "^2.9.1", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/eventstream-serde-node": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@smithy/eventstream-serde-node/-/eventstream-serde-node-2.1.1.tgz", + "integrity": "sha512-LF882q/aFidFNDX7uROAGxq3H0B7rjyPkV6QDn6/KDQ+CG7AFkRccjxRf1xqajq/Pe4bMGGr+VKAaoF6lELIQw==", + "dependencies": { + "@smithy/eventstream-serde-universal": "^2.1.1", + "@smithy/types": "^2.9.1", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/eventstream-serde-universal": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@smithy/eventstream-serde-universal/-/eventstream-serde-universal-2.1.1.tgz", + "integrity": "sha512-LR0mMT+XIYTxk4k2fIxEA1BPtW3685QlqufUEUAX1AJcfFfxNDKEvuCRZbO8ntJb10DrIFVJR9vb0MhDCi0sAQ==", + "dependencies": { + "@smithy/eventstream-codec": "^2.1.1", + "@smithy/types": "^2.9.1", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/fetch-http-handler": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/@smithy/fetch-http-handler/-/fetch-http-handler-2.4.1.tgz", + "integrity": "sha512-VYGLinPsFqH68lxfRhjQaSkjXM7JysUOJDTNjHBuN/ykyRb2f1gyavN9+VhhPTWCy32L4yZ2fdhpCs/nStEicg==", + "dependencies": { + "@smithy/protocol-http": "^3.1.1", + "@smithy/querystring-builder": "^2.1.1", + "@smithy/types": "^2.9.1", + "@smithy/util-base64": "^2.1.1", + "tslib": "^2.5.0" + } + }, + "node_modules/@smithy/hash-blob-browser": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@smithy/hash-blob-browser/-/hash-blob-browser-2.1.1.tgz", + "integrity": "sha512-jizu1+2PAUjiGIfRtlPEU8Yo6zn+d78ti/ZHDesdf1SUn2BuZW433JlPoCOLH3dBoEEvTgLvQ8tUGSoTTALA+A==", + "dependencies": { + "@smithy/chunked-blob-reader": "^2.1.1", + "@smithy/chunked-blob-reader-native": "^2.1.1", + "@smithy/types": "^2.9.1", + "tslib": "^2.5.0" + } + }, + "node_modules/@smithy/hash-node": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@smithy/hash-node/-/hash-node-2.1.1.tgz", + "integrity": "sha512-Qhoq0N8f2OtCnvUpCf+g1vSyhYQrZjhSwvJ9qvR8BUGOtTXiyv2x1OD2e6jVGmlpC4E4ax1USHoyGfV9JFsACg==", + "dependencies": { + "@smithy/types": "^2.9.1", + "@smithy/util-buffer-from": "^2.1.1", + "@smithy/util-utf8": "^2.1.1", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/hash-stream-node": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@smithy/hash-stream-node/-/hash-stream-node-2.1.1.tgz", + "integrity": "sha512-VgDaKcfCy0iHcmtAZgZ3Yw9g37Gkn2JsQiMtFQXUh8Wmo3GfNgDwLOtdhJ272pOT7DStzpe9cNr+eV5Au8KfQA==", + "dependencies": { + "@smithy/types": "^2.9.1", + "@smithy/util-utf8": "^2.1.1", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/invalid-dependency": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@smithy/invalid-dependency/-/invalid-dependency-2.1.1.tgz", + "integrity": "sha512-7WTgnKw+VPg8fxu2v9AlNOQ5yaz6RA54zOVB4f6vQuR0xFKd+RzlCpt0WidYTsye7F+FYDIaS/RnJW4pxjNInw==", + "dependencies": { + "@smithy/types": "^2.9.1", + "tslib": "^2.5.0" + } + }, + "node_modules/@smithy/is-array-buffer": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@smithy/is-array-buffer/-/is-array-buffer-2.1.1.tgz", + "integrity": "sha512-xozSQrcUinPpNPNPds4S7z/FakDTh1MZWtRP/2vQtYB/u3HYrX2UXuZs+VhaKBd6Vc7g2XPr2ZtwGBNDN6fNKQ==", + "dependencies": { + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/md5-js": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@smithy/md5-js/-/md5-js-2.1.1.tgz", + "integrity": "sha512-L3MbIYBIdLlT+MWTYrdVSv/dow1+6iZ1Ad7xS0OHxTTs17d753ZcpOV4Ro7M7tRAVWML/sg2IAp/zzCb6aAttg==", + "dependencies": { + "@smithy/types": "^2.9.1", + "@smithy/util-utf8": "^2.1.1", + "tslib": "^2.5.0" + } + }, + "node_modules/@smithy/middleware-content-length": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@smithy/middleware-content-length/-/middleware-content-length-2.1.1.tgz", + "integrity": "sha512-rSr9ezUl9qMgiJR0UVtVOGEZElMdGFyl8FzWEF5iEKTlcWxGr2wTqGfDwtH3LAB7h+FPkxqv4ZU4cpuCN9Kf/g==", + "dependencies": { + "@smithy/protocol-http": "^3.1.1", + "@smithy/types": "^2.9.1", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/middleware-endpoint": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/@smithy/middleware-endpoint/-/middleware-endpoint-2.4.1.tgz", + "integrity": "sha512-XPZTb1E2Oav60Ven3n2PFx+rX9EDsU/jSTA8VDamt7FXks67ekjPY/XrmmPDQaFJOTUHJNKjd8+kZxVO5Ael4Q==", + "dependencies": { + "@smithy/middleware-serde": "^2.1.1", + "@smithy/node-config-provider": "^2.2.1", + "@smithy/shared-ini-file-loader": "^2.3.1", + "@smithy/types": "^2.9.1", + "@smithy/url-parser": "^2.1.1", + "@smithy/util-middleware": "^2.1.1", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/middleware-retry": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@smithy/middleware-retry/-/middleware-retry-2.1.1.tgz", + "integrity": "sha512-eMIHOBTXro6JZ+WWzZWd/8fS8ht5nS5KDQjzhNMHNRcG5FkNTqcKpYhw7TETMYzbLfhO5FYghHy1vqDWM4FLDA==", + "dependencies": { + "@smithy/node-config-provider": "^2.2.1", + "@smithy/protocol-http": "^3.1.1", + "@smithy/service-error-classification": "^2.1.1", + "@smithy/smithy-client": "^2.3.1", + "@smithy/types": "^2.9.1", + "@smithy/util-middleware": "^2.1.1", + "@smithy/util-retry": "^2.1.1", + "tslib": "^2.5.0", + "uuid": "^8.3.2" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/middleware-serde": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@smithy/middleware-serde/-/middleware-serde-2.1.1.tgz", + "integrity": "sha512-D8Gq0aQBeE1pxf3cjWVkRr2W54t+cdM2zx78tNrVhqrDykRA7asq8yVJij1u5NDtKzKqzBSPYh7iW0svUKg76g==", + "dependencies": { + "@smithy/types": "^2.9.1", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/middleware-stack": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@smithy/middleware-stack/-/middleware-stack-2.1.1.tgz", + "integrity": "sha512-KPJhRlhsl8CjgGXK/DoDcrFGfAqoqvuwlbxy+uOO4g2Azn1dhH+GVfC3RAp+6PoL5PWPb+vt6Z23FP+Mr6qeCw==", + "dependencies": { + "@smithy/types": "^2.9.1", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/node-config-provider": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/@smithy/node-config-provider/-/node-config-provider-2.2.1.tgz", + "integrity": "sha512-epzK3x1xNxA9oJgHQ5nz+2j6DsJKdHfieb+YgJ7ATWxzNcB7Hc+Uya2TUck5MicOPhDV8HZImND7ZOecVr+OWg==", + "dependencies": { + "@smithy/property-provider": "^2.1.1", + "@smithy/shared-ini-file-loader": "^2.3.1", + "@smithy/types": "^2.9.1", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/node-http-handler": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/@smithy/node-http-handler/-/node-http-handler-2.3.1.tgz", + "integrity": "sha512-gLA8qK2nL9J0Rk/WEZSvgin4AppvuCYRYg61dcUo/uKxvMZsMInL5I5ZdJTogOvdfVug3N2dgI5ffcUfS4S9PA==", + "dependencies": { + "@smithy/abort-controller": "^2.1.1", + "@smithy/protocol-http": "^3.1.1", + "@smithy/querystring-builder": "^2.1.1", + "@smithy/types": "^2.9.1", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/property-provider": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@smithy/property-provider/-/property-provider-2.1.1.tgz", + "integrity": "sha512-FX7JhhD/o5HwSwg6GLK9zxrMUrGnb3PzNBrcthqHKBc3dH0UfgEAU24xnJ8F0uow5mj17UeBEOI6o3CF2k7Mhw==", + "dependencies": { + "@smithy/types": "^2.9.1", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/protocol-http": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@smithy/protocol-http/-/protocol-http-3.1.1.tgz", + "integrity": "sha512-6ZRTSsaXuSL9++qEwH851hJjUA0OgXdQFCs+VDw4tGH256jQ3TjYY/i34N4vd24RV3nrjNsgd1yhb57uMoKbzQ==", + "dependencies": { + "@smithy/types": "^2.9.1", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/querystring-builder": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@smithy/querystring-builder/-/querystring-builder-2.1.1.tgz", + "integrity": "sha512-C/ko/CeEa8jdYE4gt6nHO5XDrlSJ3vdCG0ZAc6nD5ZIE7LBp0jCx4qoqp7eoutBu7VrGMXERSRoPqwi1WjCPbg==", + "dependencies": { + "@smithy/types": "^2.9.1", + "@smithy/util-uri-escape": "^2.1.1", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/querystring-parser": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@smithy/querystring-parser/-/querystring-parser-2.1.1.tgz", + "integrity": "sha512-H4+6jKGVhG1W4CIxfBaSsbm98lOO88tpDWmZLgkJpt8Zkk/+uG0FmmqMuCAc3HNM2ZDV+JbErxr0l5BcuIf/XQ==", + "dependencies": { + "@smithy/types": "^2.9.1", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/service-error-classification": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@smithy/service-error-classification/-/service-error-classification-2.1.1.tgz", + "integrity": "sha512-txEdZxPUgM1PwGvDvHzqhXisrc5LlRWYCf2yyHfvITWioAKat7srQvpjMAvgzf0t6t7j8yHrryXU9xt7RZqFpw==", + "dependencies": { + "@smithy/types": "^2.9.1" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/shared-ini-file-loader": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/@smithy/shared-ini-file-loader/-/shared-ini-file-loader-2.3.1.tgz", + "integrity": "sha512-2E2kh24igmIznHLB6H05Na4OgIEilRu0oQpYXo3LCNRrawHAcfDKq9004zJs+sAMt2X5AbY87CUCJ7IpqpSgdw==", + "dependencies": { + "@smithy/types": "^2.9.1", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/signature-v4": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@smithy/signature-v4/-/signature-v4-2.1.1.tgz", + "integrity": "sha512-Hb7xub0NHuvvQD3YwDSdanBmYukoEkhqBjqoxo+bSdC0ryV9cTfgmNjuAQhTPYB6yeU7hTR+sPRiFMlxqv6kmg==", + "dependencies": { + "@smithy/eventstream-codec": "^2.1.1", + "@smithy/is-array-buffer": "^2.1.1", + "@smithy/types": "^2.9.1", + "@smithy/util-hex-encoding": "^2.1.1", + "@smithy/util-middleware": "^2.1.1", + "@smithy/util-uri-escape": "^2.1.1", + "@smithy/util-utf8": "^2.1.1", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/smithy-client": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/@smithy/smithy-client/-/smithy-client-2.3.1.tgz", + "integrity": "sha512-YsTdU8xVD64r2pLEwmltrNvZV6XIAC50LN6ivDopdt+YiF/jGH6PY9zUOu0CXD/d8GMB8gbhnpPsdrjAXHS9QA==", + "dependencies": { + "@smithy/middleware-endpoint": "^2.4.1", + "@smithy/middleware-stack": "^2.1.1", + "@smithy/protocol-http": "^3.1.1", + "@smithy/types": "^2.9.1", + "@smithy/util-stream": "^2.1.1", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/types": { + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@smithy/types/-/types-2.9.1.tgz", + "integrity": "sha512-vjXlKNXyprDYDuJ7UW5iobdmyDm6g8dDG+BFUncAg/3XJaN45Gy5RWWWUVgrzIK7S4R1KWgIX5LeJcfvSI24bw==", + "dependencies": { + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/url-parser": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@smithy/url-parser/-/url-parser-2.1.1.tgz", + "integrity": "sha512-qC9Bv8f/vvFIEkHsiNrUKYNl8uKQnn4BdhXl7VzQRP774AwIjiSMMwkbT+L7Fk8W8rzYVifzJNYxv1HwvfBo3Q==", + "dependencies": { + "@smithy/querystring-parser": "^2.1.1", + "@smithy/types": "^2.9.1", + "tslib": "^2.5.0" + } + }, + "node_modules/@smithy/util-base64": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@smithy/util-base64/-/util-base64-2.1.1.tgz", + "integrity": "sha512-UfHVpY7qfF/MrgndI5PexSKVTxSZIdz9InghTFa49QOvuu9I52zLPLUHXvHpNuMb1iD2vmc6R+zbv/bdMipR/g==", + "dependencies": { + "@smithy/util-buffer-from": "^2.1.1", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/util-body-length-browser": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@smithy/util-body-length-browser/-/util-body-length-browser-2.1.1.tgz", + "integrity": "sha512-ekOGBLvs1VS2d1zM2ER4JEeBWAvIOUKeaFch29UjjJsxmZ/f0L3K3x0dEETgh3Q9bkZNHgT+rkdl/J/VUqSRag==", + "dependencies": { + "tslib": "^2.5.0" + } + }, + "node_modules/@smithy/util-body-length-node": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/@smithy/util-body-length-node/-/util-body-length-node-2.2.1.tgz", + "integrity": "sha512-/ggJG+ta3IDtpNVq4ktmEUtOkH1LW64RHB5B0hcr5ZaWBmo96UX2cIOVbjCqqDickTXqBWZ4ZO0APuaPrD7Abg==", + "dependencies": { + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/util-buffer-from": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@smithy/util-buffer-from/-/util-buffer-from-2.1.1.tgz", + "integrity": "sha512-clhNjbyfqIv9Md2Mg6FffGVrJxw7bgK7s3Iax36xnfVj6cg0fUG7I4RH0XgXJF8bxi+saY5HR21g2UPKSxVCXg==", + "dependencies": { + "@smithy/is-array-buffer": "^2.1.1", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/util-config-provider": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/@smithy/util-config-provider/-/util-config-provider-2.2.1.tgz", + "integrity": "sha512-50VL/tx9oYYcjJn/qKqNy7sCtpD0+s8XEBamIFo4mFFTclKMNp+rsnymD796uybjiIquB7VCB/DeafduL0y2kw==", + "dependencies": { + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/util-defaults-mode-browser": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-browser/-/util-defaults-mode-browser-2.1.1.tgz", + "integrity": "sha512-lqLz/9aWRO6mosnXkArtRuQqqZBhNpgI65YDpww4rVQBuUT7qzKbDLG5AmnQTCiU4rOquaZO/Kt0J7q9Uic7MA==", + "dependencies": { + "@smithy/property-provider": "^2.1.1", + "@smithy/smithy-client": "^2.3.1", + "@smithy/types": "^2.9.1", + "bowser": "^2.11.0", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/@smithy/util-defaults-mode-node": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-node/-/util-defaults-mode-node-2.1.1.tgz", + "integrity": "sha512-tYVrc+w+jSBfBd267KDnvSGOh4NMz+wVH7v4CClDbkdPfnjvImBZsOURncT5jsFwR9KCuDyPoSZq4Pa6+eCUrA==", + "dependencies": { + "@smithy/config-resolver": "^2.1.1", + "@smithy/credential-provider-imds": "^2.2.1", + "@smithy/node-config-provider": "^2.2.1", + "@smithy/property-provider": "^2.1.1", + "@smithy/smithy-client": "^2.3.1", + "@smithy/types": "^2.9.1", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/@smithy/util-endpoints": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@smithy/util-endpoints/-/util-endpoints-1.1.1.tgz", + "integrity": "sha512-sI4d9rjoaekSGEtq3xSb2nMjHMx8QXcz2cexnVyRWsy4yQ9z3kbDpX+7fN0jnbdOp0b3KSTZJZ2Yb92JWSanLw==", + "dependencies": { + "@smithy/node-config-provider": "^2.2.1", + "@smithy/types": "^2.9.1", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@smithy/util-hex-encoding": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@smithy/util-hex-encoding/-/util-hex-encoding-2.1.1.tgz", + "integrity": "sha512-3UNdP2pkYUUBGEXzQI9ODTDK+Tcu1BlCyDBaRHwyxhA+8xLP8agEKQq4MGmpjqb4VQAjq9TwlCQX0kP6XDKYLg==", + "dependencies": { + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/util-middleware": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@smithy/util-middleware/-/util-middleware-2.1.1.tgz", + "integrity": "sha512-mKNrk8oz5zqkNcbcgAAepeJbmfUW6ogrT2Z2gDbIUzVzNAHKJQTYmH9jcy0jbWb+m7ubrvXKb6uMjkSgAqqsFA==", + "dependencies": { + "@smithy/types": "^2.9.1", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/util-retry": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@smithy/util-retry/-/util-retry-2.1.1.tgz", + "integrity": "sha512-Mg+xxWPTeSPrthpC5WAamJ6PW4Kbo01Fm7lWM1jmGRvmrRdsd3192Gz2fBXAMURyXpaNxyZf6Hr/nQ4q70oVEA==", + "dependencies": { + "@smithy/service-error-classification": "^2.1.1", + "@smithy/types": "^2.9.1", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@smithy/util-stream": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@smithy/util-stream/-/util-stream-2.1.1.tgz", + "integrity": "sha512-J7SMIpUYvU4DQN55KmBtvaMc7NM3CZ2iWICdcgaovtLzseVhAqFRYqloT3mh0esrFw+3VEK6nQFteFsTqZSECQ==", + "dependencies": { + "@smithy/fetch-http-handler": "^2.4.1", + "@smithy/node-http-handler": "^2.3.1", + "@smithy/types": "^2.9.1", + "@smithy/util-base64": "^2.1.1", + "@smithy/util-buffer-from": "^2.1.1", + "@smithy/util-hex-encoding": "^2.1.1", + "@smithy/util-utf8": "^2.1.1", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/util-uri-escape": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@smithy/util-uri-escape/-/util-uri-escape-2.1.1.tgz", + "integrity": "sha512-saVzI1h6iRBUVSqtnlOnc9ssU09ypo7n+shdQ8hBTZno/9rZ3AuRYvoHInV57VF7Qn7B+pFJG7qTzFiHxWlWBw==", + "dependencies": { + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/util-utf8": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@smithy/util-utf8/-/util-utf8-2.1.1.tgz", + "integrity": "sha512-BqTpzYEcUMDwAKr7/mVRUtHDhs6ZoXDi9NypMvMfOr/+u1NW7JgqodPDECiiLboEm6bobcPcECxzjtQh865e9A==", + "dependencies": { + "@smithy/util-buffer-from": "^2.1.1", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/util-waiter": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@smithy/util-waiter/-/util-waiter-2.1.1.tgz", + "integrity": "sha512-kYy6BLJJNif+uqNENtJqWdXcpqo1LS+nj1AfXcDhOpqpSHJSAkVySLyZV9fkmuVO21lzGoxjvd1imGGJHph/IA==", + "dependencies": { + "@smithy/abort-controller": "^2.1.1", + "@smithy/types": "^2.9.1", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@tsconfig/node10": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.9.tgz", + "integrity": "sha512-jNsYVVxU8v5g43Erja32laIDHXeoNvFEpX33OK4d6hljo3jDhCBDhx5dhCCTMWUojscpAagGiRkBKxpdl9fxqA==", + "dev": true + }, + "node_modules/@tsconfig/node12": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz", + "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==", + "dev": true + }, + "node_modules/@tsconfig/node14": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz", + "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==", + "dev": true + }, + "node_modules/@tsconfig/node16": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.4.tgz", + "integrity": "sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==", + "dev": true + }, + "node_modules/@types/bad-words": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/bad-words/-/bad-words-3.0.3.tgz", + "integrity": "sha512-jYdpTxDOJ+EENnsCwt8cOZhV/+4+qcwhks1igrOSg4zwwA17rsPqLsZpTo1l+OwViNu+5SPus0v5g7iGx+ofzA==", + "dev": true + }, + "node_modules/@types/config": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/@types/config/-/config-3.3.3.tgz", + "integrity": "sha512-BB8DBAud88EgiAKlz8WQStzI771Kb6F3j4dioRJ4GD+tP4tzcZyMlz86aXuZT4s9hyesFORehMQE6eqtA5O+Vg==", + "dev": true + }, + "node_modules/@types/jsdom": { + "version": "21.1.6", + "resolved": "https://registry.npmjs.org/@types/jsdom/-/jsdom-21.1.6.tgz", + "integrity": "sha512-/7kkMsC+/kMs7gAYmmBR9P0vGTnOoLhQhyhQJSlXGI5bzTHp6xdo0TtKWQAsz6pmSAeVqKSbqeyP6hytqr9FDw==", + "dev": true, + "dependencies": { + "@types/node": "*", + "@types/tough-cookie": "*", + "parse5": "^7.0.0" + } + }, + "node_modules/@types/node": { + "version": "18.19.6", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.6.tgz", + "integrity": "sha512-X36s5CXMrrJOs2lQCdDF68apW4Rfx9ixYMawlepwmE4Anezv/AV2LSpKD1Ub8DAc+urp5bk0BGZ6NtmBitfnsg==", + "dependencies": { + "undici-types": "~5.26.4" + } + }, + "node_modules/@types/node-fetch": { + "version": "2.6.10", + "resolved": "https://registry.npmjs.org/@types/node-fetch/-/node-fetch-2.6.10.tgz", + "integrity": "sha512-PPpPK6F9ALFTn59Ka3BaL+qGuipRfxNE8qVgkp0bVixeiR2c2/L+IVOiBdu9JhhT22sWnQEp6YyHGI2b2+CMcA==", + "dev": true, + "dependencies": { + "@types/node": "*", + "form-data": "^4.0.0" + } + }, + "node_modules/@types/tough-cookie": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/@types/tough-cookie/-/tough-cookie-4.0.5.tgz", + "integrity": "sha512-/Ad8+nIOV7Rl++6f1BdKxFSMgmoqEoYbHRpPcx3JEfv8VRsQe9Z4mCXeJBzxs7mbHY/XOZZuXlRNfhpVPbs6ZA==", + "dev": true + }, + "node_modules/@types/triple-beam": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/@types/triple-beam/-/triple-beam-1.3.5.tgz", + "integrity": "sha512-6WaYesThRMCl19iryMYP7/x2OVgCtbIVflDGFpWnb9irXI3UjYE4AzmYuiUKY1AJstGijoY+MgUszMgRxIYTYw==" + }, + "node_modules/@types/webidl-conversions": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/@types/webidl-conversions/-/webidl-conversions-7.0.3.tgz", + "integrity": "sha512-CiJJvcRtIgzadHCYXw7dqEnMNRjhGZlYK05Mj9OyktqV8uVT8fD2BFOB7S1uwBE3Kj2Z+4UyPmFw/Ixgw/LAlA==" + }, + "node_modules/@types/whatwg-url": { + "version": "8.2.2", + "resolved": "https://registry.npmjs.org/@types/whatwg-url/-/whatwg-url-8.2.2.tgz", + "integrity": "sha512-FtQu10RWgn3D9U4aazdwIE2yzphmTJREDqNdODHrbrZmmMqI0vMheC/6NE/J1Yveaj8H+ela+YwWTjq5PGmuhA==", + "dependencies": { + "@types/node": "*", + "@types/webidl-conversions": "*" + } + }, + "node_modules/@types/ws": { + "version": "8.5.9", + "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.9.tgz", + "integrity": "sha512-jbdrY0a8lxfdTp/+r7Z4CkycbOFN8WX+IOchLJr3juT/xzbJ8URyTVSJ/hvNdadTgM1mnedb47n+Y31GsFnQlg==", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@typescript-eslint/type-utils": { + "version": "8.0.0-alpha.30", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.0.0-alpha.30.tgz", + "integrity": "sha512-FrnhlCKEKZKRbpDviHkIU9tayIUGTOfa+SjvrRv6p/AJIUv6QT8oRboRjLH/cCuwUEbM0k5UtRWYug4albHUqQ==", + "dev": true, + "dependencies": { + "@typescript-eslint/typescript-estree": "8.0.0-alpha.30", + "@typescript-eslint/utils": "8.0.0-alpha.30", + "debug": "^4.3.4", + "ts-api-utils": "^1.3.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/@typescript-eslint/type-utils/node_modules/@typescript-eslint/types": { + "version": "8.0.0-alpha.30", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.0.0-alpha.30.tgz", + "integrity": "sha512-4WzLlw27SO9pK9UFj/Hu7WGo8WveT0SEiIpFVsV2WwtQmLps6kouwtVCB8GJPZKJyurhZhcqCoQVQFmpv441Vg==", + "dev": true, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/typescript-estree": { + "version": "8.0.0-alpha.30", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.0.0-alpha.30.tgz", + "integrity": "sha512-WSXbc9ZcXI+7yC+6q95u77i8FXz6HOLsw3ST+vMUlFy1lFbXyFL/3e6HDKQCm2Clt0krnoCPiTGvIn+GkYPn4Q==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "8.0.0-alpha.30", + "@typescript-eslint/visitor-keys": "8.0.0-alpha.30", + "debug": "^4.3.4", + "globby": "^11.1.0", + "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.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/visitor-keys": { + "version": "8.0.0-alpha.30", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.0.0-alpha.30.tgz", + "integrity": "sha512-XZuNurZxBqmr6ZIRIwWFq7j5RZd6ZlkId/HZEWyfciK+CWoyOxSF9Pv2VXH9Rlu2ZG2PfbhLz2Veszl4Pfn7yA==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "8.0.0-alpha.30", + "eslint-visitor-keys": "^3.4.3" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/type-utils/node_modules/minimatch": { + "version": "9.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.4.tgz", + "integrity": "sha512-KqWh+VchfxcMNRAJjj2tnsSJdNbHsVgnkBhTNrW7AjVo6OvLtxw8zfT9oLw1JSohlFzJ8jCoTgaoXvJ+kHt6fw==", + "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": "8.0.0-alpha.30", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.0.0-alpha.30.tgz", + "integrity": "sha512-rfhqfLqFyXhHNDwMnHiVGxl/Z2q/3guQ1jLlGQ0hi9Rb7inmwz42crM+NnLPR+2vEnwyw1P/g7fnQgQ3qvFx4g==", + "dev": true, + "dependencies": { + "@eslint-community/eslint-utils": "^4.4.0", + "@typescript-eslint/scope-manager": "8.0.0-alpha.30", + "@typescript-eslint/types": "8.0.0-alpha.30", + "@typescript-eslint/typescript-estree": "8.0.0-alpha.30" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0" + } + }, + "node_modules/@typescript-eslint/utils/node_modules/@typescript-eslint/scope-manager": { + "version": "8.0.0-alpha.30", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.0.0-alpha.30.tgz", + "integrity": "sha512-FGW/iPWGyPFamAVZ60oCAthMqQrqafUGebF8UKuq/ha+e9SVG6YhJoRzurlQXOVf8dHfOhJ0ADMXyFnMc53clg==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "8.0.0-alpha.30", + "@typescript-eslint/visitor-keys": "8.0.0-alpha.30" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/utils/node_modules/@typescript-eslint/types": { + "version": "8.0.0-alpha.30", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.0.0-alpha.30.tgz", + "integrity": "sha512-4WzLlw27SO9pK9UFj/Hu7WGo8WveT0SEiIpFVsV2WwtQmLps6kouwtVCB8GJPZKJyurhZhcqCoQVQFmpv441Vg==", + "dev": true, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/utils/node_modules/@typescript-eslint/typescript-estree": { + "version": "8.0.0-alpha.30", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.0.0-alpha.30.tgz", + "integrity": "sha512-WSXbc9ZcXI+7yC+6q95u77i8FXz6HOLsw3ST+vMUlFy1lFbXyFL/3e6HDKQCm2Clt0krnoCPiTGvIn+GkYPn4Q==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "8.0.0-alpha.30", + "@typescript-eslint/visitor-keys": "8.0.0-alpha.30", + "debug": "^4.3.4", + "globby": "^11.1.0", + "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.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/utils/node_modules/@typescript-eslint/visitor-keys": { + "version": "8.0.0-alpha.30", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.0.0-alpha.30.tgz", + "integrity": "sha512-XZuNurZxBqmr6ZIRIwWFq7j5RZd6ZlkId/HZEWyfciK+CWoyOxSF9Pv2VXH9Rlu2ZG2PfbhLz2Veszl4Pfn7yA==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "8.0.0-alpha.30", + "eslint-visitor-keys": "^3.4.3" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/utils/node_modules/minimatch": { + "version": "9.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.4.tgz", + "integrity": "sha512-KqWh+VchfxcMNRAJjj2tnsSJdNbHsVgnkBhTNrW7AjVo6OvLtxw8zfT9oLw1JSohlFzJ8jCoTgaoXvJ+kHt6fw==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@vladfrangu/async_event_emitter": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/@vladfrangu/async_event_emitter/-/async_event_emitter-2.2.4.tgz", + "integrity": "sha512-ButUPz9E9cXMLgvAW8aLAKKJJsPu1dY1/l/E8xzLFuysowXygs6GBcyunK9rnGC4zTsnIc2mQo71rGw9U+Ykug==", + "engines": { + "node": ">=v14.0.0", + "npm": ">=7.0.0" + } + }, + "node_modules/abbrev": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", + "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", + "dev": true + }, + "node_modules/acorn": { + "version": "8.11.3", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.3.tgz", + "integrity": "sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==", + "dev": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true, + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/acorn-walk": { + "version": "8.3.1", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.1.tgz", + "integrity": "sha512-TgUZgYvqZprrl7YldZNoa9OciCAyZR+Ejm9eXzKCmjsF5IKp/wgQ7Z/ZpjpGTIUPwrHQIcYeI8qDh4PsEwxMbw==", + "dev": true, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/agent-base": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.0.tgz", + "integrity": "sha512-o/zjMZRhJxny7OyEF+Op8X+efiELC7k7yOjMzgfzVqOzXqkBkWI79YoTdOtsuWd5BWhAGAuOY/Xa6xpiaWXiNg==", + "dependencies": { + "debug": "^4.3.4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "dev": true, + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/arg": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", + "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", + "dev": true + }, + "node_modules/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 + }, + "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/async": { + "version": "3.2.5", + "resolved": "https://registry.npmjs.org/async/-/async-3.2.5.tgz", + "integrity": "sha512-baNZyqaaLhyLVKm/DlvdW051MSgO6b8eVfIezl9E5PqWxFgzLm/wQntEW4zOytVburDEr0JlALEpdOFwvErLsg==" + }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" + }, + "node_modules/bad-words": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/bad-words/-/bad-words-3.0.4.tgz", + "integrity": "sha512-v/Q9uRPH4+yzDVLL4vR1+S9KoFgOEUl5s4axd6NIAq8SV2mradgi4E8lma/Y0cw1ltVdvyegCQQKffCPRCp8fg==", + "dependencies": { + "badwords-list": "^1.0.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/badwords-list": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/badwords-list/-/badwords-list-1.0.0.tgz", + "integrity": "sha512-oWhaSG67e+HQj3OGHQt2ucP+vAPm1wTbdp2aDHeuh4xlGXBdWwzZ//pfu6swf5gZ8iX0b7JgmSo8BhgybbqszA==" + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true + }, + "node_modules/base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/bidi-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/bidi-js/-/bidi-js-1.0.3.tgz", + "integrity": "sha512-RKshQI1R3YQ+n9YJz2QQ147P66ELpa1FQEg20Dk8oW9t2KgLbpDLLp9aGZ7y8WHSshDknG0bknqGw5/tyCs5tw==", + "dependencies": { + "require-from-string": "^2.0.2" + } + }, + "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==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/bowser": { + "version": "2.11.0", + "resolved": "https://registry.npmjs.org/bowser/-/bowser-2.11.0.tgz", + "integrity": "sha512-AlcaJBi/pqqJBIQ8U9Mcpc9i8Aqxn88Skv5d+xBX006BY5u8N3mGLHa5Lgppa7L/HfwgwLgZ6NYs+Ag6uUmJRA==" + }, + "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/braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dev": true, + "dependencies": { + "fill-range": "^7.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/bson": { + "version": "4.7.2", + "resolved": "https://registry.npmjs.org/bson/-/bson-4.7.2.tgz", + "integrity": "sha512-Ry9wCtIZ5kGqkJoi6aD8KjxFZEx78guTQDnpXWiNthsxzrxAK/i8E6pCHAIZTbaEFWcOCvbecMukfK7XUvyLpQ==", + "dependencies": { + "buffer": "^5.6.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/buffer": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", + "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.1.13" + } + }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/chokidar": { + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", + "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + ], + "dependencies": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/color": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/color/-/color-3.2.1.tgz", + "integrity": "sha512-aBl7dZI9ENN6fUGC7mWpMTPNHmWUSNan9tuWN6ahh5ZLNk9baLJOnSMlrQkHcrfFgz2/RigjUVAjdx36VcemKA==", + "dependencies": { + "color-convert": "^1.9.3", + "color-string": "^1.6.0" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "node_modules/color-string": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/color-string/-/color-string-1.9.1.tgz", + "integrity": "sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==", + "dependencies": { + "color-name": "^1.0.0", + "simple-swizzle": "^0.2.2" + } + }, + "node_modules/color/node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/color/node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==" + }, + "node_modules/colorspace": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/colorspace/-/colorspace-1.1.4.tgz", + "integrity": "sha512-BgvKJiuVu1igBUF2kEjRCZXol6wiiGbY5ipL/oVPwm0BL9sIpMIzM8IK7vwuxIIzOXMV3Ey5w+vxhm0rR/TN8w==", + "dependencies": { + "color": "^3.1.3", + "text-hex": "1.0.x" + } + }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true + }, + "node_modules/config": { + "version": "3.3.10", + "resolved": "https://registry.npmjs.org/config/-/config-3.3.10.tgz", + "integrity": "sha512-9Kl3LpQ6zj93KaqgfIMTcpwTpgozFOqNl/Dk7mjras1BgGIOlqxWkyIGeU1my+sRuskRYwrCATgCk1RjAnRPGA==", + "dependencies": { + "json5": "^2.2.3" + }, + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/create-require": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", + "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", + "dev": true + }, + "node_modules/cron-parser": { + "version": "4.9.0", + "resolved": "https://registry.npmjs.org/cron-parser/-/cron-parser-4.9.0.tgz", + "integrity": "sha512-p0SaNjrHOnQeR8/VnfGbmg9te2kfyYSQ7Sc/j/6DtPL3JQvKxmjO9TSjNFpujqV3vEYYBvNNvXSxzyksBWAx1Q==", + "dependencies": { + "luxon": "^3.2.1" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dev": true, + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/css-tree": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-2.3.1.tgz", + "integrity": "sha512-6Fv1DV/TYw//QF5IzQdqsNDjx/wc8TrMBZsqjL9eW01tWb7R7k/mq+/VXfJCl7SoD5emsJop9cOByJZfs8hYIw==", + "dependencies": { + "mdn-data": "2.0.30", + "source-map-js": "^1.0.1" + }, + "engines": { + "node": "^10 || ^12.20.0 || ^14.13.0 || >=15.0.0" + } + }, + "node_modules/cssstyle": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-4.0.1.tgz", + "integrity": "sha512-8ZYiJ3A/3OkDd093CBT/0UKDWry7ak4BdPTFP2+QEP7cmhouyq/Up709ASSj2cK02BbZiMgk7kYjZNS4QP5qrQ==", + "dependencies": { + "rrweb-cssom": "^0.6.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/data-urls": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-5.0.0.tgz", + "integrity": "sha512-ZYP5VBHshaDAiVZxjbRVcFJpc+4xGgT0bK3vzy1HLN8jTO975HEbuYzZJcHoQEY5K1a0z8YayJkyVETa08eNTg==", + "dependencies": { + "whatwg-mimetype": "^4.0.0", + "whatwg-url": "^14.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/data-urls/node_modules/tr46": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-5.0.0.tgz", + "integrity": "sha512-tk2G5R2KRwBd+ZN0zaEXpmzdKyOYksXwywulIX95MBODjSzMIuQnQ3m8JxgbhnL1LeVo7lqQKsYa1O3Htl7K5g==", + "dependencies": { + "punycode": "^2.3.1" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/data-urls/node_modules/whatwg-url": { + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-14.0.0.tgz", + "integrity": "sha512-1lfMEm2IEr7RIV+f4lUNPOqfFL+pO+Xw3fJSqmjX9AbXcXcYOkCe1P6+9VBZB6n94af16NfZf+sSk0JCBZC9aw==", + "dependencies": { + "tr46": "^5.0.0", + "webidl-conversions": "^7.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/date.js": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/date.js/-/date.js-0.3.3.tgz", + "integrity": "sha512-HgigOS3h3k6HnW011nAb43c5xx5rBXk8P2v/WIT9Zv4koIaVXiH2BURguI78VVp+5Qc076T7OR378JViCnZtBw==", + "dependencies": { + "debug": "~3.1.0" + } + }, + "node_modules/date.js/node_modules/debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/date.js/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + }, + "node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/decimal.js": { + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.4.3.tgz", + "integrity": "sha512-VBBaLc1MgL5XpzgIP7ny5Z6Nx3UrRkIViUkPUdtl9aya5amy3De1gsUUSB1g3+3sExYNjCAsAznmukyxCb1GRA==" + }, + "node_modules/deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true + }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/deprecation": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/deprecation/-/deprecation-2.3.1.tgz", + "integrity": "sha512-xmHIy4F3scKVwMsQ4WnVaS8bHOx0DmVwRywosKhaILI0ywMDWPtBSku2HNxRvF7jtwDRsoEwYQSfbxj8b7RlJQ==" + }, + "node_modules/diff": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", + "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", + "dev": true, + "engines": { + "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.61", + "resolved": "https://registry.npmjs.org/discord-api-types/-/discord-api-types-0.37.61.tgz", + "integrity": "sha512-o/dXNFfhBpYHpQFdT6FWzeO7pKc838QeeZ9d91CfVAtpr5XLK4B/zYxQbYgPdoMiTDvJfzcsLW5naXgmHGDNXw==" + }, + "node_modules/discord.js": { + "version": "14.14.1", + "resolved": "https://registry.npmjs.org/discord.js/-/discord.js-14.14.1.tgz", + "integrity": "sha512-/hUVzkIerxKHyRKopJy5xejp4MYKDPTszAnpYxzVVv4qJYf+Tkt+jnT2N29PIPschicaEEpXwF2ARrTYHYwQ5w==", + "dependencies": { + "@discordjs/builders": "^1.7.0", + "@discordjs/collection": "1.5.3", + "@discordjs/formatters": "^0.3.3", + "@discordjs/rest": "^2.1.0", + "@discordjs/util": "^1.0.2", + "@discordjs/ws": "^1.0.2", + "@sapphire/snowflake": "3.5.1", + "@types/ws": "8.5.9", + "discord-api-types": "0.37.61", + "fast-deep-equal": "3.1.3", + "lodash.snakecase": "4.1.1", + "tslib": "2.6.2", + "undici": "5.27.2", + "ws": "8.14.2" + }, + "engines": { + "node": ">=16.11.0" + } + }, + "node_modules/dotenv": { + "version": "16.3.1", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.3.1.tgz", + "integrity": "sha512-IPzF4w4/Rd94bA9imS68tZBaYyBWSCE47V1RGuMrB94iyTOIEwRmVL2x/4An+6mETpLrKJ5hQkB8W4kFAadeIQ==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/motdotla/dotenv?sponsor=1" + } + }, + "node_modules/enabled": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/enabled/-/enabled-2.0.0.tgz", + "integrity": "sha512-AKrN98kuwOzMIdAizXGI86UFBoo26CL21UM763y1h/GMSJ4/OHU9k2YlsmBpyScFo/wbLzWQJBMCW4+IO3/+OQ==" + }, + "node_modules/entities": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", + "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint": { + "version": "9.4.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.4.0.tgz", + "integrity": "sha512-sjc7Y8cUD1IlwYcTS9qPSvGjAC8Ne9LctpxKKu3x/1IC9bnOg98Zy6GxEJUfr1NojMgVPlyANXYns8oE2c1TAA==", + "dev": true, + "dependencies": { + "@eslint-community/eslint-utils": "^4.2.0", + "@eslint-community/regexpp": "^4.6.1", + "@eslint/config-array": "^0.15.1", + "@eslint/eslintrc": "^3.1.0", + "@eslint/js": "9.4.0", + "@humanwhocodes/module-importer": "^1.0.1", + "@humanwhocodes/retry": "^0.3.0", + "@nodelib/fs.walk": "^1.2.8", + "ajv": "^6.12.4", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.2", + "debug": "^4.3.2", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^8.0.1", + "eslint-visitor-keys": "^4.0.0", + "espree": "^10.0.1", + "esquery": "^1.4.2", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^8.0.0", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "ignore": "^5.2.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "is-path-inside": "^3.0.3", + "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" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-config-prettier": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-9.1.0.tgz", + "integrity": "sha512-NSWl5BFQWEPi1j4TjVNItzYV7dZXZ+wP6I6ZhrBGpChQhZRUaElihE9uRRkcbRnNb76UMKDF3r+WTmNcGPKsqw==", + "dev": true, + "bin": { + "eslint-config-prettier": "bin/cli.js" + }, + "peerDependencies": { + "eslint": ">=7.0.0" + } + }, + "node_modules/eslint-plugin-prettier": { + "version": "5.1.3", + "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-5.1.3.tgz", + "integrity": "sha512-C9GCVAs4Eq7ZC/XFQHITLiHJxQngdtraXaM+LoUFoFp/lHNl2Zn8f3WQbe9HvTBBQ9YnKFB0/2Ajdqwo5D1EAw==", + "dev": true, + "dependencies": { + "prettier-linter-helpers": "^1.0.0", + "synckit": "^0.8.6" + }, + "engines": { + "node": "^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint-plugin-prettier" + }, + "peerDependencies": { + "@types/eslint": ">=8.0.0", + "eslint": ">=8.0.0", + "eslint-config-prettier": "*", + "prettier": ">=3.0.0" + }, + "peerDependenciesMeta": { + "@types/eslint": { + "optional": true + }, + "eslint-config-prettier": { + "optional": true + } + } + }, + "node_modules/eslint-scope": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.0.1.tgz", + "integrity": "sha512-pL8XjgP4ZOmmwfFE8mEhSxA7ZY4C+LWyqjQ3o4yWkkmD0qcMT9kkW3zWHOczhWcjTSgqycYAgwSlXvZltv65og==", + "dev": true, + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "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, + "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, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint/node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "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, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/espree": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-10.0.1.tgz", + "integrity": "sha512-MWkrWZbJsL2UwnjxTX3gG8FneachS/Mwg7tdGXce011sJd5b0JG54vat5KHnfSBODZ3Wvzd2WnjxyzsRoVv+ww==", + "dev": true, + "dependencies": { + "acorn": "^8.11.3", + "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/espree/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, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/esquery": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.5.0.tgz", + "integrity": "sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==", + "dev": true, + "dependencies": { + "estraverse": "^5.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/events": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", + "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", + "engines": { + "node": ">=0.8.x" + } + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" + }, + "node_modules/fast-diff": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.3.0.tgz", + "integrity": "sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw==", + "dev": true + }, + "node_modules/fast-glob": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz", + "integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==", + "dev": true, + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.4" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/fast-json-stable-stringify": { + "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 + }, + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", + "dev": true + }, + "node_modules/fast-xml-parser": { + "version": "4.2.5", + "resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-4.2.5.tgz", + "integrity": "sha512-B9/wizE4WngqQftFPmdaMYlXoJlJOYxGQOanC77fq9k8+Z0v5dDSVh+3glErdIROP//s/jgb7ZuxKfB8nVyo0g==", + "funding": [ + { + "type": "paypal", + "url": "https://paypal.me/naturalintelligence" + }, + { + "type": "github", + "url": "https://github.com/sponsors/NaturalIntelligence" + } + ], + "dependencies": { + "strnum": "^1.0.5" + }, + "bin": { + "fxparser": "src/cli/cli.js" + } + }, + "node_modules/fastq": { + "version": "1.16.0", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.16.0.tgz", + "integrity": "sha512-ifCoaXsDrsdkWTtiNJX5uzHDsrck5TzfKKDcuFFTIrrc/BS076qgEIfoIy1VeZqViznfKiysPYTh/QeHtnIsYA==", + "dev": true, + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/fecha": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/fecha/-/fecha-4.2.3.tgz", + "integrity": "sha512-OP2IUU6HeYKJi3i0z4A19kHMQoLVs4Hc+DPqqxI2h/DPZHTm/vjsfC6P0b4jCMy14XizLBqvndQ+UilD7707Jw==" + }, + "node_modules/file-entry-cache": { + "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, + "dependencies": { + "flat-cache": "^4.0.0" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "dev": true, + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/flat-cache": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz", + "integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==", + "dev": true, + "dependencies": { + "flatted": "^3.2.9", + "keyv": "^4.5.4" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/flatted": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.1.tgz", + "integrity": "sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==", + "dev": true + }, + "node_modules/fn.name": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/fn.name/-/fn.name-1.1.0.tgz", + "integrity": "sha512-GRnmB5gPyJpAhTQdSZTSp9uaPSvl09KoYcMQtsB9rQoOmzs9dH6ffeccH+Z+cv6P68Hu5bC6JjRh4Ah/mHSNRw==" + }, + "node_modules/form-data": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", + "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/globals": { + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz", + "integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==", + "dev": true, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "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/graphemer": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", + "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", + "dev": true + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/html-encoding-sniffer": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-4.0.0.tgz", + "integrity": "sha512-Y22oTqIU4uuPgEemfz7NDJz6OeKf12Lsu+QC+s3BVpda64lTiMYCyGwg5ki4vFxkMwQdeZDl2adZoqUgdFuTgQ==", + "dependencies": { + "whatwg-encoding": "^3.1.1" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/http-proxy-agent": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.0.tgz", + "integrity": "sha512-+ZT+iBxVUQ1asugqnD6oWoRiS25AkjNfG085dKJGtGxkdwLQrMKU5wJr2bOOFAXzKcTuqq+7fZlTMgG3SRfIYQ==", + "dependencies": { + "agent-base": "^7.1.0", + "debug": "^4.3.4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/https-proxy-agent": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.2.tgz", + "integrity": "sha512-NmLNjm6ucYwtcUmL7JQC1ZQ57LmHP4lT15FQ8D61nak1rO6DH+fz5qNK2Ap5UN4ZapYICE3/0KodcLYSPsPbaA==", + "dependencies": { + "agent-base": "^7.0.2", + "debug": "4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/human-interval": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/human-interval/-/human-interval-2.0.1.tgz", + "integrity": "sha512-r4Aotzf+OtKIGQCB3odUowy4GfUDTy3aTWTfLd7ZF2gBCy3XW3v/dJLRefZnOFFnjqs5B1TypvS8WarpBkYUNQ==", + "dependencies": { + "numbered": "^1.1.0" + } + }, + "node_modules/iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/ignore": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.1.tgz", + "integrity": "sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw==", + "dev": true, + "engines": { + "node": ">= 4" + } + }, + "node_modules/ignore-by-default": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/ignore-by-default/-/ignore-by-default-1.0.1.tgz", + "integrity": "sha512-Ius2VYcGNk7T90CppJqcIkS5ooHUZyIQK+ClZfMfMNFEF9VSE73Fq+906u/CWu92x4gzZMWOwfFYckPObzdEbA==", + "dev": true + }, + "node_modules/import-fresh": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", + "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "dev": true, + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "dev": true, + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + }, + "node_modules/ip": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ip/-/ip-2.0.0.tgz", + "integrity": "sha512-WKa+XuLG1A1R0UWhl2+1XQSi+fZWMsYKffMZTTYsiZaUD8k2yDAj5atimTUD2TZkyCkNEeYE5NhFZmupOGtjYQ==" + }, + "node_modules/is-arrayish": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz", + "integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==" + }, + "node_modules/is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dev": true, + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-path-inside": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", + "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-potential-custom-element-name": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz", + "integrity": "sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==" + }, + "node_modules/is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true + }, + "node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/jsdom": { + "version": "23.2.0", + "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-23.2.0.tgz", + "integrity": "sha512-L88oL7D/8ufIES+Zjz7v0aes+oBMh2Xnh3ygWvL0OaICOomKEPKuPnIfBJekiXr+BHbbMjrWn/xqrDQuxFTeyA==", + "dependencies": { + "@asamuzakjp/dom-selector": "^2.0.1", + "cssstyle": "^4.0.1", + "data-urls": "^5.0.0", + "decimal.js": "^10.4.3", + "form-data": "^4.0.0", + "html-encoding-sniffer": "^4.0.0", + "http-proxy-agent": "^7.0.0", + "https-proxy-agent": "^7.0.2", + "is-potential-custom-element-name": "^1.0.1", + "parse5": "^7.1.2", + "rrweb-cssom": "^0.6.0", + "saxes": "^6.0.0", + "symbol-tree": "^3.2.4", + "tough-cookie": "^4.1.3", + "w3c-xmlserializer": "^5.0.0", + "webidl-conversions": "^7.0.0", + "whatwg-encoding": "^3.1.1", + "whatwg-mimetype": "^4.0.0", + "whatwg-url": "^14.0.0", + "ws": "^8.16.0", + "xml-name-validator": "^5.0.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "canvas": "^2.11.2" + }, + "peerDependenciesMeta": { + "canvas": { + "optional": true + } + } + }, + "node_modules/jsdom/node_modules/tr46": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-5.0.0.tgz", + "integrity": "sha512-tk2G5R2KRwBd+ZN0zaEXpmzdKyOYksXwywulIX95MBODjSzMIuQnQ3m8JxgbhnL1LeVo7lqQKsYa1O3Htl7K5g==", + "dependencies": { + "punycode": "^2.3.1" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/jsdom/node_modules/whatwg-url": { + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-14.0.0.tgz", + "integrity": "sha512-1lfMEm2IEr7RIV+f4lUNPOqfFL+pO+Xw3fJSqmjX9AbXcXcYOkCe1P6+9VBZB6n94af16NfZf+sSk0JCBZC9aw==", + "dependencies": { + "tr46": "^5.0.0", + "webidl-conversions": "^7.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/jsdom/node_modules/ws": { + "version": "8.16.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.16.0.tgz", + "integrity": "sha512-HS0c//TP7Ina87TfiPUz1rQzMhHrl/SG2guqRcTOIUYD2q8uhUdNHZYJUaQ8aTGPzCh+c6oawMKW35nFl1dxyQ==", + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "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 + }, + "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 + }, + "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 + }, + "node_modules/json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/kareem": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/kareem/-/kareem-2.5.1.tgz", + "integrity": "sha512-7jFxRVm+jD+rkq3kY0iZDJfsO2/t4BBPeEb2qKn2lR/9KhuksYk5hxzfRYWMPV8P/x2d0kHD306YyWLzjjH+uA==", + "engines": { + "node": ">=12.0.0" + } + }, + "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, + "dependencies": { + "json-buffer": "3.0.1" + } + }, + "node_modules/kuler": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/kuler/-/kuler-2.0.0.tgz", + "integrity": "sha512-Xq9nH7KlWZmXAtodXDDRE7vs6DU1gTU8zYDHDiWLSip45Egwq3plLHzPn27NgvzL2r1LMPC1vdqh98sQxtqj4A==" + }, + "node_modules/levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" + }, + "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 + }, + "node_modules/lodash.snakecase": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/lodash.snakecase/-/lodash.snakecase-4.1.1.tgz", + "integrity": "sha512-QZ1d4xoBHYUeuouhEq3lk3Uq7ldgyFXGBhg04+oRLnIz8o9T65Eh+8YdroUwn846zchkA9yDsDl5CVVaV2nqYw==" + }, + "node_modules/logform": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/logform/-/logform-2.6.0.tgz", + "integrity": "sha512-1ulHeNPp6k/LD8H91o7VYFBng5i1BDE7HoKxVbZiGFidS1Rj65qcywLxX+pVfAPoQJEjRdvKcusKwOupHCVOVQ==", + "dependencies": { + "@colors/colors": "1.6.0", + "@types/triple-beam": "^1.3.2", + "fecha": "^4.2.0", + "ms": "^2.1.1", + "safe-stable-stringify": "^2.3.1", + "triple-beam": "^1.3.0" + }, + "engines": { + "node": ">= 12.0.0" + } + }, + "node_modules/luxon": { + "version": "3.4.4", + "resolved": "https://registry.npmjs.org/luxon/-/luxon-3.4.4.tgz", + "integrity": "sha512-zobTr7akeGHnv7eBOXcRgMeCP6+uyYsczwmeRCauvpvaAltgNyTbLH/+VaEAPUeWBT+1GuNmz4wC/6jtQzbbVA==", + "engines": { + "node": ">=12" + } + }, + "node_modules/magic-bytes.js": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/magic-bytes.js/-/magic-bytes.js-1.7.0.tgz", + "integrity": "sha512-YzVU2+/hrjwx8xcgAw+ffNq3jkactpj+f1iSL4LonrFKhvnwDzHSqtFdk/MMRP53y9ScouJ7cKEnqYsJwsHoYA==" + }, + "node_modules/make-error": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", + "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", + "dev": true + }, + "node_modules/mdn-data": { + "version": "2.0.30", + "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.30.tgz", + "integrity": "sha512-GaqWWShW4kv/G9IEucWScBx9G1/vsFZZJUO+tD26M8J8z3Kw5RDQjaoZe03YAClgeS/SWPOcb4nkFBTEi5DUEA==" + }, + "node_modules/memory-pager": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/memory-pager/-/memory-pager-1.5.0.tgz", + "integrity": "sha512-ZS4Bp4r/Zoeq6+NLJpP+0Zzm0pR8whtGPf1XExKLJBAczGMnSi3It14OiNCStjQjM6NU1okjQGSxgEZN8eBYKg==" + }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/micromatch": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", + "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", + "dev": true, + "dependencies": { + "braces": "^3.0.2", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/moment": { + "version": "2.30.1", + "resolved": "https://registry.npmjs.org/moment/-/moment-2.30.1.tgz", + "integrity": "sha512-uEmtNhbDOrWPFS+hdjFCBfy9f2YoyzRpwcl+DqpC6taX21FzsTLQVbMV/W7PzNSX6x/bhC1zA3c2UQ5NzH6how==", + "engines": { + "node": "*" + } + }, + "node_modules/mongodb": { + "version": "4.17.2", + "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-4.17.2.tgz", + "integrity": "sha512-mLV7SEiov2LHleRJPMPrK2PMyhXFZt2UQLC4VD4pnth3jMjYKHhtqfwwkkvS/NXuo/Fp3vbhaNcXrIDaLRb9Tg==", + "dependencies": { + "bson": "^4.7.2", + "mongodb-connection-string-url": "^2.6.0", + "socks": "^2.7.1" + }, + "engines": { + "node": ">=12.9.0" + }, + "optionalDependencies": { + "@aws-sdk/credential-providers": "^3.186.0", + "@mongodb-js/saslprep": "^1.1.0" + } + }, + "node_modules/mongodb-connection-string-url": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/mongodb-connection-string-url/-/mongodb-connection-string-url-2.6.0.tgz", + "integrity": "sha512-WvTZlI9ab0QYtTYnuMLgobULWhokRjtC7db9LtcVfJ+Hsnyr5eo6ZtNAt3Ly24XZScGMelOcGtm7lSn0332tPQ==", + "dependencies": { + "@types/whatwg-url": "^8.2.1", + "whatwg-url": "^11.0.0" + } + }, + "node_modules/mongoose": { + "version": "8.0.4", + "resolved": "https://registry.npmjs.org/mongoose/-/mongoose-8.0.4.tgz", + "integrity": "sha512-wN9qvdevX3+922VnLT7CpaZRT3jmVCBOK2QMHMGeScQxDRnFMPpkuI9StEPpZo/3x8t+kbzH7F8RMPsyNwyM4w==", + "dependencies": { + "bson": "^6.2.0", + "kareem": "2.5.1", + "mongodb": "6.2.0", + "mpath": "0.9.0", + "mquery": "5.0.0", + "ms": "2.1.3", + "sift": "16.0.1" + }, + "engines": { + "node": ">=16.20.1" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mongoose" + } + }, + "node_modules/mongoose/node_modules/bson": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/bson/-/bson-6.2.0.tgz", + "integrity": "sha512-ID1cI+7bazPDyL9wYy9GaQ8gEEohWvcUl/Yf0dIdutJxnmInEEyCsb4awy/OiBfall7zBA179Pahi3vCdFze3Q==", + "engines": { + "node": ">=16.20.1" + } + }, + "node_modules/mongoose/node_modules/mongodb": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-6.2.0.tgz", + "integrity": "sha512-d7OSuGjGWDZ5usZPqfvb36laQ9CPhnWkAGHT61x5P95p/8nMVeH8asloMwW6GcYFeB0Vj4CB/1wOTDG2RA9BFA==", + "dependencies": { + "@mongodb-js/saslprep": "^1.1.0", + "bson": "^6.2.0", + "mongodb-connection-string-url": "^2.6.0" + }, + "engines": { + "node": ">=16.20.1" + }, + "peerDependencies": { + "@aws-sdk/credential-providers": "^3.188.0", + "@mongodb-js/zstd": "^1.1.0", + "gcp-metadata": "^5.2.0", + "kerberos": "^2.0.1", + "mongodb-client-encryption": ">=6.0.0 <7", + "snappy": "^7.2.2", + "socks": "^2.7.1" + }, + "peerDependenciesMeta": { + "@aws-sdk/credential-providers": { + "optional": true + }, + "@mongodb-js/zstd": { + "optional": true + }, + "gcp-metadata": { + "optional": true + }, + "kerberos": { + "optional": true + }, + "mongodb-client-encryption": { + "optional": true + }, + "snappy": { + "optional": true + }, + "socks": { + "optional": true + } + } + }, + "node_modules/mongoose/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==" + }, + "node_modules/mpath": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/mpath/-/mpath-0.9.0.tgz", + "integrity": "sha512-ikJRQTk8hw5DEoFVxHG1Gn9T/xcjtdnOKIU1JTmGjZZlg9LST2mBLmcX3/ICIbgJydT2GOc15RnNy5mHmzfSew==", + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/mquery": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/mquery/-/mquery-5.0.0.tgz", + "integrity": "sha512-iQMncpmEK8R8ncT8HJGsGc9Dsp8xcgYMVSbs5jgnm1lFHTZqMJTUWTDx1LBO8+mK3tPNZWFLBghQEIOULSTHZg==", + "dependencies": { + "debug": "4.x" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "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==" + }, + "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 + }, + "node_modules/node-fetch": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", + "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", + "dependencies": { + "whatwg-url": "^5.0.0" + }, + "engines": { + "node": "4.x || >=6.0.0" + }, + "peerDependencies": { + "encoding": "^0.1.0" + }, + "peerDependenciesMeta": { + "encoding": { + "optional": true + } + } + }, + "node_modules/node-fetch/node_modules/tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" + }, + "node_modules/node-fetch/node_modules/webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==" + }, + "node_modules/node-fetch/node_modules/whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "dependencies": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, + "node_modules/nodemon": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-3.0.2.tgz", + "integrity": "sha512-9qIN2LNTrEzpOPBaWHTm4Asy1LxXLSickZStAQ4IZe7zsoIpD/A7LWxhZV3t4Zu352uBcqVnRsDXSMR2Sc3lTA==", + "dev": true, + "dependencies": { + "chokidar": "^3.5.2", + "debug": "^4", + "ignore-by-default": "^1.0.1", + "minimatch": "^3.1.2", + "pstree.remy": "^1.1.8", + "semver": "^7.5.3", + "simple-update-notifier": "^2.0.0", + "supports-color": "^5.5.0", + "touch": "^3.1.0", + "undefsafe": "^2.0.5" + }, + "bin": { + "nodemon": "bin/nodemon.js" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/nodemon" + } + }, + "node_modules/nodemon/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, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/nodemon/node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/nodemon/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, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/nodemon/node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/nopt": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-1.0.10.tgz", + "integrity": "sha512-NWmpvLSqUrgrAC9HCuxEvb+PSloHpqVu+FqcO4eeF2h5qYRhA7ev6KvelyQAKtegUbC6RypJnlEOhd8vloNKYg==", + "dev": true, + "dependencies": { + "abbrev": "1" + }, + "bin": { + "nopt": "bin/nopt.js" + }, + "engines": { + "node": "*" + } + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/numbered": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/numbered/-/numbered-1.1.0.tgz", + "integrity": "sha512-pv/ue2Odr7IfYOO0byC1KgBI10wo5YDauLhxY6/saNzAdAs0r1SotGCPzzCLNPL0xtrAwWRialLu23AAu9xO1g==" + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/one-time": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/one-time/-/one-time-1.0.0.tgz", + "integrity": "sha512-5DXOiRKwuSEcQ/l0kGCF6Q3jcADFv5tSmRaJck/OqkVFcOzutB134KRSfF0xDrL39MNnqxbHBbUUcjZIhTgb2g==", + "dependencies": { + "fn.name": "1.x.x" + } + }, + "node_modules/optionator": { + "version": "0.9.3", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.3.tgz", + "integrity": "sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg==", + "dev": true, + "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" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "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, + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/parse5": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.1.2.tgz", + "integrity": "sha512-Czj1WaSVpaoj0wbhMzLmWD69anp2WH7FXMB9n1Sy8/ZFF9jolSQVMu1Ij5WIyGmcBmhk7EOndpO4mIpihVqAXw==", + "dependencies": { + "entities": "^4.4.0" + }, + "funding": { + "url": "https://github.com/inikulin/parse5?sponsor=1" + } + }, + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "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==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/prettier": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.3.2.tgz", + "integrity": "sha512-rAVeHYMcv8ATV5d508CFdn+8/pHPpXeIid1DdrPwXnaAdH7cqjVbpJaT5eq4yRAFU/lsbwYwSF/n5iNrdJHPQA==", + "dev": true, + "bin": { + "prettier": "bin/prettier.cjs" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } + }, + "node_modules/prettier-linter-helpers": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz", + "integrity": "sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==", + "dev": true, + "dependencies": { + "fast-diff": "^1.1.2" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/psl": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/psl/-/psl-1.9.0.tgz", + "integrity": "sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag==" + }, + "node_modules/pstree.remy": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/pstree.remy/-/pstree.remy-1.1.8.tgz", + "integrity": "sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w==", + "dev": true + }, + "node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "engines": { + "node": ">=6" + } + }, + "node_modules/querystringify": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz", + "integrity": "sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==" + }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dev": true, + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/require-from-string": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/requires-port": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", + "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==" + }, + "node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/reusify": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "dev": true, + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "node_modules/rrweb-cssom": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/rrweb-cssom/-/rrweb-cssom-0.6.0.tgz", + "integrity": "sha512-APM0Gt1KoXBz0iIkkdB/kfvGOwC4UuJFeG/c+yV7wSc7q96cG/kJ0HiYCnzivD9SB53cLV1MlHFNfOuPaadYSw==" + }, + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/safe-stable-stringify": { + "version": "2.4.3", + "resolved": "https://registry.npmjs.org/safe-stable-stringify/-/safe-stable-stringify-2.4.3.tgz", + "integrity": "sha512-e2bDA2WJT0wxseVd4lsDP4+3ONX6HpMXQa1ZhFQ7SU+GjvORCmShbCMltrtIDfkYhVHrOcPtj+KhmDBdPdZD1g==", + "engines": { + "node": ">=10" + } + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" + }, + "node_modules/saxes": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/saxes/-/saxes-6.0.0.tgz", + "integrity": "sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA==", + "dependencies": { + "xmlchars": "^2.2.0" + }, + "engines": { + "node": ">=v12.22.7" + } + }, + "node_modules/semver": { + "version": "7.6.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.2.tgz", + "integrity": "sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/sift": { + "version": "16.0.1", + "resolved": "https://registry.npmjs.org/sift/-/sift-16.0.1.tgz", + "integrity": "sha512-Wv6BjQ5zbhW7VFefWusVP33T/EM0vYikCaQ2qR8yULbsilAT8/wQaXvuQ3ptGLpoKx+lihJE3y2UTgKDyyNHZQ==" + }, + "node_modules/simple-swizzle": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz", + "integrity": "sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==", + "dependencies": { + "is-arrayish": "^0.3.1" + } + }, + "node_modules/simple-update-notifier": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/simple-update-notifier/-/simple-update-notifier-2.0.0.tgz", + "integrity": "sha512-a2B9Y0KlNXl9u/vsW6sTIu9vGEpfKu2wRV6l1H3XEas/0gUIzGzBoP/IouTcUQbm9JWZLH3COxyn03TYlFax6w==", + "dev": true, + "dependencies": { + "semver": "^7.5.3" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/smart-buffer": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz", + "integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==", + "engines": { + "node": ">= 6.0.0", + "npm": ">= 3.0.0" + } + }, + "node_modules/socks": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/socks/-/socks-2.7.1.tgz", + "integrity": "sha512-7maUZy1N7uo6+WVEX6psASxtNlKaNVMlGQKkG/63nEDdLOWNbiUMoLK7X4uYoLhQstau72mLgfEWcXcwsaHbYQ==", + "dependencies": { + "ip": "^2.0.0", + "smart-buffer": "^4.2.0" + }, + "engines": { + "node": ">= 10.13.0", + "npm": ">= 3.0.0" + } + }, + "node_modules/source-map-js": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", + "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/sparse-bitfield": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/sparse-bitfield/-/sparse-bitfield-3.0.3.tgz", + "integrity": "sha512-kvzhi7vqKTfkh0PZU+2D2PIllw2ymqJKujUcyPMd9Y75Nv4nPbGJZXNhxsgdQab2BmlDct1YnfQCguEvHr7VsQ==", + "dependencies": { + "memory-pager": "^1.0.2" + } + }, + "node_modules/stack-trace": { + "version": "0.0.10", + "resolved": "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.10.tgz", + "integrity": "sha512-KGzahc7puUKkzyMt+IqAep+TVNbKP+k2Lmwhub39m1AsTSkaDutx56aDCo+HLDzf/D26BIHTJWNiTG1KAJiQCg==", + "engines": { + "node": "*" + } + }, + "node_modules/stream-browserify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/stream-browserify/-/stream-browserify-3.0.0.tgz", + "integrity": "sha512-H73RAHsVBapbim0tU2JwwOiXUj+fikfiaoYAKHF3VJfA0pe2BCzkhAHBlLG6REzE+2WNZcxOXjK7lkso+9euLA==", + "dependencies": { + "inherits": "~2.0.4", + "readable-stream": "^3.5.0" + } + }, + "node_modules/string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, + "node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/strnum": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/strnum/-/strnum-1.0.5.tgz", + "integrity": "sha512-J8bbNyKKXl5qYcR36TIO8W3mVGVHrmmxsd5PAItGkmyzwJvybiw2IVq5nqd0i4LSNSkB/sx9VHllbfFdr9k1JA==" + }, + "node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/symbol-tree": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz", + "integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==" + }, + "node_modules/synckit": { + "version": "0.8.8", + "resolved": "https://registry.npmjs.org/synckit/-/synckit-0.8.8.tgz", + "integrity": "sha512-HwOKAP7Wc5aRGYdKH+dw0PRRpbO841v2DENBtjnR5HFWoiNByAl7vrx3p0G/rCyYXQsrxqtX48TImFtPcIHSpQ==", + "dev": true, + "dependencies": { + "@pkgr/core": "^0.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": "^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/unts" + } + }, + "node_modules/text-hex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/text-hex/-/text-hex-1.0.0.tgz", + "integrity": "sha512-uuVGNWzgJ4yhRaNSiubPY7OjISw4sw4E5Uv0wbjp+OzcbmVU/rsT8ujgcXJhn9ypzsgr5vlzpPqP+MBBKcGvbg==" + }, + "node_modules/text-table": { + "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 + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/touch": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/touch/-/touch-3.1.0.tgz", + "integrity": "sha512-WBx8Uy5TLtOSRtIq+M03/sKDrXCLHxwDcquSP2c43Le03/9serjQBIztjRz6FkJez9D/hleyAXTBGLwwZUw9lA==", + "dev": true, + "dependencies": { + "nopt": "~1.0.10" + }, + "bin": { + "nodetouch": "bin/nodetouch.js" + } + }, + "node_modules/tough-cookie": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.1.3.tgz", + "integrity": "sha512-aX/y5pVRkfRnfmuX+OdbSdXvPe6ieKX/G2s7e98f4poJHnqH3281gDPm/metm6E/WRamfx7WC4HUqkWHfQHprw==", + "dependencies": { + "psl": "^1.1.33", + "punycode": "^2.1.1", + "universalify": "^0.2.0", + "url-parse": "^1.5.3" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/tr46": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-3.0.0.tgz", + "integrity": "sha512-l7FvfAHlcmulp8kr+flpQZmVwtu7nfRV7NZujtN0OqES8EL4O4e0qqzL0DC5gAvx/ZC/9lk6rhcUwYvkBnBnYA==", + "dependencies": { + "punycode": "^2.1.1" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/triple-beam": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/triple-beam/-/triple-beam-1.4.1.tgz", + "integrity": "sha512-aZbgViZrg1QNcG+LULa7nhZpJTZSLm/mXnHXnbAbjmN5aSa0y7V+wvv6+4WaBtpISJzThKy+PIPxc1Nq1EJ9mg==", + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/ts-api-utils": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.3.0.tgz", + "integrity": "sha512-UQMIo7pb8WRomKR1/+MFVLTroIvDVtMX3K6OUir8ynLyzB8Jeriont2bTAtmNPa1ekAgN7YPDyf6V+ygrdU+eQ==", + "dev": true, + "engines": { + "node": ">=16" + }, + "peerDependencies": { + "typescript": ">=4.2.0" + } + }, + "node_modules/ts-mixer": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/ts-mixer/-/ts-mixer-6.0.3.tgz", + "integrity": "sha512-k43M7uCG1AkTyxgnmI5MPwKoUvS/bRvLvUb7+Pgpdlmok8AoqmUaZxUUw8zKM5B1lqZrt41GjYgnvAi0fppqgQ==" + }, + "node_modules/ts-node": { + "version": "10.9.2", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.2.tgz", + "integrity": "sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==", + "dev": true, + "dependencies": { + "@cspotcode/source-map-support": "^0.8.0", + "@tsconfig/node10": "^1.0.7", + "@tsconfig/node12": "^1.0.7", + "@tsconfig/node14": "^1.0.0", + "@tsconfig/node16": "^1.0.2", + "acorn": "^8.4.1", + "acorn-walk": "^8.1.1", + "arg": "^4.1.0", + "create-require": "^1.1.0", + "diff": "^4.0.1", + "make-error": "^1.1.1", + "v8-compile-cache-lib": "^3.0.1", + "yn": "3.1.1" + }, + "bin": { + "ts-node": "dist/bin.js", + "ts-node-cwd": "dist/bin-cwd.js", + "ts-node-esm": "dist/bin-esm.js", + "ts-node-script": "dist/bin-script.js", + "ts-node-transpile-only": "dist/bin-transpile.js", + "ts-script": "dist/bin-script-deprecated.js" + }, + "peerDependencies": { + "@swc/core": ">=1.2.50", + "@swc/wasm": ">=1.2.50", + "@types/node": "*", + "typescript": ">=2.7" + }, + "peerDependenciesMeta": { + "@swc/core": { + "optional": true + }, + "@swc/wasm": { + "optional": true + } + } + }, + "node_modules/tslib": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", + "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==" + }, + "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, + "dependencies": { + "prelude-ls": "^1.2.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/typescript": { + "version": "5.4.5", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.4.5.tgz", + "integrity": "sha512-vcI4UpRgg81oIRUFwR0WSIHKt11nJ7SAVlYNIu+QpqeyXP+gpQJy/Z4+F0aGxSE4MqwjyXvW/TzgkLAx2AGHwQ==", + "dev": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/typescript-eslint": { + "version": "8.0.0-alpha.30", + "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.0.0-alpha.30.tgz", + "integrity": "sha512-/vGhBMsK1TpadQh1eQ02c5pyiPGmKR9cVzX5C9plZ+LC0HPLpWoJbbTVfQN7BkIK7tUxDt2BFr3pFL5hDDrx7g==", + "dev": true, + "dependencies": { + "@typescript-eslint/eslint-plugin": "8.0.0-alpha.30", + "@typescript-eslint/parser": "8.0.0-alpha.30", + "@typescript-eslint/utils": "8.0.0-alpha.30" + }, + "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/typescript-eslint/node_modules/@typescript-eslint/eslint-plugin": { + "version": "8.0.0-alpha.30", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.0.0-alpha.30.tgz", + "integrity": "sha512-2CBUupdkfbE3eATph4QeZejvT+M+1bVur+zXlVx09WN31phap51ps/qemeclnCbGEz6kTgBDmScrr9XmmF8/Pg==", + "dev": true, + "dependencies": { + "@eslint-community/regexpp": "^4.10.0", + "@typescript-eslint/scope-manager": "8.0.0-alpha.30", + "@typescript-eslint/type-utils": "8.0.0-alpha.30", + "@typescript-eslint/utils": "8.0.0-alpha.30", + "@typescript-eslint/visitor-keys": "8.0.0-alpha.30", + "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.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "@typescript-eslint/parser": "^8.0.0 || ^8.0.0-alpha.0", + "eslint": "^8.57.0 || ^9.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/typescript-eslint/node_modules/@typescript-eslint/parser": { + "version": "8.0.0-alpha.30", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.0.0-alpha.30.tgz", + "integrity": "sha512-tAYgFmgXU1MlCK3nbblUvJlDSibBvxtAQXGrF3IG0KmnRza9FXILZifHWL0rrwacDn40K53K607Fk2QkMjiGgw==", + "dev": true, + "dependencies": { + "@typescript-eslint/scope-manager": "8.0.0-alpha.30", + "@typescript-eslint/types": "8.0.0-alpha.30", + "@typescript-eslint/typescript-estree": "8.0.0-alpha.30", + "@typescript-eslint/visitor-keys": "8.0.0-alpha.30", + "debug": "^4.3.4" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/typescript-eslint/node_modules/@typescript-eslint/scope-manager": { + "version": "8.0.0-alpha.30", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.0.0-alpha.30.tgz", + "integrity": "sha512-FGW/iPWGyPFamAVZ60oCAthMqQrqafUGebF8UKuq/ha+e9SVG6YhJoRzurlQXOVf8dHfOhJ0ADMXyFnMc53clg==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "8.0.0-alpha.30", + "@typescript-eslint/visitor-keys": "8.0.0-alpha.30" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/typescript-eslint/node_modules/@typescript-eslint/types": { + "version": "8.0.0-alpha.30", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.0.0-alpha.30.tgz", + "integrity": "sha512-4WzLlw27SO9pK9UFj/Hu7WGo8WveT0SEiIpFVsV2WwtQmLps6kouwtVCB8GJPZKJyurhZhcqCoQVQFmpv441Vg==", + "dev": true, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/typescript-eslint/node_modules/@typescript-eslint/typescript-estree": { + "version": "8.0.0-alpha.30", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.0.0-alpha.30.tgz", + "integrity": "sha512-WSXbc9ZcXI+7yC+6q95u77i8FXz6HOLsw3ST+vMUlFy1lFbXyFL/3e6HDKQCm2Clt0krnoCPiTGvIn+GkYPn4Q==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "8.0.0-alpha.30", + "@typescript-eslint/visitor-keys": "8.0.0-alpha.30", + "debug": "^4.3.4", + "globby": "^11.1.0", + "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.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/typescript-eslint/node_modules/@typescript-eslint/visitor-keys": { + "version": "8.0.0-alpha.30", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.0.0-alpha.30.tgz", + "integrity": "sha512-XZuNurZxBqmr6ZIRIwWFq7j5RZd6ZlkId/HZEWyfciK+CWoyOxSF9Pv2VXH9Rlu2ZG2PfbhLz2Veszl4Pfn7yA==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "8.0.0-alpha.30", + "eslint-visitor-keys": "^3.4.3" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/typescript-eslint/node_modules/minimatch": { + "version": "9.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.4.tgz", + "integrity": "sha512-KqWh+VchfxcMNRAJjj2tnsSJdNbHsVgnkBhTNrW7AjVo6OvLtxw8zfT9oLw1JSohlFzJ8jCoTgaoXvJ+kHt6fw==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/undefsafe": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/undefsafe/-/undefsafe-2.0.5.tgz", + "integrity": "sha512-WxONCrssBM8TSPRqN5EmsjVrsv4A8X12J4ArBiiayv3DyyG3ZlIg6yysuuSYdZsVz3TKcTg2fd//Ujd4CHV1iA==", + "dev": true + }, + "node_modules/undici": { + "version": "5.27.2", + "resolved": "https://registry.npmjs.org/undici/-/undici-5.27.2.tgz", + "integrity": "sha512-iS857PdOEy/y3wlM3yRp+6SNQQ6xU0mmZcwRSriqk+et/cwWAtwmIGf6WkoDN2EK/AMdCO/dfXzIwi+rFMrjjQ==", + "dependencies": { + "@fastify/busboy": "^2.0.0" + }, + "engines": { + "node": ">=14.0" + } + }, + "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==" + }, + "node_modules/universal-user-agent": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/universal-user-agent/-/universal-user-agent-6.0.1.tgz", + "integrity": "sha512-yCzhz6FN2wU1NiiQRogkTQszlQSlpWaw8SvVegAc+bDxbzHgh1vX8uIe8OYyMH6DwH+sdTJsgMl36+mSMdRJIQ==" + }, + "node_modules/universalify": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.2.0.tgz", + "integrity": "sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg==", + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/url-parse": { + "version": "1.5.10", + "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.10.tgz", + "integrity": "sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==", + "dependencies": { + "querystringify": "^2.1.1", + "requires-port": "^1.0.0" + } + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" + }, + "node_modules/uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "bin": { + "uuid": "dist/bin/uuid" + } + }, + "node_modules/v8-compile-cache-lib": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", + "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==", + "dev": true + }, + "node_modules/w3c-xmlserializer": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-5.0.0.tgz", + "integrity": "sha512-o8qghlI8NZHU1lLPrpi2+Uq7abh4GGPpYANlalzWxyWteJOCsr/P+oPBA49TOLu5FTZO4d3F9MnWJfiMo4BkmA==", + "dependencies": { + "xml-name-validator": "^5.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/webidl-conversions": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz", + "integrity": "sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==", + "engines": { + "node": ">=12" + } + }, + "node_modules/whatwg-encoding": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-3.1.1.tgz", + "integrity": "sha512-6qN4hJdMwfYBtE3YBTTHhoeuUrDBPZmbQaxWAqSALV/MeEnR5z1xd8UKud2RAkFoPkmB+hli1TZSnyi84xz1vQ==", + "dependencies": { + "iconv-lite": "0.6.3" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/whatwg-mimetype": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-4.0.0.tgz", + "integrity": "sha512-QaKxh0eNIi2mE9p2vEdzfagOKHCcj1pJ56EEHGQOVxp8r9/iszLUUV7v89x9O1p/T+NlTM5W7jW6+cz4Fq1YVg==", + "engines": { + "node": ">=18" + } + }, + "node_modules/whatwg-url": { + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-11.0.0.tgz", + "integrity": "sha512-RKT8HExMpoYx4igMiVMY83lN6UeITKJlBQ+vR/8ZJ8OCdSiN3RwCq+9gH0+Xzj0+5IrM6i4j/6LuvzbZIQgEcQ==", + "dependencies": { + "tr46": "^3.0.0", + "webidl-conversions": "^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/winston": { + "version": "3.11.0", + "resolved": "https://registry.npmjs.org/winston/-/winston-3.11.0.tgz", + "integrity": "sha512-L3yR6/MzZAOl0DsysUXHVjOwv8mKZ71TrA/41EIduGpOOV5LQVodqN+QdQ6BS6PJ/RdIshZhq84P/fStEZkk7g==", + "dependencies": { + "@colors/colors": "^1.6.0", + "@dabh/diagnostics": "^2.0.2", + "async": "^3.2.3", + "is-stream": "^2.0.0", + "logform": "^2.4.0", + "one-time": "^1.0.0", + "readable-stream": "^3.4.0", + "safe-stable-stringify": "^2.3.1", + "stack-trace": "0.0.x", + "triple-beam": "^1.3.0", + "winston-transport": "^4.5.0" + }, + "engines": { + "node": ">= 12.0.0" + } + }, + "node_modules/winston-transport": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/winston-transport/-/winston-transport-4.6.0.tgz", + "integrity": "sha512-wbBA9PbPAHxKiygo7ub7BYRiKxms0tpfU2ljtWzb3SjRjv5yl6Ozuy/TkXf00HTAt+Uylo3gSkNwzc4ME0wiIg==", + "dependencies": { + "logform": "^2.3.2", + "readable-stream": "^3.6.0", + "triple-beam": "^1.3.0" + }, + "engines": { + "node": ">= 12.0.0" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==" + }, + "node_modules/ws": { + "version": "8.14.2", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.14.2.tgz", + "integrity": "sha512-wEBG1ftX4jcglPxgFCMJmZ2PLtSbJ2Peg6TmpJFTbe9GZYOQCDPdMYu/Tm0/bGZkw8paZnJY45J4K2PZrLYq8g==", + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/xml-name-validator": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-5.0.0.tgz", + "integrity": "sha512-EvGK8EJ3DhaHfbRlETOWAS5pO9MZITeauHKJyb8wyajUfQUenkIg2MvLDTZ4T/TgIcm3HU0TFBgWWboAZ30UHg==", + "engines": { + "node": ">=18" + } + }, + "node_modules/xmlchars": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz", + "integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==" + }, + "node_modules/yn": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", + "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } } - } - }, - "node_modules/xml-name-validator": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-5.0.0.tgz", - "integrity": "sha512-EvGK8EJ3DhaHfbRlETOWAS5pO9MZITeauHKJyb8wyajUfQUenkIg2MvLDTZ4T/TgIcm3HU0TFBgWWboAZ30UHg==", - "engines": { - "node": ">=18" - } - }, - "node_modules/xmlchars": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz", - "integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==" - }, - "node_modules/yn": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", - "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/yocto-queue": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", - "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } } - } } diff --git a/package.json b/package.json index 2003679e..ef2d46ba 100644 --- a/package.json +++ b/package.json @@ -1,55 +1,55 @@ { - "name": "fbw-discord-bot", - "version": "1.0.0", - "description": "Moderation, utility and support bot for the FlyByWire Simulations Discord server", - "main": "./build/index.js", - "exports": "./build/index.js", - "scripts": { - "start": "node .", - "dev": "nodemon --config nodemon.json src/index.ts", - "build": "tsc", - "build:digitalocean": "npm ci --include=dev && npm run build", - "lint": "eslint", - "lint-fix": "eslint --fix", - "prettier": "prettier \"**/*.ts\" \"**/*.js\" \"**/*.json\" \"**/*.yaml\" \"**/*.yml\" \"**/*.md\"", - "prettier:check": "npm run prettier -- --check", - "prettier:write": "npm run prettier -- --write", - "test": "tsc --noEmit && eslint & npm run prettier:check" - }, - "author": "FlyByWire Simulations", - "license": "AGPL-3.0", - "dependencies": { - "@aws-sdk/client-s3": "^3.499.0", - "@aws-sdk/lib-storage": "^3.499.0", - "@hokify/agenda": "^6.0.0", - "@octokit/request": "^8.1.1", - "bad-words": "^3.0.4", - "config": "^3.3.9", - "discord.js": "^14.11.0", - "jsdom": "^23.2.0", - "moment": "^2.29.4", - "mongoose": "^8.0.3", - "node-fetch": "^2.6.10", - "winston": "^3.3.4" - }, - "devDependencies": { - "@eslint/js": "^9.3.0", - "@types/bad-words": "^3.0.3", - "@types/config": "^3.3.1", - "@types/jsdom": "^21.1.6", - "@types/node": "^18.0.0", - "@types/node-fetch": "^2.6.10", - "dotenv": "^16.0.0", - "eslint": "^9.4.0", - "eslint-config-prettier": "^9.1.0", - "eslint-plugin-prettier": "^5.1.3", - "nodemon": "^3.0.2", - "prettier": "^3.3.2", - "ts-node": "^10.4.0", - "typescript": "^5.4.5", - "typescript-eslint": "^8.0.0-alpha.30" - }, - "engines": { - "node": "18.x" - } + "name": "fbw-discord-bot", + "version": "1.0.0", + "description": "Moderation, utility and support bot for the FlyByWire Simulations Discord server", + "main": "./build/index.js", + "exports": "./build/index.js", + "scripts": { + "start": "node .", + "dev": "nodemon --config nodemon.json src/index.ts", + "build": "tsc", + "build:digitalocean": "npm ci --include=dev && npm run build", + "lint": "eslint", + "lint-fix": "eslint --fix", + "prettier": "prettier \"**/*.ts\" \"**/*.js\" \"**/*.json\" \"**/*.yaml\" \"**/*.yml\" \"**/*.md\"", + "prettier:check": "npm run prettier -- --check", + "prettier:write": "npm run prettier -- --write", + "test": "tsc --noEmit && eslint & npm run prettier:check" + }, + "author": "FlyByWire Simulations", + "license": "AGPL-3.0", + "dependencies": { + "@aws-sdk/client-s3": "^3.499.0", + "@aws-sdk/lib-storage": "^3.499.0", + "@hokify/agenda": "^6.0.0", + "@octokit/request": "^8.1.1", + "bad-words": "^3.0.4", + "config": "^3.3.9", + "discord.js": "^14.11.0", + "jsdom": "^23.2.0", + "moment": "^2.29.4", + "mongoose": "^8.0.3", + "node-fetch": "^2.6.10", + "winston": "^3.3.4" + }, + "devDependencies": { + "@eslint/js": "^9.3.0", + "@types/bad-words": "^3.0.3", + "@types/config": "^3.3.1", + "@types/jsdom": "^21.1.6", + "@types/node": "^18.0.0", + "@types/node-fetch": "^2.6.10", + "dotenv": "^16.0.0", + "eslint": "^9.4.0", + "eslint-config-prettier": "^9.1.0", + "eslint-plugin-prettier": "^5.1.3", + "nodemon": "^3.0.2", + "prettier": "^3.3.2", + "ts-node": "^10.4.0", + "typescript": "^5.4.5", + "typescript-eslint": "^8.0.0-alpha.30" + }, + "engines": { + "node": "18.x" + } } diff --git a/src/client.ts b/src/client.ts index b1177f80..15ae8985 100644 --- a/src/client.ts +++ b/src/client.ts @@ -3,46 +3,46 @@ import { constantsConfig, closeMongooseConnection, registerEvents, Logger } from import Events from './events/index'; if (!process.env.BOT_SECRET) { - Logger.error('Missing BOT_SECRET environment variable. Exiting...'); - process.exit(1); + Logger.error('Missing BOT_SECRET environment variable. Exiting...'); + process.exit(1); } if (!constantsConfig.guildId) { - Logger.error('Missing guildId configuration constant. Exiting...'); - process.exit(1); + Logger.error('Missing guildId configuration constant. Exiting...'); + process.exit(1); } export const client = new Client({ - intents: [ - GatewayIntentBits.Guilds, - GatewayIntentBits.GuildMembers, - GatewayIntentBits.GuildMessages, - GatewayIntentBits.MessageContent, - GatewayIntentBits.GuildMessageReactions, - GatewayIntentBits.GuildBans, - GatewayIntentBits.GuildPresences, - ], + intents: [ + GatewayIntentBits.Guilds, + GatewayIntentBits.GuildMembers, + GatewayIntentBits.GuildMessages, + GatewayIntentBits.MessageContent, + GatewayIntentBits.GuildMessageReactions, + GatewayIntentBits.GuildBans, + GatewayIntentBits.GuildPresences, + ], }); registerEvents(client, Events); client.login(process.env.BOT_SECRET).catch((e) => { - Logger.error(e); - process.exit(1); + Logger.error(e); + process.exit(1); }); const handleTermination = async () => { - Logger.info('Terminating bot...'); - try { - client.removeAllListeners(); - await closeMongooseConnection(); - await client.destroy(); - Logger.info('Cleanup complete. Exiting...'); - process.exit(0); - } catch (error) { - Logger.error('Error during termination:', error); - process.exit(1); - } + Logger.info('Terminating bot...'); + try { + client.removeAllListeners(); + await closeMongooseConnection(); + await client.destroy(); + Logger.info('Cleanup complete. Exiting...'); + process.exit(0); + } catch (error) { + Logger.error('Error during termination:', error); + process.exit(1); + } }; process.on('SIGINT', handleTermination); diff --git a/src/commands/context/message/reportMessage.ts b/src/commands/context/message/reportMessage.ts index d0edead0..e653cfb0 100644 --- a/src/commands/context/message/reportMessage.ts +++ b/src/commands/context/message/reportMessage.ts @@ -1,322 +1,320 @@ import { - ActionRowBuilder, - ApplicationCommandType, - ContextMenuCommandInteraction, - ModalBuilder, - TextChannel, - TextInputBuilder, - TextInputStyle, - Colors, + ActionRowBuilder, + ApplicationCommandType, + ContextMenuCommandInteraction, + ModalBuilder, + TextChannel, + TextInputBuilder, + TextInputStyle, + Colors, } from 'discord.js'; import moment from 'moment/moment'; import { constantsConfig, contextMenuCommand, contextMenuCommandStructure, Logger, makeEmbed } from '../../../lib'; const data = contextMenuCommandStructure({ - name: 'Report Message', - type: ApplicationCommandType.Message, + name: 'Report Message', + type: ApplicationCommandType.Message, }); const reportedMessageEmbed = ( - targetMessage: any, - interaction: ContextMenuCommandInteraction<'cached'>, - messageContent: string, - commentContent: string, - formattedDate: string, + targetMessage: any, + interaction: ContextMenuCommandInteraction<'cached'>, + messageContent: string, + commentContent: string, + formattedDate: string, ) => - makeEmbed({ - author: { - name: `[REPORTED MESSAGE] ${targetMessage.author.tag}`, - iconURL: targetMessage.author.displayAvatarURL(), - }, - fields: [ - { - name: 'Reported by', - value: interaction.user.toString(), - inline: true, - }, - { - name: 'Message Author', - value: targetMessage.author.toString(), - inline: true, - }, - { - name: 'Message Content', - value: messageContent, - inline: false, - }, - { - name: 'Link to Message', - value: targetMessage.url, - inline: false, - }, - { - name: 'Additional Comments', - value: commentContent, - inline: false, - }, - { - name: 'Reported at', - value: formattedDate, - inline: false, - }, - ], - color: Colors.Red, - footer: { text: `Reported Users ID: ${targetMessage.author.id}` }, - }); + makeEmbed({ + author: { + name: `[REPORTED MESSAGE] ${targetMessage.author.tag}`, + iconURL: targetMessage.author.displayAvatarURL(), + }, + fields: [ + { + name: 'Reported by', + value: interaction.user.toString(), + inline: true, + }, + { + name: 'Message Author', + value: targetMessage.author.toString(), + inline: true, + }, + { + name: 'Message Content', + value: messageContent, + inline: false, + }, + { + name: 'Link to Message', + value: targetMessage.url, + inline: false, + }, + { + name: 'Additional Comments', + value: commentContent, + inline: false, + }, + { + name: 'Reported at', + value: formattedDate, + inline: false, + }, + ], + color: Colors.Red, + footer: { text: `Reported Users ID: ${targetMessage.author.id}` }, + }); export default contextMenuCommand(data, async ({ interaction }) => { - const currentDate = new Date(); - const formattedDate: string = moment(currentDate).utcOffset(0).format(); - const scamReportLogs = interaction.guild.channels.resolve(constantsConfig.channels.SCAM_REPORT_LOGS) as TextChannel; - const modRoleId = constantsConfig.roles.MODERATION_TEAM; - - if (!scamReportLogs) { - await interaction.reply({ - content: 'Unable to find the reporting channel. Please contact a Moderator.', - ephemeral: true, - }); - return; - } + const currentDate = new Date(); + const formattedDate: string = moment(currentDate).utcOffset(0).format(); + const scamReportLogs = interaction.guild.channels.resolve(constantsConfig.channels.SCAM_REPORT_LOGS) as TextChannel; + const modRoleId = constantsConfig.roles.MODERATION_TEAM; + + if (!scamReportLogs) { + await interaction.reply({ + content: 'Unable to find the reporting channel. Please contact a Moderator.', + ephemeral: true, + }); + return; + } - const targetMessageId = interaction.targetId; + const targetMessageId = interaction.targetId; - if (!interaction.channel || !targetMessageId) { - await interaction.reply({ - content: 'Unable to find the target message.', - ephemeral: true, - }); - return; - } + if (!interaction.channel || !targetMessageId) { + await interaction.reply({ + content: 'Unable to find the target message.', + ephemeral: true, + }); + return; + } - const targetMessage = await interaction.channel.messages.fetch(targetMessageId); + const targetMessage = await interaction.channel.messages.fetch(targetMessageId); - if (!targetMessage) { - await interaction.reply({ - content: 'Unable to find the target message.', - ephemeral: true, - }); - return; - } + if (!targetMessage) { + await interaction.reply({ + content: 'Unable to find the target message.', + ephemeral: true, + }); + return; + } - let messageContent; - if (targetMessage.embeds.length === 0) { - if (targetMessage.content.length <= 1024) { - messageContent = targetMessage.content; - } else { - messageContent = 'Message is longer than 1024 characters. Please check the link below.'; - } + let messageContent; + if (targetMessage.embeds.length === 0) { + if (targetMessage.content.length <= 1024) { + messageContent = targetMessage.content; } else { - messageContent = 'Message is an embed. Please check the link below.'; + messageContent = 'Message is longer than 1024 characters. Please check the link below.'; } + } else { + messageContent = 'Message is an embed. Please check the link below.'; + } - //Create and send the modal + //Create and send the modal - const modal = new ModalBuilder({ - customId: 'reportMessageModal', - title: 'Report a Message', - }); + const modal = new ModalBuilder({ + customId: 'reportMessageModal', + title: 'Report a Message', + }); - const reportMessageComments = new TextInputBuilder() - .setCustomId('reportMessageComments') - .setLabel('Comments') - .setPlaceholder('Please provide any additional comments about your report here. You may leave this blank.') - .setStyle(TextInputStyle.Paragraph) - .setMaxLength(500) - .setRequired(false); + const reportMessageComments = new TextInputBuilder() + .setCustomId('reportMessageComments') + .setLabel('Comments') + .setPlaceholder('Please provide any additional comments about your report here. You may leave this blank.') + .setStyle(TextInputStyle.Paragraph) + .setMaxLength(500) + .setRequired(false); - const actionRow = new ActionRowBuilder().addComponents(reportMessageComments); + const actionRow = new ActionRowBuilder().addComponents(reportMessageComments); - modal.addComponents(actionRow); + modal.addComponents(actionRow); - await interaction.showModal(modal); + await interaction.showModal(modal); - //Modal sent + //Modal sent - const filter = (interaction: { customId: string; user: { id: any } }) => - interaction.customId === 'reportMessageModal' && interaction.user.id; + const filter = (interaction: { customId: string; user: { id: any } }) => + interaction.customId === 'reportMessageModal' && interaction.user.id; - let commentContent = 'No additional comments provided.'; + let commentContent = 'No additional comments provided.'; - try { - //Await a modal response - const modalSubmitInteraction = await interaction.awaitModalSubmit({ - filter, - time: 120000, - }); + try { + //Await a modal response + const modalSubmitInteraction = await interaction.awaitModalSubmit({ + filter, + time: 120000, + }); - //Respond to the user once they have submitted the modal - await modalSubmitInteraction.reply({ - content: `Thank you for reporting the message from ${targetMessage.author.toString()}, the <@&${modRoleId}> will review your report as soon as possible.`, - ephemeral: true, - }); + //Respond to the user once they have submitted the modal + await modalSubmitInteraction.reply({ + content: `Thank you for reporting the message from ${targetMessage.author.toString()}, the <@&${modRoleId}> will review your report as soon as possible.`, + ephemeral: true, + }); - commentContent = modalSubmitInteraction.fields.getTextInputValue('reportMessageComments'); - commentContent = commentContent.trim() || 'No additional comments provided.'; + commentContent = modalSubmitInteraction.fields.getTextInputValue('reportMessageComments'); + commentContent = commentContent.trim() || 'No additional comments provided.'; + } catch (error) { + //Handle the error if the user does not respond in time + Logger.error(error); + await interaction.followUp({ + content: 'You did not provide any comments in time. Your report has been cancelled.', + ephemeral: true, + }); + return; + } + + //Send a follow-up message to the user if they are part of the staff role group + + if ( + constantsConfig.roleGroups.SUPPORT && + constantsConfig.roleGroups.SUPPORT.some((role) => interaction.member.roles.cache.has(role)) + ) { + await interaction.followUp({ + content: `Is your report urgent and requires immediate attention from the <@&${modRoleId}>? If so please click yes and I will ping the <@&${modRoleId}>. If not, click no.`, + components: [ + { + type: 1, + components: [ + { + type: 2, + style: 3, + label: 'Yes', + customId: 'pingModerationTeamYes', + }, + { + type: 2, + style: 4, + label: 'No', + customId: 'pingModerationTeamNo', + }, + ], + }, + ], + ephemeral: true, + }); + + try { + // Handle the button interactions + const modPingButtonInteraction = await interaction.channel.awaitMessageComponent({ + filter: (i) => i.customId === 'pingModerationTeamYes' || i.customId === 'pingModerationTeamNo', + time: 60000, + }); + + let pingModerationTeam = false; + + if (modPingButtonInteraction.customId === 'pingModerationTeamYes') { + pingModerationTeam = true; + } + + // Respond based on the user's choice + let responseMessage; + + if (pingModerationTeam) { + // Ping the moderation team + await scamReportLogs.send({ content: `<@&${modRoleId}>` }); + responseMessage = `I will also ping the <@&${modRoleId}>.`; + } else { + // Do not ping the moderation team + responseMessage = `I will not ping the <@&${modRoleId}>.`; + } + + // Respond to the user + await modPingButtonInteraction.reply({ + content: responseMessage, + ephemeral: true, + }); } catch (error) { - //Handle the error if the user does not respond in time - Logger.error(error); - await interaction.followUp({ - content: 'You did not provide any comments in time. Your report has been cancelled.', - ephemeral: true, - }); - return; + Logger.error(error); + // Handle the error if the user does not respond in time + await interaction.followUp({ + content: `You did not choose an option in time. Your report has been submitted without pinging the <@&${modRoleId}>.`, + ephemeral: true, + }); } - //Send a follow-up message to the user if they are part of the staff role group - - if ( - constantsConfig.roleGroups.SUPPORT && - constantsConfig.roleGroups.SUPPORT.some((role) => interaction.member.roles.cache.has(role)) - ) { - await interaction.followUp({ - content: `Is your report urgent and requires immediate attention from the <@&${modRoleId}>? If so please click yes and I will ping the <@&${modRoleId}>. If not, click no.`, - components: [ - { - type: 1, - components: [ - { - type: 2, - style: 3, - label: 'Yes', - customId: 'pingModerationTeamYes', - }, - { - type: 2, - style: 4, - label: 'No', - customId: 'pingModerationTeamNo', - }, - ], - }, - ], - ephemeral: true, - }); + const modAlertsChannel = interaction.guild.channels.resolve(constantsConfig.channels.MOD_ALERTS) as TextChannel; + + if (!modAlertsChannel) { + await interaction.followUp({ + content: 'Unable to find the mod alerts channel. Please contact a Moderator.', + ephemeral: true, + }); + await scamReportLogs.send({ + embeds: [reportedMessageEmbed(targetMessage, interaction, messageContent, commentContent, formattedDate)], + }); + return; + } + + await interaction.followUp({ + content: `Would you like to share this report in ${modAlertsChannel}? If you do not respond in 15 seconds, I will assume you do not want to share this report.`, + components: [ + { + type: 1, + components: [ + { + type: 2, + style: 3, + label: 'Yes', + customId: 'shareReportYes', + }, + { + type: 2, + style: 4, + label: 'No', + customId: 'shareReportNo', + }, + ], + }, + ], + ephemeral: true, + }); - try { - // Handle the button interactions - const modPingButtonInteraction = await interaction.channel.awaitMessageComponent({ - filter: (i) => i.customId === 'pingModerationTeamYes' || i.customId === 'pingModerationTeamNo', - time: 60000, - }); - - let pingModerationTeam = false; - - if (modPingButtonInteraction.customId === 'pingModerationTeamYes') { - pingModerationTeam = true; - } - - // Respond based on the user's choice - let responseMessage; - - if (pingModerationTeam) { - // Ping the moderation team - await scamReportLogs.send({ content: `<@&${modRoleId}>` }); - responseMessage = `I will also ping the <@&${modRoleId}>.`; - } else { - // Do not ping the moderation team - responseMessage = `I will not ping the <@&${modRoleId}>.`; - } - - // Respond to the user - await modPingButtonInteraction.reply({ - content: responseMessage, - ephemeral: true, - }); - } catch (error) { - Logger.error(error); - // Handle the error if the user does not respond in time - await interaction.followUp({ - content: `You did not choose an option in time. Your report has been submitted without pinging the <@&${modRoleId}>.`, - ephemeral: true, - }); - } - - const modAlertsChannel = interaction.guild.channels.resolve(constantsConfig.channels.MOD_ALERTS) as TextChannel; - - if (!modAlertsChannel) { - await interaction.followUp({ - content: 'Unable to find the mod alerts channel. Please contact a Moderator.', - ephemeral: true, - }); - await scamReportLogs.send({ - embeds: [ - reportedMessageEmbed(targetMessage, interaction, messageContent, commentContent, formattedDate), - ], - }); - return; - } - - await interaction.followUp({ - content: `Would you like to share this report in ${modAlertsChannel}? If you do not respond in 15 seconds, I will assume you do not want to share this report.`, - components: [ - { - type: 1, - components: [ - { - type: 2, - style: 3, - label: 'Yes', - customId: 'shareReportYes', - }, - { - type: 2, - style: 4, - label: 'No', - customId: 'shareReportNo', - }, - ], - }, - ], - ephemeral: true, + try { + const shareReportButtonInteraction = await interaction.channel.awaitMessageComponent({ + filter: (i) => i.customId === 'shareReportYes' || i.customId === 'shareReportNo', + time: 15000, + }); + + const sharedReportEmbed = makeEmbed({ + title: '[REPORTED MESSAGE]', + description: `A message has been reported in ${interaction.channel}.`, + fields: [ + { + name: 'Link to Message', + value: targetMessage.url, + }, + { + name: 'Reported At', + value: formattedDate, + }, + ], + }); + + if (shareReportButtonInteraction.customId === 'shareReportYes') { + await modAlertsChannel.send({ embeds: [sharedReportEmbed] }); + await shareReportButtonInteraction.reply({ + content: `Your report has been submitted and shared in ${modAlertsChannel}.`, + ephemeral: true, }); + await scamReportLogs.send({ + content: `Reported message from ${interaction.user.toString()} has been shared in ${modAlertsChannel}.`, + }); + } - try { - const shareReportButtonInteraction = await interaction.channel.awaitMessageComponent({ - filter: (i) => i.customId === 'shareReportYes' || i.customId === 'shareReportNo', - time: 15000, - }); - - const sharedReportEmbed = makeEmbed({ - title: '[REPORTED MESSAGE]', - description: `A message has been reported in ${interaction.channel}.`, - fields: [ - { - name: 'Link to Message', - value: targetMessage.url, - }, - { - name: 'Reported At', - value: formattedDate, - }, - ], - }); - - if (shareReportButtonInteraction.customId === 'shareReportYes') { - await modAlertsChannel.send({ embeds: [sharedReportEmbed] }); - await shareReportButtonInteraction.reply({ - content: `Your report has been submitted and shared in ${modAlertsChannel}.`, - ephemeral: true, - }); - await scamReportLogs.send({ - content: `Reported message from ${interaction.user.toString()} has been shared in ${modAlertsChannel}.`, - }); - } - - if (shareReportButtonInteraction.customId === 'shareReportNo') { - await shareReportButtonInteraction.reply({ - content: `Your report has been submitted without sharing in ${modAlertsChannel}.`, - ephemeral: true, - }); - } - } catch (error) { - Logger.error(error); - await interaction.followUp({ - content: `Your report has been submitted without sharing in ${modAlertsChannel}.`, - ephemeral: true, - }); - } + if (shareReportButtonInteraction.customId === 'shareReportNo') { + await shareReportButtonInteraction.reply({ + content: `Your report has been submitted without sharing in ${modAlertsChannel}.`, + ephemeral: true, + }); + } + } catch (error) { + Logger.error(error); + await interaction.followUp({ + content: `Your report has been submitted without sharing in ${modAlertsChannel}.`, + ephemeral: true, + }); } - await scamReportLogs.send({ - embeds: [reportedMessageEmbed(targetMessage, interaction, messageContent, commentContent, formattedDate)], - }); + } + await scamReportLogs.send({ + embeds: [reportedMessageEmbed(targetMessage, interaction, messageContent, commentContent, formattedDate)], + }); }); diff --git a/src/commands/context/user/listInfractions.ts b/src/commands/context/user/listInfractions.ts index d487d488..743e9890 100644 --- a/src/commands/context/user/listInfractions.ts +++ b/src/commands/context/user/listInfractions.ts @@ -3,14 +3,14 @@ import { constantsConfig, contextMenuCommand, contextMenuCommandStructure } from import { handleListInfraction } from '../../moderation/infractions/functions/listInfractions'; const data = contextMenuCommandStructure({ - name: 'List Infractions', - type: ApplicationCommandType.User, - default_member_permissions: constantsConfig.commandPermission.MANAGE_SERVER, // Overrides need to be added for admin and moderator roles - dm_permission: false, + name: 'List Infractions', + type: ApplicationCommandType.User, + default_member_permissions: constantsConfig.commandPermission.MANAGE_SERVER, // Overrides need to be added for admin and moderator roles + dm_permission: false, }); export default contextMenuCommand(data, async ({ interaction }) => { - const userID = interaction.targetId; + const userID = interaction.targetId; - await handleListInfraction(interaction, userID, true); + await handleListInfraction(interaction, userID, true); }); diff --git a/src/commands/context/user/userInfo.ts b/src/commands/context/user/userInfo.ts index d4e6c654..1f87554d 100644 --- a/src/commands/context/user/userInfo.ts +++ b/src/commands/context/user/userInfo.ts @@ -3,78 +3,78 @@ import moment from 'moment/moment'; import { constantsConfig, contextMenuCommand, contextMenuCommandStructure, makeEmbed } from '../../../lib'; const data = contextMenuCommandStructure({ - name: 'User Info', - type: ApplicationCommandType.User, - default_member_permissions: constantsConfig.commandPermission.MANAGE_SERVER, - dm_permission: false, + name: 'User Info', + type: ApplicationCommandType.User, + default_member_permissions: constantsConfig.commandPermission.MANAGE_SERVER, + dm_permission: false, }); const beautifiedStatus: { [key: string]: string } = { - ONLINE: 'Online', - IDLE: 'Idle', - DND: 'Do Not Disturb', - OFFLINE: 'Offline', + ONLINE: 'Online', + IDLE: 'Idle', + DND: 'Do Not Disturb', + OFFLINE: 'Offline', }; export default contextMenuCommand(data, async ({ interaction }) => { - const targetMember = interaction.guild?.members.cache.get(interaction.targetId)!; + const targetMember = interaction.guild?.members.cache.get(interaction.targetId)!; - const filteredRoles = targetMember.roles.cache.filter((role) => role.id !== interaction.guild.id); - const listedRoles = filteredRoles.sort((a, b) => b.position - a.position).map((role) => role.toString()); + const filteredRoles = targetMember.roles.cache.filter((role) => role.id !== interaction.guild.id); + const listedRoles = filteredRoles.sort((a, b) => b.position - a.position).map((role) => role.toString()); - const onlineStatus = beautifiedStatus[targetMember.presence?.status?.toUpperCase() ?? 'OFFLINE']; + const onlineStatus = beautifiedStatus[targetMember.presence?.status?.toUpperCase() ?? 'OFFLINE']; - let status; - if (targetMember.presence == null) { - status = 'Offline'; - } else { - status = onlineStatus; - } + let status; + if (targetMember.presence == null) { + status = 'Offline'; + } else { + status = onlineStatus; + } - const whoisEmbed = makeEmbed({ - author: { - name: targetMember.user.username, - iconURL: targetMember.user.avatarURL()!, - }, - description: `${targetMember}`, - thumbnail: { url: targetMember.user.avatarURL()! }, - fields: [ - { - name: 'Username', - value: targetMember.user.tag, - inline: true, - }, - { - name: 'Status', - value: status, - inline: true, - }, - { - name: 'Joined', - value: moment(targetMember.joinedTimestamp).format('llll'), - inline: true, - }, - { - name: 'Registered', - value: moment(targetMember.user.createdTimestamp).format('llll'), - inline: false, - }, - { - name: 'Roles', - value: `\u200B${listedRoles.join(', ')}`, - }, - { - name: 'Permissions', - value: targetMember.permissions - .toArray() - .join(', ') - .toLowerCase() - .replace(/_/g, ' ') - .replace(/(^\w)|(\s+\w)/g, (char) => char.toUpperCase()), - }, - ], - footer: { text: `User ID: ${targetMember.id}` }, - }); + const whoisEmbed = makeEmbed({ + author: { + name: targetMember.user.username, + iconURL: targetMember.user.avatarURL()!, + }, + description: `${targetMember}`, + thumbnail: { url: targetMember.user.avatarURL()! }, + fields: [ + { + name: 'Username', + value: targetMember.user.tag, + inline: true, + }, + { + name: 'Status', + value: status, + inline: true, + }, + { + name: 'Joined', + value: moment(targetMember.joinedTimestamp).format('llll'), + inline: true, + }, + { + name: 'Registered', + value: moment(targetMember.user.createdTimestamp).format('llll'), + inline: false, + }, + { + name: 'Roles', + value: `\u200B${listedRoles.join(', ')}`, + }, + { + name: 'Permissions', + value: targetMember.permissions + .toArray() + .join(', ') + .toLowerCase() + .replace(/_/g, ' ') + .replace(/(^\w)|(\s+\w)/g, (char) => char.toUpperCase()), + }, + ], + footer: { text: `User ID: ${targetMember.id}` }, + }); - return interaction.reply({ embeds: [whoisEmbed] }); + return interaction.reply({ embeds: [whoisEmbed] }); }); diff --git a/src/commands/index.ts b/src/commands/index.ts index e16ab038..6363057e 100644 --- a/src/commands/index.ts +++ b/src/commands/index.ts @@ -33,38 +33,38 @@ import clearMessages from './moderation/clearMessages'; import locate from './utils/locate/locate'; const commandArray: SlashCommand[] = [ - ping, - deployCommands, - avatar, - liveFlights, - memberCount, - metar, - github, - roleInfo, - simbriefData, - station, - taf, - wolframAlpha, - zulu, - cacheUpdate, - infractions, - slowmode, - whois, - faq, - rules, - welcome, - searchFaq, - roleAssignment, - birthday, - count, - vatsim, - help, - docSearch, - reportedIssues, - commandTable, - listRoleUsers, - clearMessages, - locate, + ping, + deployCommands, + avatar, + liveFlights, + memberCount, + metar, + github, + roleInfo, + simbriefData, + station, + taf, + wolframAlpha, + zulu, + cacheUpdate, + infractions, + slowmode, + whois, + faq, + rules, + welcome, + searchFaq, + roleAssignment, + birthday, + count, + vatsim, + help, + docSearch, + reportedIssues, + commandTable, + listRoleUsers, + clearMessages, + locate, ]; export default commandArray; diff --git a/src/commands/moderation/cacheUpdate.ts b/src/commands/moderation/cacheUpdate.ts index caab4f9b..bc587ca5 100644 --- a/src/commands/moderation/cacheUpdate.ts +++ b/src/commands/moderation/cacheUpdate.ts @@ -2,137 +2,137 @@ import { ApplicationCommandOptionType, ApplicationCommandType, Colors, EmbedFiel import { constantsConfig, slashCommand, slashCommandStructure, makeEmbed } from '../../lib'; const data = slashCommandStructure({ - name: 'cache-update', - description: 'Updates the cache of the bot for a specific cache type.', - type: ApplicationCommandType.ChatInput, - default_member_permissions: constantsConfig.commandPermission.MANAGE_SERVER, //Overrides need to be added for admin, moderator and bot developer roles - dm_permission: false, - options: [ - { - name: 'bans', - description: 'Updates the bans cache by fetching all bans.', - type: ApplicationCommandOptionType.Subcommand, - }, - { - name: 'channels', - description: 'Updates the channels cache by fetching all channels.', - type: ApplicationCommandOptionType.Subcommand, - }, - { - name: 'members', - description: 'Updates the members cache by fetching all members.', - type: ApplicationCommandOptionType.Subcommand, - }, - { - name: 'roles', - description: 'Updates the roles cache by fetching all roles.', - type: ApplicationCommandOptionType.Subcommand, - }, - ], -}); - -const cacheUpdateEmbed = (action: string, fields: any, color: number) => - makeEmbed({ - title: `Cache Update - ${action}`, - fields, - color, - }); - -const noChannelEmbed = (action: string, channelName: string) => - makeEmbed({ - title: `Sticky Message - ${action} - No ${channelName} channel`, - description: `The command was successful, but no message to ${channelName} was sent. Please check the channel still exists.`, - color: Colors.Yellow, - }); - -const cacheUpdateEmbedField = ( - moderator: string, - cacheType: string, - cacheSize: string, - duration: string, -): EmbedField[] => [ + name: 'cache-update', + description: 'Updates the cache of the bot for a specific cache type.', + type: ApplicationCommandType.ChatInput, + default_member_permissions: constantsConfig.commandPermission.MANAGE_SERVER, //Overrides need to be added for admin, moderator and bot developer roles + dm_permission: false, + options: [ { - name: 'Type', - value: cacheType, - inline: true, + name: 'bans', + description: 'Updates the bans cache by fetching all bans.', + type: ApplicationCommandOptionType.Subcommand, }, { - name: 'Count', - value: cacheSize, - inline: true, + name: 'channels', + description: 'Updates the channels cache by fetching all channels.', + type: ApplicationCommandOptionType.Subcommand, }, { - name: 'Moderator', - value: moderator, - inline: true, + name: 'members', + description: 'Updates the members cache by fetching all members.', + type: ApplicationCommandOptionType.Subcommand, }, { - name: 'Duration', - value: `${duration}s`, - inline: true, + name: 'roles', + description: 'Updates the roles cache by fetching all roles.', + type: ApplicationCommandOptionType.Subcommand, }, + ], +}); + +const cacheUpdateEmbed = (action: string, fields: any, color: number) => + makeEmbed({ + title: `Cache Update - ${action}`, + fields, + color, + }); + +const noChannelEmbed = (action: string, channelName: string) => + makeEmbed({ + title: `Sticky Message - ${action} - No ${channelName} channel`, + description: `The command was successful, but no message to ${channelName} was sent. Please check the channel still exists.`, + color: Colors.Yellow, + }); + +const cacheUpdateEmbedField = ( + moderator: string, + cacheType: string, + cacheSize: string, + duration: string, +): EmbedField[] => [ + { + name: 'Type', + value: cacheType, + inline: true, + }, + { + name: 'Count', + value: cacheSize, + inline: true, + }, + { + name: 'Moderator', + value: moderator, + inline: true, + }, + { + name: 'Duration', + value: `${duration}s`, + inline: true, + }, ]; export default slashCommand(data, async ({ interaction }) => { - await interaction.deferReply({ ephemeral: true }); + await interaction.deferReply({ ephemeral: true }); - const modLogsChannel = interaction.guild.channels.resolve(constantsConfig.channels.MOD_LOGS) as TextChannel; - let cacheSize: number | undefined; - const start = new Date().getTime(); - const { bans, channels, members, roles } = interaction.guild; + const modLogsChannel = interaction.guild.channels.resolve(constantsConfig.channels.MOD_LOGS) as TextChannel; + let cacheSize: number | undefined; + const start = new Date().getTime(); + const { bans, channels, members, roles } = interaction.guild; - if (interaction.options.getSubcommand() === 'bans') { - await bans.fetch(); - cacheSize = bans.cache.size; - } - if (interaction.options.getSubcommand() === 'channels') { - await channels.fetch(); - cacheSize = channels.cache.size; - } - if (interaction.options.getSubcommand() === 'members') { - await members.fetch(); - cacheSize = members.cache.size; - } - if (interaction.options.getSubcommand() === 'roles') { - await roles.fetch(); - cacheSize = roles.cache.size; - } + if (interaction.options.getSubcommand() === 'bans') { + await bans.fetch(); + cacheSize = bans.cache.size; + } + if (interaction.options.getSubcommand() === 'channels') { + await channels.fetch(); + cacheSize = channels.cache.size; + } + if (interaction.options.getSubcommand() === 'members') { + await members.fetch(); + cacheSize = members.cache.size; + } + if (interaction.options.getSubcommand() === 'roles') { + await roles.fetch(); + cacheSize = roles.cache.size; + } - const duration = ((new Date().getTime() - start) / 1000).toFixed(2); + const duration = ((new Date().getTime() - start) / 1000).toFixed(2); - if (cacheSize !== undefined) { - await interaction.editReply({ - embeds: [ - cacheUpdateEmbed( - interaction.options.getSubcommand(), - cacheUpdateEmbedField( - interaction.user.tag, - interaction.options.getSubcommand(), - cacheSize.toString(), - duration, - ), - Colors.Green, - ), - ], - }); + if (cacheSize !== undefined) { + await interaction.editReply({ + embeds: [ + cacheUpdateEmbed( + interaction.options.getSubcommand(), + cacheUpdateEmbedField( + interaction.user.tag, + interaction.options.getSubcommand(), + cacheSize.toString(), + duration, + ), + Colors.Green, + ), + ], + }); - try { - await modLogsChannel.send({ - embeds: [ - cacheUpdateEmbed( - interaction.options.getSubcommand(), - cacheUpdateEmbedField( - interaction.user.tag, - interaction.options.getSubcommand(), - cacheSize.toString(), - duration, - ), - Colors.Green, - ), - ], - }); - } catch (error) { - await interaction.followUp({ embeds: [noChannelEmbed(interaction.options.getSubcommand(), 'mod-log')] }); - } + try { + await modLogsChannel.send({ + embeds: [ + cacheUpdateEmbed( + interaction.options.getSubcommand(), + cacheUpdateEmbedField( + interaction.user.tag, + interaction.options.getSubcommand(), + cacheSize.toString(), + duration, + ), + Colors.Green, + ), + ], + }); + } catch (error) { + await interaction.followUp({ embeds: [noChannelEmbed(interaction.options.getSubcommand(), 'mod-log')] }); } + } }); diff --git a/src/commands/moderation/clearMessages.ts b/src/commands/moderation/clearMessages.ts index 9b6c5e05..ebca1712 100644 --- a/src/commands/moderation/clearMessages.ts +++ b/src/commands/moderation/clearMessages.ts @@ -1,129 +1,127 @@ import { - ApplicationCommandOptionType, - ApplicationCommandType, - TextChannel, - Colors, - ActionRowBuilder, - ButtonBuilder, - ButtonStyle, - Interaction, + ApplicationCommandOptionType, + ApplicationCommandType, + TextChannel, + Colors, + ActionRowBuilder, + ButtonBuilder, + ButtonStyle, + Interaction, } from 'discord.js'; import { slashCommand, slashCommandStructure, makeEmbed, constantsConfig, Logger } from '../../lib'; const data = slashCommandStructure({ - name: 'clear-messages', - description: 'Clear a specified number of messages in the current channel.', - type: ApplicationCommandType.ChatInput, - default_member_permissions: constantsConfig.commandPermission.MANAGE_SERVER, //Overrides need to be added for admin and moderator roles - dm_permission: false, - options: [ - { - name: 'amount', - description: 'Number of messages to clear (1-100).', - type: ApplicationCommandOptionType.Integer, - required: true, - min_value: 1, - max_value: 100, - }, - ], + name: 'clear-messages', + description: 'Clear a specified number of messages in the current channel.', + type: ApplicationCommandType.ChatInput, + default_member_permissions: constantsConfig.commandPermission.MANAGE_SERVER, //Overrides need to be added for admin and moderator roles + dm_permission: false, + options: [ + { + name: 'amount', + description: 'Number of messages to clear (1-100).', + type: ApplicationCommandOptionType.Integer, + required: true, + min_value: 1, + max_value: 100, + }, + ], }); export default slashCommand(data, async ({ interaction }) => { - const confirmButton = new ButtonBuilder() - .setCustomId('clearMessages_confirm') - .setLabel('Confirm') - .setStyle(ButtonStyle.Danger); + const confirmButton = new ButtonBuilder() + .setCustomId('clearMessages_confirm') + .setLabel('Confirm') + .setStyle(ButtonStyle.Danger); - const cancelButton = new ButtonBuilder() - .setCustomId('clearMessages_cancel') - .setLabel('Cancel') - .setStyle(ButtonStyle.Secondary); + const cancelButton = new ButtonBuilder() + .setCustomId('clearMessages_cancel') + .setLabel('Cancel') + .setStyle(ButtonStyle.Secondary); - const buttonRow = new ActionRowBuilder().addComponents(cancelButton, confirmButton); + const buttonRow = new ActionRowBuilder().addComponents(cancelButton, confirmButton); - const amount = interaction.options.getInteger('amount'); + const amount = interaction.options.getInteger('amount'); - if (!amount) { - return interaction.reply({ content: 'Please specify the number of messages to clear.', ephemeral: true }); - } - - const { channel, user } = interaction; - if (!channel) { - return interaction.reply({ content: 'The channel could not be resolved.', ephemeral: true }); - } + if (!amount) { + return interaction.reply({ content: 'Please specify the number of messages to clear.', ephemeral: true }); + } - const confirmEmbed = makeEmbed({ - title: 'Confirm or Cancel', - description: `You are about to clear **${amount}** message${amount > 1 ? 's' : ''}. This action **cannot** be undone.`, - color: Colors.Red, - footer: { text: 'Please confirm or cancel this action within 2 minutes.' }, - }); + const { channel, user } = interaction; + if (!channel) { + return interaction.reply({ content: 'The channel could not be resolved.', ephemeral: true }); + } - const response = await interaction.reply({ - embeds: [confirmEmbed], - components: [buttonRow], - ephemeral: true, - }); + const confirmEmbed = makeEmbed({ + title: 'Confirm or Cancel', + description: `You are about to clear **${amount}** message${amount > 1 ? 's' : ''}. This action **cannot** be undone.`, + color: Colors.Red, + footer: { text: 'Please confirm or cancel this action within 2 minutes.' }, + }); - const filter = (buttonInteraction: Interaction) => buttonInteraction.user.id === interaction.user.id; + const response = await interaction.reply({ + embeds: [confirmEmbed], + components: [buttonRow], + ephemeral: true, + }); - try { - const confirmation = await response.awaitMessageComponent({ filter, time: 120_000 }); - if (confirmation.customId === 'clearMessages_confirm') { - try { - const messages = await (channel as TextChannel).bulkDelete(amount, true); - const replyEmbed = makeEmbed({ - title: 'Messages Cleared', - description: `Successfully cleared **${messages.size}** message${amount > 1 ? 's' : ''}.`, - color: Colors.Green, - timestamp: new Date(), - }); + const filter = (buttonInteraction: Interaction) => buttonInteraction.user.id === interaction.user.id; - const modLogsChannel = interaction.guild.channels.resolve( - constantsConfig.channels.MOD_LOGS, - ) as TextChannel; - const modLogEmbed = makeEmbed({ - title: '🧹 Messages Cleared', - description: 'Messages have been cleared.', - color: Colors.Green, - fields: [ - { name: 'Moderator', value: `<@${user.id}>`, inline: true }, - { name: 'Channel', value: `<#${channel.id}>`, inline: true }, - { name: 'Amount', value: `${messages.size}`, inline: true }, - ], - footer: { text: `Moderator ID: ${user.id}`, iconURL: user.displayAvatarURL() }, - timestamp: new Date(), - }); + try { + const confirmation = await response.awaitMessageComponent({ filter, time: 120_000 }); + if (confirmation.customId === 'clearMessages_confirm') { + try { + const messages = await (channel as TextChannel).bulkDelete(amount, true); + const replyEmbed = makeEmbed({ + title: 'Messages Cleared', + description: `Successfully cleared **${messages.size}** message${amount > 1 ? 's' : ''}.`, + color: Colors.Green, + timestamp: new Date(), + }); - try { - await modLogsChannel.send({ embeds: [modLogEmbed] }); - } catch (e) { - Logger.error('An error occurred while trying to send the mod log:', e); - } - setTimeout(async () => { - try { - return interaction.deleteReply(); - } catch (error) { - Logger.error('Failed to delete the reply message:', error); - return interaction.editReply({ content: 'Failed to delete the reply message.' }); - } - }, 5000); - return interaction.editReply({ content: '', embeds: [replyEmbed], components: [] }); - } catch (error) { - Logger.error('Error clearing messages:', error); - return interaction.editReply({ - content: 'There was an error trying to clear messages in this channel. The error has been logged.', - }); - } - } else { - const canceledEmbed = makeEmbed({ - title: 'Interaction canceled.', - color: Colors.Yellow, - }); + const modLogsChannel = interaction.guild.channels.resolve(constantsConfig.channels.MOD_LOGS) as TextChannel; + const modLogEmbed = makeEmbed({ + title: '🧹 Messages Cleared', + description: 'Messages have been cleared.', + color: Colors.Green, + fields: [ + { name: 'Moderator', value: `<@${user.id}>`, inline: true }, + { name: 'Channel', value: `<#${channel.id}>`, inline: true }, + { name: 'Amount', value: `${messages.size}`, inline: true }, + ], + footer: { text: `Moderator ID: ${user.id}`, iconURL: user.displayAvatarURL() }, + timestamp: new Date(), + }); - return interaction.editReply({ embeds: [canceledEmbed], components: [] }); + try { + await modLogsChannel.send({ embeds: [modLogEmbed] }); + } catch (e) { + Logger.error('An error occurred while trying to send the mod log:', e); } - } catch (e) { - return interaction.editReply({ content: 'The command timed out.', components: [] }); + setTimeout(async () => { + try { + return interaction.deleteReply(); + } catch (error) { + Logger.error('Failed to delete the reply message:', error); + return interaction.editReply({ content: 'Failed to delete the reply message.' }); + } + }, 5000); + return interaction.editReply({ content: '', embeds: [replyEmbed], components: [] }); + } catch (error) { + Logger.error('Error clearing messages:', error); + return interaction.editReply({ + content: 'There was an error trying to clear messages in this channel. The error has been logged.', + }); + } + } else { + const canceledEmbed = makeEmbed({ + title: 'Interaction canceled.', + color: Colors.Yellow, + }); + + return interaction.editReply({ embeds: [canceledEmbed], components: [] }); } + } catch (e) { + return interaction.editReply({ content: 'The command timed out.', components: [] }); + } }); diff --git a/src/commands/moderation/commandTable.ts b/src/commands/moderation/commandTable.ts index 66ee5f0f..26eb71da 100644 --- a/src/commands/moderation/commandTable.ts +++ b/src/commands/moderation/commandTable.ts @@ -3,119 +3,119 @@ import { S3Client, PutObjectCommand } from '@aws-sdk/client-s3'; import { slashCommand, slashCommandStructure, Logger, constantsConfig } from '../../lib'; const data = slashCommandStructure({ - name: 'generate-command-table', - description: 'Generates the command table.', - type: ApplicationCommandType.ChatInput, - default_member_permissions: constantsConfig.commandPermission.MANAGE_SERVER, //Overrides need to be added for admin, moderator bot developer and docs team roles - dm_permission: false, + name: 'generate-command-table', + description: 'Generates the command table.', + type: ApplicationCommandType.ChatInput, + default_member_permissions: constantsConfig.commandPermission.MANAGE_SERVER, //Overrides need to be added for admin, moderator bot developer and docs team roles + dm_permission: false, }); export default slashCommand(data, async ({ interaction }: { interaction: CommandInteraction }) => { - try { - // Fetch all commands from the API based on the environment - let commands; - - if (process.env.NODE_ENV === 'production') { - commands = await interaction.client.application?.commands.fetch(); - } else { - commands = await interaction.guild?.commands.fetch(); - } - - // Check if the commands were fetched successfully - if (!commands) { - return interaction.reply({ - content: 'An error occurred while fetching commands.', - ephemeral: true, - }); - } - - // Convert the iterable of commands into an array - const commandArray = Array.from(commands.values()); - - // Sort the commands alphabetically by name - const sortedCommands = commandArray.sort((a, b) => a.name.localeCompare(b.name)); - - // Build the Markdown table - let table = '## Bot Commands\n\n| Command | Description | Subcommand and Groups |\n| --- | --- | --- |\n'; - - for (const command of sortedCommands) { - // eslint-disable-next-line prefer-const - let { name, description, type } = command; - - const subcommandList = command.options?.filter( - (option) => - option.type === ApplicationCommandOptionType.Subcommand || - option.type === ApplicationCommandOptionType.SubcommandGroup, - ); - - let subcommandDescription = ''; - - if (subcommandList && subcommandList.length > 0) { - subcommandDescription = subcommandList - .map((subcommand) => { - if (subcommand.type === ApplicationCommandOptionType.Subcommand) { - return subcommand.name; - } - if (subcommand.type === ApplicationCommandOptionType.SubcommandGroup) { - const groupSubcommands = subcommand.options?.filter( - (sub) => sub.type === ApplicationCommandOptionType.Subcommand, - ); - if (groupSubcommands && groupSubcommands.length > 0) { - return `${subcommand.name} [${groupSubcommands.map((sub) => sub.name).join(', ')}]`; - } - return `${subcommand.name} [None]`; - } - return ''; - }) - .join(', '); - } + try { + // Fetch all commands from the API based on the environment + let commands; + + if (process.env.NODE_ENV === 'production') { + commands = await interaction.client.application?.commands.fetch(); + } else { + commands = await interaction.guild?.commands.fetch(); + } + + // Check if the commands were fetched successfully + if (!commands) { + return interaction.reply({ + content: 'An error occurred while fetching commands.', + ephemeral: true, + }); + } + + // Convert the iterable of commands into an array + const commandArray = Array.from(commands.values()); + + // Sort the commands alphabetically by name + const sortedCommands = commandArray.sort((a, b) => a.name.localeCompare(b.name)); + + // Build the Markdown table + let table = '## Bot Commands\n\n| Command | Description | Subcommand and Groups |\n| --- | --- | --- |\n'; - // Denote context-specific commands in the description - if (type === ApplicationCommandType.User || type === ApplicationCommandType.Message) { - description += `(Context Command - ${type === ApplicationCommandType.User ? 'User' : 'Message'})`; + for (const command of sortedCommands) { + // eslint-disable-next-line prefer-const + let { name, description, type } = command; + + const subcommandList = command.options?.filter( + (option) => + option.type === ApplicationCommandOptionType.Subcommand || + option.type === ApplicationCommandOptionType.SubcommandGroup, + ); + + let subcommandDescription = ''; + + if (subcommandList && subcommandList.length > 0) { + subcommandDescription = subcommandList + .map((subcommand) => { + if (subcommand.type === ApplicationCommandOptionType.Subcommand) { + return subcommand.name; + } + if (subcommand.type === ApplicationCommandOptionType.SubcommandGroup) { + const groupSubcommands = subcommand.options?.filter( + (sub) => sub.type === ApplicationCommandOptionType.Subcommand, + ); + if (groupSubcommands && groupSubcommands.length > 0) { + return `${subcommand.name} [${groupSubcommands.map((sub) => sub.name).join(', ')}]`; + } + return `${subcommand.name} [None]`; } + return ''; + }) + .join(', '); + } + + // Denote context-specific commands in the description + if (type === ApplicationCommandType.User || type === ApplicationCommandType.Message) { + description += `(Context Command - ${type === ApplicationCommandType.User ? 'User' : 'Message'})`; + } + + // Append subcommands to the Subcommands column + table += `| ${name} | ${description} | ${subcommandDescription} |\n`; + } + + // Upload the file to Cloudflare R2 + const uploadParams = { + Bucket: process.env.CLOUDFLARE_BUCKET_NAME, + Key: 'utils/commands_table.md', + Body: table, + }; - // Append subcommands to the Subcommands column - table += `| ${name} | ${description} | ${subcommandDescription} |\n`; - } - - // Upload the file to Cloudflare R2 - const uploadParams = { - Bucket: process.env.CLOUDFLARE_BUCKET_NAME, - Key: 'utils/commands_table.md', - Body: table, - }; - - try { - const S3 = new S3Client({ - region: 'auto', - endpoint: `https://${process.env.CLOUDFLARE_ACCOUNT_ID}.r2.cloudflarestorage.com`, - credentials: { - accessKeyId: process.env.CLOUDFLARE_ACCESS_KEY_ID!, - secretAccessKey: process.env.CLOUDFLARE_SECRET_ACCESS_KEY!, - }, - }); - - const commandTableUpload = new PutObjectCommand(uploadParams); - await S3.send(commandTableUpload); - Logger.info('Successfully uploaded commands table to Cloudflare R2.'); - } catch (error) { - Logger.error(error); - return interaction.reply({ - content: 'An error occurred while uploading to Cloudflare R2.', - ephemeral: true, - }); - } - - return interaction.reply({ - content: 'Markdown table has been saved and uploaded to Cloudflare R2.', - ephemeral: true, - }); + try { + const S3 = new S3Client({ + region: 'auto', + endpoint: `https://${process.env.CLOUDFLARE_ACCOUNT_ID}.r2.cloudflarestorage.com`, + credentials: { + accessKeyId: process.env.CLOUDFLARE_ACCESS_KEY_ID!, + secretAccessKey: process.env.CLOUDFLARE_SECRET_ACCESS_KEY!, + }, + }); + + const commandTableUpload = new PutObjectCommand(uploadParams); + await S3.send(commandTableUpload); + Logger.info('Successfully uploaded commands table to Cloudflare R2.'); } catch (error) { - Logger.error(error); - return interaction.reply({ - content: 'An error occurred while generating the Markdown file.', - ephemeral: true, - }); + Logger.error(error); + return interaction.reply({ + content: 'An error occurred while uploading to Cloudflare R2.', + ephemeral: true, + }); } + + return interaction.reply({ + content: 'Markdown table has been saved and uploaded to Cloudflare R2.', + ephemeral: true, + }); + } catch (error) { + Logger.error(error); + return interaction.reply({ + content: 'An error occurred while generating the Markdown file.', + ephemeral: true, + }); + } }); diff --git a/src/commands/moderation/deployCommands.ts b/src/commands/moderation/deployCommands.ts index f7b59a8b..03807188 100644 --- a/src/commands/moderation/deployCommands.ts +++ b/src/commands/moderation/deployCommands.ts @@ -6,58 +6,58 @@ import contextArray from '../context/index'; import { client } from '../../client'; const data = slashCommandStructure({ - name: 'deploy-commands', - description: 'Deploy commands to the server or globally.', - type: ApplicationCommandType.ChatInput, - default_member_permissions: constantsConfig.commandPermission.MANAGE_SERVER, //Overrides need to be added for admin, moderator and bot developer roles - dm_permission: false, + name: 'deploy-commands', + description: 'Deploy commands to the server or globally.', + type: ApplicationCommandType.ChatInput, + default_member_permissions: constantsConfig.commandPermission.MANAGE_SERVER, //Overrides need to be added for admin, moderator and bot developer roles + dm_permission: false, }); export default slashCommand(data, async ({ interaction }) => { - if (interaction.guild) { - try { - await deployCommands(commandArray, contextArray).then(async (user) => { - const bot = `<@${user.id}>`; + if (interaction.guild) { + try { + await deployCommands(commandArray, contextArray).then(async (user) => { + const bot = `<@${user.id}>`; - const guildID = constantsConfig.guildId; - if (!guildID) { - await interaction.reply('guildId configuration constant is not defined.'); - return; - } + const guildID = constantsConfig.guildId; + if (!guildID) { + await interaction.reply('guildId configuration constant is not defined.'); + return; + } - const guildName = client.guilds.cache.get(guildID); + const guildName = client.guilds.cache.get(guildID); - let response; - //If the bot is deployed to a guild and can resolve the name, use the guild name in the response - if (guildName) { - response = - process.env.NODE_ENV === 'production' - ? `Deployed ${commandArray.length} commands and ${contextArray.length} contexts globally as ${bot}!` - : `Deployed ${commandArray.length} commands and ${contextArray.length} contexts to \`${guildName}\` as ${bot}!`; - } else { - //If the bot can't gather the guild name, use the ID in the response - response = - process.env.NODE_ENV === 'production' - ? `Deployed ${commandArray.length} commands and ${contextArray.length} contexts globally as ${bot}!` - : `Deployed ${commandArray.length} commands and ${contextArray.length} contexts to \`<@${guildID}>\` as ${bot}!`; - } - Logger.info(response); - await interaction.reply({ - content: response, - ephemeral: true, - }); - }); - } catch (error) { - await interaction.reply({ - content: 'Failed to deploy commands!', - ephemeral: true, - }); - Logger.error(error); + let response; + //If the bot is deployed to a guild and can resolve the name, use the guild name in the response + if (guildName) { + response = + process.env.NODE_ENV === 'production' + ? `Deployed ${commandArray.length} commands and ${contextArray.length} contexts globally as ${bot}!` + : `Deployed ${commandArray.length} commands and ${contextArray.length} contexts to \`${guildName}\` as ${bot}!`; + } else { + //If the bot can't gather the guild name, use the ID in the response + response = + process.env.NODE_ENV === 'production' + ? `Deployed ${commandArray.length} commands and ${contextArray.length} contexts globally as ${bot}!` + : `Deployed ${commandArray.length} commands and ${contextArray.length} contexts to \`<@${guildID}>\` as ${bot}!`; } - } else { + Logger.info(response); await interaction.reply({ - content: 'This command can only be used in a guild!', - ephemeral: true, + content: response, + ephemeral: true, }); + }); + } catch (error) { + await interaction.reply({ + content: 'Failed to deploy commands!', + ephemeral: true, + }); + Logger.error(error); } + } else { + await interaction.reply({ + content: 'This command can only be used in a guild!', + ephemeral: true, + }); + } }); diff --git a/src/commands/moderation/faq/faq.ts b/src/commands/moderation/faq/faq.ts index f003ddb1..454cbfaf 100644 --- a/src/commands/moderation/faq/faq.ts +++ b/src/commands/moderation/faq/faq.ts @@ -6,77 +6,77 @@ import { handleListFaq } from './functions/listFaq'; import { handlePrintAllFAQ } from './functions/faqPrintAll'; const data = slashCommandStructure({ - name: 'faq', - description: 'Command to manage FAQ messages.', - type: ApplicationCommandType.ChatInput, - default_member_permissions: constantsConfig.commandPermission.MANAGE_SERVER, //Overrides need to be added for admin and moderator - dm_permission: false, - options: [ + name: 'faq', + description: 'Command to manage FAQ messages.', + type: ApplicationCommandType.ChatInput, + default_member_permissions: constantsConfig.commandPermission.MANAGE_SERVER, //Overrides need to be added for admin and moderator + dm_permission: false, + options: [ + { + name: 'add', + description: 'Adds an FAQ.', + type: ApplicationCommandOptionType.Subcommand, + }, + { + name: 'remove', + description: 'Removes an FAQ.', + type: ApplicationCommandOptionType.Subcommand, + options: [ { - name: 'add', - description: 'Adds an FAQ.', - type: ApplicationCommandOptionType.Subcommand, + name: 'faq_id', + description: 'ID of FAQ to remove.', + type: ApplicationCommandOptionType.String, + required: true, }, - { - name: 'remove', - description: 'Removes an FAQ.', - type: ApplicationCommandOptionType.Subcommand, - options: [ - { - name: 'faq_id', - description: 'ID of FAQ to remove.', - type: ApplicationCommandOptionType.String, - required: true, - }, - ], - }, - { - name: 'list', - description: 'Lists all FAQs.', - type: ApplicationCommandOptionType.Subcommand, - }, - { - name: 'print-all', - description: 'Prints all FAQs.', - type: ApplicationCommandOptionType.Subcommand, - }, - ], + ], + }, + { + name: 'list', + description: 'Lists all FAQs.', + type: ApplicationCommandOptionType.Subcommand, + }, + { + name: 'print-all', + description: 'Prints all FAQs.', + type: ApplicationCommandOptionType.Subcommand, + }, + ], }); const noConnEmbed = makeEmbed({ - title: 'FAQ - No Connection', - description: 'Could not connect to the database', - color: Colors.Red, + title: 'FAQ - No Connection', + description: 'Could not connect to the database', + color: Colors.Red, }); export default slashCommand(data, async ({ interaction }) => { - const conn = getConn(); + const conn = getConn(); - if (!conn) { - await interaction.reply({ embeds: [noConnEmbed], ephemeral: true }); - return; - } + if (!conn) { + await interaction.reply({ embeds: [noConnEmbed], ephemeral: true }); + return; + } - const subcommandName = interaction.options.getSubcommand(); + const subcommandName = interaction.options.getSubcommand(); - const faqID = interaction.options.getString('faq_id')!; - const modLogsChannel = interaction.guild.channels.resolve(constantsConfig.channels.MOD_LOGS) as TextChannel; + const faqID = interaction.options.getString('faq_id')!; + const modLogsChannel = interaction.guild.channels.resolve(constantsConfig.channels.MOD_LOGS) as TextChannel; - switch (subcommandName) { - case 'add': - await handleAddFaq(interaction, modLogsChannel); - break; - case 'remove': - await handleRemoveFaq(interaction, faqID, modLogsChannel); - break; - case 'list': - await handleListFaq(interaction); - break; - case 'print-all': - await handlePrintAllFAQ(interaction); - break; + switch (subcommandName) { + case 'add': + await handleAddFaq(interaction, modLogsChannel); + break; + case 'remove': + await handleRemoveFaq(interaction, faqID, modLogsChannel); + break; + case 'list': + await handleListFaq(interaction); + break; + case 'print-all': + await handlePrintAllFAQ(interaction); + break; - default: - await interaction.reply({ content: 'Unknown subcommand', ephemeral: true }); - } + default: + await interaction.reply({ content: 'Unknown subcommand', ephemeral: true }); + } }); diff --git a/src/commands/moderation/faq/functions/addFaq.ts b/src/commands/moderation/faq/functions/addFaq.ts index d2fbb510..5b08875e 100644 --- a/src/commands/moderation/faq/functions/addFaq.ts +++ b/src/commands/moderation/faq/functions/addFaq.ts @@ -1,138 +1,138 @@ import { - ActionRowBuilder, - ChatInputCommandInteraction, - Colors, - ModalBuilder, - TextChannel, - TextInputBuilder, - TextInputStyle, - User, + ActionRowBuilder, + ChatInputCommandInteraction, + Colors, + ModalBuilder, + TextChannel, + TextInputBuilder, + TextInputStyle, + User, } from 'discord.js'; import { Logger, makeEmbed, FAQ } from '../../../../lib'; const faqAddedEmbed = (discordUser: User, question: string, answer: string) => - makeEmbed({ - author: { - name: `[FAQ Added] ${discordUser.tag}`, - iconURL: discordUser.displayAvatarURL(), - }, - fields: [ - { - inline: false, - name: 'Question', - value: question, - }, - { - inline: false, - name: 'Answer', - value: answer, - }, - ], - color: Colors.Green, - }); + makeEmbed({ + author: { + name: `[FAQ Added] ${discordUser.tag}`, + iconURL: discordUser.displayAvatarURL(), + }, + fields: [ + { + inline: false, + name: 'Question', + value: question, + }, + { + inline: false, + name: 'Answer', + value: answer, + }, + ], + color: Colors.Green, + }); export async function handleAddFaq(interaction: ChatInputCommandInteraction<'cached'>, modLogsChannel: TextChannel) { - const modal = new ModalBuilder({ - customId: 'faqAddModal', - title: 'Add an FAQ entry', - }); - - const faqTitleInput = new TextInputBuilder({ - customId: 'faqTitleInput', - label: 'Title', - placeholder: 'Please enter the title of the FAQ.', - style: TextInputStyle.Short, - maxLength: 500, - required: true, + const modal = new ModalBuilder({ + customId: 'faqAddModal', + title: 'Add an FAQ entry', + }); + + const faqTitleInput = new TextInputBuilder({ + customId: 'faqTitleInput', + label: 'Title', + placeholder: 'Please enter the title of the FAQ.', + style: TextInputStyle.Short, + maxLength: 500, + required: true, + }); + + const faqAnswerInput = new TextInputBuilder({ + customId: 'faqAnswerInput', + label: 'Answer', + placeholder: 'If you wish to mention a role or channel use <@&*ID*> or <#*ID*> respectively.', + style: TextInputStyle.Paragraph, + maxLength: 1000, + required: true, + }); + + const titleActionRow = new ActionRowBuilder().addComponents(faqTitleInput); + const answerActionRow = new ActionRowBuilder().addComponents(faqAnswerInput); + + modal.addComponents(titleActionRow, answerActionRow); + + await interaction.showModal(modal); + + //Modal sent + + const filter = (interaction: { customId: string; user: { id: any } }) => + interaction.customId === 'faqAddModal' && interaction.user.id; + + try { + //Await a modal response + const modalSubmitInteraction = await interaction.awaitModalSubmit({ + filter, + time: 120000, }); - const faqAnswerInput = new TextInputBuilder({ - customId: 'faqAnswerInput', - label: 'Answer', - placeholder: 'If you wish to mention a role or channel use <@&*ID*> or <#*ID*> respectively.', - style: TextInputStyle.Paragraph, - maxLength: 1000, - required: true, + //Respond to the user once they have submitted the modal + await modalSubmitInteraction.reply({ + content: 'FAQ Modal Submitted! I will try and add the FAQ to the database.', + ephemeral: true, }); - const titleActionRow = new ActionRowBuilder().addComponents(faqTitleInput); - const answerActionRow = new ActionRowBuilder().addComponents(faqAnswerInput); - - modal.addComponents(titleActionRow, answerActionRow); - - await interaction.showModal(modal); - - //Modal sent + const faqTitle = modalSubmitInteraction.fields.getTextInputValue('faqTitleInput'); + const faqAnswer = modalSubmitInteraction.fields.getTextInputValue('faqAnswerInput'); + + const discordUser = interaction.user; + const currentDate = new Date(); + + let faqData = await FAQ.findOne({ faqTitle }); + + if (!faqData) { + faqData = new FAQ({ + faqTitle: faqTitle!, + faqAnswer: faqAnswer!, + moderatorID: discordUser.id, + dateSet: currentDate, + }); + } else { + await interaction.followUp({ + content: 'FAQ with this title already exists. Please choose another title', + ephemeral: true, + }); + return; + } - const filter = (interaction: { customId: string; user: { id: any } }) => - interaction.customId === 'faqAddModal' && interaction.user.id; + try { + await faqData.save(); + } catch (error) { + Logger.error(error); + await interaction.followUp({ + content: 'Could not add FAQ, error has been logged, please notify the bot team.', + ephemeral: true, + }); + return; + } try { - //Await a modal response - const modalSubmitInteraction = await interaction.awaitModalSubmit({ - filter, - time: 120000, - }); - - //Respond to the user once they have submitted the modal - await modalSubmitInteraction.reply({ - content: 'FAQ Modal Submitted! I will try and add the FAQ to the database.', - ephemeral: true, - }); - - const faqTitle = modalSubmitInteraction.fields.getTextInputValue('faqTitleInput'); - const faqAnswer = modalSubmitInteraction.fields.getTextInputValue('faqAnswerInput'); - - const discordUser = interaction.user; - const currentDate = new Date(); - - let faqData = await FAQ.findOne({ faqTitle }); - - if (!faqData) { - faqData = new FAQ({ - faqTitle: faqTitle!, - faqAnswer: faqAnswer!, - moderatorID: discordUser.id, - dateSet: currentDate, - }); - } else { - await interaction.followUp({ - content: 'FAQ with this title already exists. Please choose another title', - ephemeral: true, - }); - return; - } - - try { - await faqData.save(); - } catch (error) { - Logger.error(error); - await interaction.followUp({ - content: 'Could not add FAQ, error has been logged, please notify the bot team.', - ephemeral: true, - }); - return; - } - - try { - await modLogsChannel.send({ embeds: [faqAddedEmbed(discordUser, faqTitle, faqAnswer)] }); - } catch (error) { - Logger.error(error); - await interaction.followUp({ - content: - 'FAQ added successfully, but could not send mod log, error has been logged, please notify the bot team.', - ephemeral: true, - }); - return; - } - - await interaction.followUp({ content: 'FAQ added successfully.', ephemeral: true }); + await modLogsChannel.send({ embeds: [faqAddedEmbed(discordUser, faqTitle, faqAnswer)] }); } catch (error) { - //Handle the error if the user does not respond in time - Logger.error(error); - await interaction.followUp({ - content: 'You did not provide a response in time. Please try again.', - ephemeral: true, - }); + Logger.error(error); + await interaction.followUp({ + content: + 'FAQ added successfully, but could not send mod log, error has been logged, please notify the bot team.', + ephemeral: true, + }); + return; } + + await interaction.followUp({ content: 'FAQ added successfully.', ephemeral: true }); + } catch (error) { + //Handle the error if the user does not respond in time + Logger.error(error); + await interaction.followUp({ + content: 'You did not provide a response in time. Please try again.', + ephemeral: true, + }); + } } diff --git a/src/commands/moderation/faq/functions/faqPrintAll.ts b/src/commands/moderation/faq/functions/faqPrintAll.ts index 15421ed7..cb67a9c3 100644 --- a/src/commands/moderation/faq/functions/faqPrintAll.ts +++ b/src/commands/moderation/faq/functions/faqPrintAll.ts @@ -4,70 +4,70 @@ import { constantsConfig, imageBaseUrl, Logger, makeEmbed, FAQ } from '../../../ const FLIGHT_DECK_IMAGE_URL = `${imageBaseUrl}/moderation/faq.png`; const linksEmbed = makeEmbed({ - title: 'Useful Links', - fields: [ - { - name: '**Docs FAQ**', - value: 'https://docs.flybywiresim.com/fbw-a32nx/faq/', - }, - { - name: '**Beginners Guide**', - value: 'https://docs.flybywiresim.com/pilots-corner/beginner-guide/overview/', - }, - { - name: '**Flight School**', - value: `<#${constantsConfig.channels.FLIGHT_SCHOOL}>`, - }, - { - name: '**Support**', - value: `<#${constantsConfig.channels.A32NX_SUPPORT}>`, - }, - ], + title: 'Useful Links', + fields: [ + { + name: '**Docs FAQ**', + value: 'https://docs.flybywiresim.com/fbw-a32nx/faq/', + }, + { + name: '**Beginners Guide**', + value: 'https://docs.flybywiresim.com/pilots-corner/beginner-guide/overview/', + }, + { + name: '**Flight School**', + value: `<#${constantsConfig.channels.FLIGHT_SCHOOL}>`, + }, + { + name: '**Support**', + value: `<#${constantsConfig.channels.A32NX_SUPPORT}>`, + }, + ], }); export async function handlePrintAllFAQ(interaction: ChatInputCommandInteraction<'cached'>) { - await interaction.deferReply({ ephemeral: true }); + await interaction.deferReply({ ephemeral: true }); - try { - // Fetch all FAQs from the database - const faqs = await FAQ.find(); + try { + // Fetch all FAQs from the database + const faqs = await FAQ.find(); - if (faqs.length === 0) { - return interaction.followUp('No FAQs found.'); - } - if (interaction.channel) { - await interaction.channel.send({ files: [FLIGHT_DECK_IMAGE_URL] }); + if (faqs.length === 0) { + return interaction.followUp('No FAQs found.'); + } + if (interaction.channel) { + await interaction.channel.send({ files: [FLIGHT_DECK_IMAGE_URL] }); - // Divide the FAQs into sets of 5 - const faqSets = []; - for (let i = 0; i < faqs.length; i += 5) { - const faqSet = faqs.slice(i, i + 5); - faqSets.push(faqSet); - } + // Divide the FAQs into sets of 5 + const faqSets = []; + for (let i = 0; i < faqs.length; i += 5) { + const faqSet = faqs.slice(i, i + 5); + faqSets.push(faqSet); + } - // Send an embed for each set of FAQs - for (let i = 0; i < faqSets.length; i++) { - const faqSet = faqSets[i]; - const faqEmbed = makeEmbed({ - title: `Frequently Asked Questions (${i + 1}/${faqSets.length})`, - fields: faqSet.map((faq) => ({ - name: `**${faq.faqTitle}**`, - value: `${faq.faqAnswer}`, - })), - }); + // Send an embed for each set of FAQs + for (let i = 0; i < faqSets.length; i++) { + const faqSet = faqSets[i]; + const faqEmbed = makeEmbed({ + title: `Frequently Asked Questions (${i + 1}/${faqSets.length})`, + fields: faqSet.map((faq) => ({ + name: `**${faq.faqTitle}**`, + value: `${faq.faqAnswer}`, + })), + }); - // eslint-disable-next-line no-await-in-loop - await interaction.channel.send({ embeds: [faqEmbed] }); - } + // eslint-disable-next-line no-await-in-loop + await interaction.channel.send({ embeds: [faqEmbed] }); + } - await interaction.channel.send({ embeds: [linksEmbed] }); - } else { - return interaction.followUp({ content: 'FAQs can only be printed in a text channel.', ephemeral: true }); - } - } catch (error) { - Logger.error('Error fetching FAQs:', error); - return interaction.followUp('An error occurred while fetching FAQs.'); + await interaction.channel.send({ embeds: [linksEmbed] }); + } else { + return interaction.followUp({ content: 'FAQs can only be printed in a text channel.', ephemeral: true }); } + } catch (error) { + Logger.error('Error fetching FAQs:', error); + return interaction.followUp('An error occurred while fetching FAQs.'); + } - return interaction.followUp({ content: 'FAQs printed successfully.', ephemeral: true }); + return interaction.followUp({ content: 'FAQs printed successfully.', ephemeral: true }); } diff --git a/src/commands/moderation/faq/functions/listFaq.ts b/src/commands/moderation/faq/functions/listFaq.ts index d0b651f7..7cd9322b 100644 --- a/src/commands/moderation/faq/functions/listFaq.ts +++ b/src/commands/moderation/faq/functions/listFaq.ts @@ -3,81 +3,81 @@ import moment from 'moment/moment'; import { Logger, makeEmbed, FAQ, createPaginatedEmbedHandler } from '../../../../lib'; const faqListEmbed = (faqFields: { name: string; value: string }[], currentPage: number, totalPages: number) => - makeEmbed({ - title: `FAQ List (Page ${currentPage} of ${totalPages})`, - fields: faqFields, - }); + makeEmbed({ + title: `FAQ List (Page ${currentPage} of ${totalPages})`, + fields: faqFields, + }); export async function handleListFaq(interaction: ChatInputCommandInteraction<'cached'>) { - try { - const faqs = await FAQ.find({}); - - if (!faqs.length) { - await interaction.reply({ content: 'No FAQs exist.', ephemeral: true }); - return; - } + try { + const faqs = await FAQ.find({}); - const pageLimit = 5; - const embeds = []; - let currentPage = 1; - let faqsAddedToPage = 0; - const faqFields: { name: string; value: string }[] = []; + if (!faqs.length) { + await interaction.reply({ content: 'No FAQs exist.', ephemeral: true }); + return; + } - const moderatorPromises = faqs.map((currentFaq) => - interaction.client.users - .fetch(currentFaq.moderatorID!) - // Added for better readability - // eslint-disable-next-line arrow-body-style - .catch(() => { - return new Promise((resolve) => { - resolve(`I can't find the moderator, here is the stored ID: ${currentFaq.moderatorID}`); - }); - }), - ); - const moderatorUsers = await Promise.all(moderatorPromises); + const pageLimit = 5; + const embeds = []; + let currentPage = 1; + let faqsAddedToPage = 0; + const faqFields: { name: string; value: string }[] = []; - for (let i = 0; i < faqs.length; i++) { - const formattedDate = moment(faqs[i].dateSet).utcOffset(0).format(); + const moderatorPromises = faqs.map((currentFaq) => + interaction.client.users + .fetch(currentFaq.moderatorID!) + // Added for better readability + // eslint-disable-next-line arrow-body-style + .catch(() => { + return new Promise((resolve) => { + resolve(`I can't find the moderator, here is the stored ID: ${currentFaq.moderatorID}`); + }); + }), + ); + const moderatorUsers = await Promise.all(moderatorPromises); - faqFields.push( - { - name: `**Title:** ${faqs[i].faqTitle}`, - value: - `**Answer:** ${faqs[i].faqAnswer}\n` + - `**Moderator:** ${moderatorUsers[i]}\n` + - `**Date Set:** ${formattedDate}\n` + - `**FAQ ID:** ${faqs[i].id}\n`, - }, - { - name: '', - value: '----------------------------------------', - }, - ); + for (let i = 0; i < faqs.length; i++) { + const formattedDate = moment(faqs[i].dateSet).utcOffset(0).format(); - faqsAddedToPage++; - if (faqsAddedToPage >= pageLimit) { - embeds.push(faqListEmbed(faqFields, currentPage, Math.ceil(faqs.length / pageLimit))); - faqsAddedToPage = 0; - faqFields.length = 0; - currentPage++; - } - } + faqFields.push( + { + name: `**Title:** ${faqs[i].faqTitle}`, + value: + `**Answer:** ${faqs[i].faqAnswer}\n` + + `**Moderator:** ${moderatorUsers[i]}\n` + + `**Date Set:** ${formattedDate}\n` + + `**FAQ ID:** ${faqs[i].id}\n`, + }, + { + name: '', + value: '----------------------------------------', + }, + ); - if (faqFields.length > 0) { - embeds.push(faqListEmbed(faqFields, currentPage, Math.ceil(faqs.length / pageLimit))); - } + faqsAddedToPage++; + if (faqsAddedToPage >= pageLimit) { + embeds.push(faqListEmbed(faqFields, currentPage, Math.ceil(faqs.length / pageLimit))); + faqsAddedToPage = 0; + faqFields.length = 0; + currentPage++; + } + } - if (embeds.length === 0) { - await interaction.reply({ content: 'No FAQs exist.', ephemeral: true }); - return; - } + if (faqFields.length > 0) { + embeds.push(faqListEmbed(faqFields, currentPage, Math.ceil(faqs.length / pageLimit))); + } - await createPaginatedEmbedHandler(interaction, embeds); - } catch (error) { - Logger.error(error); - await interaction.reply({ - content: 'Could not list FAQs, error has been logged, please notify the bot team.', - ephemeral: true, - }); + if (embeds.length === 0) { + await interaction.reply({ content: 'No FAQs exist.', ephemeral: true }); + return; } + + await createPaginatedEmbedHandler(interaction, embeds); + } catch (error) { + Logger.error(error); + await interaction.reply({ + content: 'Could not list FAQs, error has been logged, please notify the bot team.', + ephemeral: true, + }); + } } diff --git a/src/commands/moderation/faq/functions/removeFaq.ts b/src/commands/moderation/faq/functions/removeFaq.ts index 30b508fc..185ffd94 100644 --- a/src/commands/moderation/faq/functions/removeFaq.ts +++ b/src/commands/moderation/faq/functions/removeFaq.ts @@ -2,65 +2,65 @@ import { ChatInputCommandInteraction, Colors, TextChannel, User } from 'discord. import { Logger, makeEmbed, FAQ } from '../../../../lib'; const faqRemovedEmbed = (discordUser: User, faqQuestion: string, faqAnswer: string) => - makeEmbed({ - author: { - name: `[FAQ Removed] ${discordUser.tag}`, - iconURL: discordUser.displayAvatarURL(), - }, - fields: [ - { - inline: false, - name: 'Question', - value: faqQuestion, - }, - { - inline: false, - name: 'Answer', - value: faqAnswer, - }, - ], - color: Colors.Red, - }); + makeEmbed({ + author: { + name: `[FAQ Removed] ${discordUser.tag}`, + iconURL: discordUser.displayAvatarURL(), + }, + fields: [ + { + inline: false, + name: 'Question', + value: faqQuestion, + }, + { + inline: false, + name: 'Answer', + value: faqAnswer, + }, + ], + color: Colors.Red, + }); export async function handleRemoveFaq( - interaction: ChatInputCommandInteraction<'cached'>, - faqID: string, - modLogsChannel: TextChannel, + interaction: ChatInputCommandInteraction<'cached'>, + faqID: string, + modLogsChannel: TextChannel, ) { - const discordUser = interaction.user; + const discordUser = interaction.user; - const faqEntry = await FAQ.findOne({ _id: faqID }); + const faqEntry = await FAQ.findOne({ _id: faqID }); - if (!faqEntry) { - await interaction.reply({ content: 'FAQ with this ID does not exist.', ephemeral: true }); - return; - } + if (!faqEntry) { + await interaction.reply({ content: 'FAQ with this ID does not exist.', ephemeral: true }); + return; + } - const faqTitle = faqEntry.faqTitle || 'Unknown'; - const faqAnswer = faqEntry.faqAnswer || 'Unknown'; + const faqTitle = faqEntry.faqTitle || 'Unknown'; + const faqAnswer = faqEntry.faqAnswer || 'Unknown'; - try { - await faqEntry.deleteOne(); - } catch (error) { - Logger.error(error); - await interaction.reply({ - content: 'Could not remove FAQ, error has been logged, please notify the bot team.', - ephemeral: true, - }); - return; - } + try { + await faqEntry.deleteOne(); + } catch (error) { + Logger.error(error); + await interaction.reply({ + content: 'Could not remove FAQ, error has been logged, please notify the bot team.', + ephemeral: true, + }); + return; + } - try { - await modLogsChannel.send({ embeds: [faqRemovedEmbed(discordUser, faqTitle, faqAnswer)] }); - } catch (error) { - Logger.error(error); - await interaction.reply({ - content: - 'FAQ removed successfully, but could not send mod log, error has been logged, please notify the bot team.', - ephemeral: true, - }); - return; - } + try { + await modLogsChannel.send({ embeds: [faqRemovedEmbed(discordUser, faqTitle, faqAnswer)] }); + } catch (error) { + Logger.error(error); + await interaction.reply({ + content: + 'FAQ removed successfully, but could not send mod log, error has been logged, please notify the bot team.', + ephemeral: true, + }); + return; + } - await interaction.reply({ content: 'FAQ removed successfully.', ephemeral: true }); + await interaction.reply({ content: 'FAQ removed successfully.', ephemeral: true }); } diff --git a/src/commands/moderation/infractions/functions/ban.ts b/src/commands/moderation/infractions/functions/ban.ts index 40c2eed6..ffa4bbb3 100644 --- a/src/commands/moderation/infractions/functions/ban.ts +++ b/src/commands/moderation/infractions/functions/ban.ts @@ -4,199 +4,199 @@ import mongoose from 'mongoose'; import { constantsConfig, getConn, Infraction, Logger, makeEmbed } from '../../../../lib'; const noConnEmbed = makeEmbed({ - title: 'Ban - No Connection', - description: 'Could not connect to the database. I will still try to ban the user.', - color: Colors.Red, + title: 'Ban - No Connection', + description: 'Could not connect to the database. I will still try to ban the user.', + color: Colors.Red, }); const moderatableFailEmbed = makeEmbed({ - color: Colors.Red, - description: "You can't ban a moderator!", + color: Colors.Red, + description: "You can't ban a moderator!", }); const failedBanEmbed = (discordUser: User) => - makeEmbed({ - title: 'Ban - Failed', - description: `Failed to Ban ${discordUser.toString()}`, - color: Colors.Red, - }); + makeEmbed({ + title: 'Ban - Failed', + description: `Failed to Ban ${discordUser.toString()}`, + color: Colors.Red, + }); const DMEmbed = (moderator: User, banReason: string, guild: Guild) => - makeEmbed({ - title: `You have been banned from ${guild.name}`, - description: 'This ban is also logged against your record.', - fields: [ - { - inline: true, - name: 'Moderator', - value: moderator.toString(), - }, - { - inline: false, - name: 'Reason', - value: banReason, - }, - { - inline: false, - name: 'Appeal', - value: `If you would like to appeal your ban, please fill out [this form.](${process.env.BAN_APPEAL_URL})`, - }, - ], - }); + makeEmbed({ + title: `You have been banned from ${guild.name}`, + description: 'This ban is also logged against your record.', + fields: [ + { + inline: true, + name: 'Moderator', + value: moderator.toString(), + }, + { + inline: false, + name: 'Reason', + value: banReason, + }, + { + inline: false, + name: 'Appeal', + value: `If you would like to appeal your ban, please fill out [this form.](${process.env.BAN_APPEAL_URL})`, + }, + ], + }); const banEmbed = (discordUser: User) => - makeEmbed({ - title: `${discordUser.tag} was banned successfully`, - color: Colors.Green, - }); + makeEmbed({ + title: `${discordUser.tag} was banned successfully`, + color: Colors.Green, + }); const DMFailed = (discordUser: User) => - makeEmbed({ - title: 'Ban - DM not sent', - description: `DM was not sent to ${discordUser.toString()}, they either have DMs closed or share no mutual servers with the bot.`, - color: Colors.Red, - }); + makeEmbed({ + title: 'Ban - DM not sent', + description: `DM was not sent to ${discordUser.toString()}, they either have DMs closed or share no mutual servers with the bot.`, + color: Colors.Red, + }); const modLogEmbed = ( - moderator: User, - discordUser: User, - banReason: string, - daysDeletedNumber: number, - formattedDate: string, + moderator: User, + discordUser: User, + banReason: string, + daysDeletedNumber: number, + formattedDate: string, ) => - makeEmbed({ - author: { - name: `[BANNED] ${discordUser.tag}`, - iconURL: discordUser.displayAvatarURL(), - }, - fields: [ - { - name: 'User', - value: discordUser.toString(), - }, - { - name: 'Moderator', - value: `${moderator}`, - }, - { - name: 'Reason', - value: `\u200B${banReason}`, - }, - { - name: 'Days of messages deleted', - value: daysDeletedNumber.toString(), - }, - { - name: 'Date', - value: formattedDate, - }, - ], - footer: { text: `User ID: ${discordUser.id}` }, - color: Colors.Red, - }); + makeEmbed({ + author: { + name: `[BANNED] ${discordUser.tag}`, + iconURL: discordUser.displayAvatarURL(), + }, + fields: [ + { + name: 'User', + value: discordUser.toString(), + }, + { + name: 'Moderator', + value: `${moderator}`, + }, + { + name: 'Reason', + value: `\u200B${banReason}`, + }, + { + name: 'Days of messages deleted', + value: daysDeletedNumber.toString(), + }, + { + name: 'Date', + value: formattedDate, + }, + ], + footer: { text: `User ID: ${discordUser.id}` }, + color: Colors.Red, + }); const noModLogs = makeEmbed({ - title: 'Ban - No Mod Log', - description: - "I can't find the mod logs channel. I will still try to ban the user. Please check the channel still exists.", - color: Colors.Red, + title: 'Ban - No Mod Log', + description: + "I can't find the mod logs channel. I will still try to ban the user. Please check the channel still exists.", + color: Colors.Red, }); const logFailed = makeEmbed({ - title: 'Ban - Failed to log', - description: 'Failed to log the ban to the database.', - color: Colors.Red, + title: 'Ban - Failed to log', + description: 'Failed to log the ban to the database.', + color: Colors.Red, }); export async function handleBanInfraction(interaction: ChatInputCommandInteraction<'cached'>) { - await interaction.deferReply({ ephemeral: true }); + await interaction.deferReply({ ephemeral: true }); - const conn = getConn(); + const conn = getConn(); - if (!conn) { - await interaction.followUp({ embeds: [noConnEmbed], ephemeral: true }); - } + if (!conn) { + await interaction.followUp({ embeds: [noConnEmbed], ephemeral: true }); + } - const userID = interaction.options.getUser('tag_or_id')!.id; - const banReason = interaction.options.getString('reason')!; - const daysDeletedNumber = interaction.options.getInteger('days_deleted') || 0; + const userID = interaction.options.getUser('tag_or_id')!.id; + const banReason = interaction.options.getString('reason')!; + const daysDeletedNumber = interaction.options.getInteger('days_deleted') || 0; - const discordUser = await interaction.guild.members.fetch(userID); - const moderator = interaction.user; - const currentDate = new Date(); - const formattedDate: string = moment(currentDate).utcOffset(0).format(); - const modLogsChannel = interaction.guild.channels.resolve(constantsConfig.channels.MOD_LOGS) as TextChannel; + const discordUser = await interaction.guild.members.fetch(userID); + const moderator = interaction.user; + const currentDate = new Date(); + const formattedDate: string = moment(currentDate).utcOffset(0).format(); + const modLogsChannel = interaction.guild.channels.resolve(constantsConfig.channels.MOD_LOGS) as TextChannel; - //Check if the user is a moderator + //Check if the user is a moderator - if (!discordUser.moderatable) { - await interaction.followUp({ embeds: [moderatableFailEmbed], ephemeral: true }); - return; - } - - //Check if the mod logs channel exists + if (!discordUser.moderatable) { + await interaction.followUp({ embeds: [moderatableFailEmbed], ephemeral: true }); + return; + } - if (!modLogsChannel) { - await interaction.followUp({ embeds: [noModLogs], ephemeral: true }); - } + //Check if the mod logs channel exists - //DM the user + if (!modLogsChannel) { + await interaction.followUp({ embeds: [noModLogs], ephemeral: true }); + } - try { - await discordUser.send({ embeds: [DMEmbed(moderator, banReason, interaction.guild)] }); - } catch { - if (modLogsChannel) { - await interaction.followUp({ embeds: [DMFailed(discordUser.user)], ephemeral: true }); - } - } + //DM the user - //Ban the user - - try { - await interaction.guild.members.ban(discordUser, { deleteMessageDays: daysDeletedNumber, reason: banReason }); - if (modLogsChannel) { - await modLogsChannel.send({ - embeds: [modLogEmbed(moderator, discordUser.user, banReason, daysDeletedNumber, formattedDate)], - }); - } - await interaction.followUp({ embeds: [banEmbed(discordUser.user)], ephemeral: true }); - } catch (error) { - Logger.error(error); - await interaction.followUp({ embeds: [failedBanEmbed(discordUser.user)], ephemeral: true }); + try { + await discordUser.send({ embeds: [DMEmbed(moderator, banReason, interaction.guild)] }); + } catch { + if (modLogsChannel) { + await interaction.followUp({ embeds: [DMFailed(discordUser.user)], ephemeral: true }); } + } - //Log to the DB - Logger.info('Starting Infraction process'); - - const newInfraction = { - infractionType: 'Ban', - moderatorID: moderator.id, - reason: banReason, - date: currentDate, - infractionID: new mongoose.Types.ObjectId(), - }; - - let userData = await Infraction.findOne({ userID }); + //Ban the user - Logger.info(userData); - - if (!userData) { - userData = new Infraction({ - userID, - infractions: [newInfraction], - }); - Logger.info(userData); - Logger.info('New user data created'); - } else { - userData.infractions.push(newInfraction); - Logger.info('User data updated'); - } - - try { - await userData.save(); - Logger.info('Infraction process complete'); - } catch (error) { - await interaction.followUp({ embeds: [logFailed], ephemeral: true }); - Logger.error(error); + try { + await interaction.guild.members.ban(discordUser, { deleteMessageDays: daysDeletedNumber, reason: banReason }); + if (modLogsChannel) { + await modLogsChannel.send({ + embeds: [modLogEmbed(moderator, discordUser.user, banReason, daysDeletedNumber, formattedDate)], + }); } + await interaction.followUp({ embeds: [banEmbed(discordUser.user)], ephemeral: true }); + } catch (error) { + Logger.error(error); + await interaction.followUp({ embeds: [failedBanEmbed(discordUser.user)], ephemeral: true }); + } + + //Log to the DB + Logger.info('Starting Infraction process'); + + const newInfraction = { + infractionType: 'Ban', + moderatorID: moderator.id, + reason: banReason, + date: currentDate, + infractionID: new mongoose.Types.ObjectId(), + }; + + let userData = await Infraction.findOne({ userID }); + + Logger.info(userData); + + if (!userData) { + userData = new Infraction({ + userID, + infractions: [newInfraction], + }); + Logger.info(userData); + Logger.info('New user data created'); + } else { + userData.infractions.push(newInfraction); + Logger.info('User data updated'); + } + + try { + await userData.save(); + Logger.info('Infraction process complete'); + } catch (error) { + await interaction.followUp({ embeds: [logFailed], ephemeral: true }); + Logger.error(error); + } } diff --git a/src/commands/moderation/infractions/functions/deleteInfractions.ts b/src/commands/moderation/infractions/functions/deleteInfractions.ts index 388d237b..90896b6c 100644 --- a/src/commands/moderation/infractions/functions/deleteInfractions.ts +++ b/src/commands/moderation/infractions/functions/deleteInfractions.ts @@ -2,116 +2,116 @@ import { ChatInputCommandInteraction, Colors, TextChannel, User } from 'discord. import { constantsConfig, getConn, Infraction, Logger, makeEmbed } from '../../../../lib'; const noConnEmbed = makeEmbed({ - title: 'Delete - No Connection', - description: 'Could not connect to the database', - color: Colors.Red, + title: 'Delete - No Connection', + description: 'Could not connect to the database', + color: Colors.Red, }); const noInfractionEmbed = makeEmbed({ - title: 'Delete - Infraction not found', - description: 'This user has no infractions, please check the user ID and try again.', - color: Colors.Red, + title: 'Delete - Infraction not found', + description: 'This user has no infractions, please check the user ID and try again.', + color: Colors.Red, }); const successEmbed = makeEmbed({ - title: 'Delete - Success', - description: 'Infraction deleted successfully', - color: Colors.Green, + title: 'Delete - Success', + description: 'Infraction deleted successfully', + color: Colors.Green, }); const noSpecificInfractionEmbed = makeEmbed({ - title: 'Delete - Infraction not found', - description: 'This user has no infractions with that ID, please check the Infraction ID and try again.', - color: Colors.Red, + title: 'Delete - Infraction not found', + description: 'This user has no infractions with that ID, please check the Infraction ID and try again.', + color: Colors.Red, }); const errorEmbed = makeEmbed({ - title: 'Delete - Error', - description: 'An error occurred while deleting the infraction, the error has been logged.', - color: Colors.Red, + title: 'Delete - Error', + description: 'An error occurred while deleting the infraction, the error has been logged.', + color: Colors.Red, }); const modLogEmbed = (moderator: string, discordUser: User, infractionType: string, infractionReason: string) => - makeEmbed({ - author: { - name: `[INFRACTION DELETE] ${discordUser.tag}`, - iconURL: discordUser.displayAvatarURL(), - }, - fields: [ - { - inline: false, - name: 'Deleted by:', - value: moderator, - }, - { - inline: false, - name: 'Infraction user:', - value: discordUser.toString(), - }, - { - inline: false, - name: 'Infraction type:', - value: infractionType, - }, - { - inline: false, - name: 'Reason', - value: infractionReason, - }, - ], - color: Colors.Green, - }); + makeEmbed({ + author: { + name: `[INFRACTION DELETE] ${discordUser.tag}`, + iconURL: discordUser.displayAvatarURL(), + }, + fields: [ + { + inline: false, + name: 'Deleted by:', + value: moderator, + }, + { + inline: false, + name: 'Infraction user:', + value: discordUser.toString(), + }, + { + inline: false, + name: 'Infraction type:', + value: infractionType, + }, + { + inline: false, + name: 'Reason', + value: infractionReason, + }, + ], + color: Colors.Green, + }); export async function handleDeleteInfraction(interaction: ChatInputCommandInteraction<'cached'>) { - const conn = getConn(); + const conn = getConn(); - if (!conn) { - await interaction.reply({ embeds: [noConnEmbed], ephemeral: true }); - return; - } + if (!conn) { + await interaction.reply({ embeds: [noConnEmbed], ephemeral: true }); + return; + } - const userID = interaction.options.getUser('tag_or_id')!.id; + const userID = interaction.options.getUser('tag_or_id')!.id; - const discordUser = await interaction.client.users.fetch(userID); + const discordUser = await interaction.client.users.fetch(userID); - const infractionID = interaction.options.getString('infraction_id'); + const infractionID = interaction.options.getString('infraction_id'); - try { - const infraction = await Infraction.findOne({ userID }); + try { + const infraction = await Infraction.findOne({ userID }); - if (!infraction) { - await interaction.reply({ embeds: [noInfractionEmbed], ephemeral: true }); - return; - } + if (!infraction) { + await interaction.reply({ embeds: [noInfractionEmbed], ephemeral: true }); + return; + } - const existingInfractionIndex = infraction.infractions.findIndex( - (item) => String(item.infractionID) === infractionID, - ); + const existingInfractionIndex = infraction.infractions.findIndex( + (item) => String(item.infractionID) === infractionID, + ); - if (existingInfractionIndex === -1) { - await interaction.reply({ embeds: [noSpecificInfractionEmbed], ephemeral: true }); - return; - } + if (existingInfractionIndex === -1) { + await interaction.reply({ embeds: [noSpecificInfractionEmbed], ephemeral: true }); + return; + } - const infractionType = infraction.infractions[existingInfractionIndex].infractionType || 'Unknown'; + const infractionType = infraction.infractions[existingInfractionIndex].infractionType || 'Unknown'; - const infractionReason = infraction.infractions[existingInfractionIndex].reason || 'Unknown'; + const infractionReason = infraction.infractions[existingInfractionIndex].reason || 'Unknown'; - infraction.infractions.splice(existingInfractionIndex, 1); + infraction.infractions.splice(existingInfractionIndex, 1); - await infraction.save(); + await infraction.save(); - await interaction.reply({ embeds: [successEmbed], ephemeral: true }); + await interaction.reply({ embeds: [successEmbed], ephemeral: true }); - const modLogsChannel = interaction.guild.channels.resolve(constantsConfig.channels.MOD_LOGS) as TextChannel; + const modLogsChannel = interaction.guild.channels.resolve(constantsConfig.channels.MOD_LOGS) as TextChannel; - if (modLogsChannel) { - await modLogsChannel.send({ - embeds: [modLogEmbed(interaction.user.toString(), discordUser, infractionType, infractionReason)], - }); - } - } catch (error) { - await interaction.reply({ embeds: [errorEmbed], ephemeral: true }); - Logger.error(error); + if (modLogsChannel) { + await modLogsChannel.send({ + embeds: [modLogEmbed(interaction.user.toString(), discordUser, infractionType, infractionReason)], + }); } + } catch (error) { + await interaction.reply({ embeds: [errorEmbed], ephemeral: true }); + Logger.error(error); + } } diff --git a/src/commands/moderation/infractions/functions/listInfractions.ts b/src/commands/moderation/infractions/functions/listInfractions.ts index 37d6b784..8ddb46ed 100644 --- a/src/commands/moderation/infractions/functions/listInfractions.ts +++ b/src/commands/moderation/infractions/functions/listInfractions.ts @@ -3,365 +3,365 @@ import moment from 'moment'; import { getConn, Infraction, makeEmbed, createPaginatedInfractionEmbedHandler } from '../../../../lib'; const noConnEmbed = makeEmbed({ - title: 'List - No Connection', - description: 'Could not connect to the database', - color: Colors.Red, + title: 'List - No Connection', + description: 'Could not connect to the database', + color: Colors.Red, }); export async function handleListInfraction( - interaction: CommandInteraction, - userID: string | undefined, - ephemeral = false, + interaction: CommandInteraction, + userID: string | undefined, + ephemeral = false, ) { - const conn = getConn(); + const conn = getConn(); - if (!conn) { - await interaction.reply({ embeds: [noConnEmbed], ephemeral }); - return; + if (!conn) { + await interaction.reply({ embeds: [noConnEmbed], ephemeral }); + return; + } + + if (!userID) { + await interaction.reply({ content: 'Please provide a user tag or ID.', ephemeral }); + return; + } + + const id = userID; + + try { + const discordUser = await interaction.client.users.fetch(id); + + const avatarURL = discordUser.displayAvatarURL(); + + const user = await Infraction.findOne({ userID: id }); + if (!user) { + const infractionsNotFound = makeEmbed({ + color: Colors.Red, + author: { + name: `${discordUser.tag}'s Infractions not found`, + iconURL: avatarURL || undefined, + }, + description: 'This user has no infractions stored in the database', + footer: { text: `UserID: ${discordUser.id}` }, + }); + + await interaction.reply({ embeds: [infractionsNotFound], ephemeral }); + + return; } - if (!userID) { - await interaction.reply({ content: 'Please provide a user tag or ID.', ephemeral }); - return; + //Grab infractions from DB and make embeds + + const warnInfractions = user.infractions.filter((infraction) => infraction.infractionType === 'Warn'); + const timeoutInfractions = user.infractions.filter((infraction) => infraction.infractionType === 'Timeout'); + const scamLogInfractions = user.infractions.filter((infraction) => infraction.infractionType === 'ScamLog'); + const banInfractions = user.infractions.filter((infraction) => infraction.infractionType === 'Ban'); + const unbanInfractions = user.infractions.filter((infraction) => infraction.infractionType === 'Unban'); + const userNotes = user.infractions.filter((infraction) => infraction.infractionType === 'Note'); + + const infractionsLengths = { + warnsLength: warnInfractions.length.toString(), + timeoutsLength: timeoutInfractions.length.toString(), + scamLogsLength: scamLogInfractions.length.toString(), + bansLength: banInfractions.length.toString(), + unbansLength: unbanInfractions.length.toString(), + notesLength: userNotes.length.toString(), + }; + + type InfractionArray = + | typeof warnInfractions + | typeof timeoutInfractions + | typeof scamLogInfractions + | typeof banInfractions + | typeof unbanInfractions + | typeof userNotes; + + const fetchModerators = (infractions: InfractionArray) => { + const moderatorPromises = infractions.map((infraction) => + interaction.client.users + .fetch(infraction.moderatorID!) + // Disabled for readability + // eslint-disable-next-line arrow-body-style + .catch(() => { + return new Promise((resolve) => { + resolve(`I can't find the moderator, here is the stored ID: ${infraction.moderatorID}`); + }); + }), + ); + + return Promise.all(moderatorPromises); + }; + + // Warns + const warnFields: { name: string; value: string }[] = []; + const warnModeratorUsers = await fetchModerators(warnInfractions); + + for (let i = 0; i < warnInfractions.length; i++) { + const formattedDate: string = moment(warnInfractions[i].date).utcOffset(0).format(); + + warnFields.push( + { + name: `Warn #${i + 1}`, + value: + `**Type:** ${warnInfractions[i].infractionType}\n` + + `**Moderator:** ${warnModeratorUsers[i]}\n` + + `**Reason:** ${warnInfractions[i].reason}\n` + + `**Date:** ${formattedDate}\n` + + `**Infraction ID:** ${warnInfractions[i].infractionID}`, + }, + { + name: '', + value: '----------------------------------------', + }, + ); } - const id = userID; + const warnsEmbed = makeEmbed({ + author: { + name: `${discordUser.tag}'s Warns`, + iconURL: avatarURL || undefined, + }, + description: warnFields.length > 0 ? '' : 'This user has no warns logged', + fields: warnFields.flat(), + footer: { text: `UserID: ${user.userID}` }, + }); + + //Timeouts + const timeoutFields: { name: string; value: string }[] = []; + const timeoutModeratorUsers = await fetchModerators(timeoutInfractions); + + for (let i = 0; i < timeoutInfractions.length; i++) { + const formattedDate: string = moment(timeoutInfractions[i].date).utcOffset(0).format(); + + timeoutFields.push( + { + name: `Timeout #${i + 1}`, + value: + `**Type:** ${timeoutInfractions[i].infractionType}\n` + + `**Moderator:** ${timeoutModeratorUsers[i]}\n` + + `**Reason:** ${timeoutInfractions[i].reason}\n` + + `**Duration:** ${timeoutInfractions[i].duration !== undefined ? timeoutInfractions[i].duration : 'No duration specified, this user was timed out before the bot upgrade!'}\n` + + `**Date:** ${formattedDate}\n` + + `**Infraction ID:** ${timeoutInfractions[i].infractionID}`, + }, + { + name: '', + value: '----------------------------------------', + }, + ); + } - try { - const discordUser = await interaction.client.users.fetch(id); + const timeoutsEmbed = makeEmbed({ + author: { + name: `${discordUser.tag}'s Timeouts`, + iconURL: avatarURL || undefined, + }, + description: timeoutFields.length > 0 ? '' : 'This user has no timeouts logged', + fields: timeoutFields.flat(), + footer: { text: `UserID: ${user.userID}` }, + }); + + //ScamLogs + const scamLogFields: { name: string; value: string }[] = []; + const scamLogModerators = await fetchModerators(scamLogInfractions); + + for (let i = 0; i < scamLogInfractions.length; i++) { + const formattedDate: string = moment(scamLogInfractions[i].date).utcOffset(0).format(); + + scamLogFields.push( + { + name: `Scam Log #${i + 1}`, + value: + `**Type:** ${scamLogInfractions[i].infractionType}\n` + + `**Moderator:** ${scamLogModerators[i]}\n` + + `**Message Content:** ${scamLogInfractions[i].reason}\n` + + `**Date:** ${formattedDate}\n` + + `**Infraction ID:** ${scamLogInfractions[i].infractionID}`, + }, + { + name: '', + value: '----------------------------------------', + }, + ); + } - const avatarURL = discordUser.displayAvatarURL(); + const scamLogEmbed = makeEmbed({ + author: { + name: `${discordUser.tag}'s Scam Log Entries`, + iconURL: avatarURL || undefined, + }, + description: scamLogFields.length > 0 ? '' : 'This user has no scam log entries logged', + fields: scamLogFields.flat(), + footer: { text: `UserID: ${user.userID}` }, + }); + + //Bans + const banFields: { name: string; value: string }[] = []; + const banModerators = await fetchModerators(banInfractions); + + for (let i = 0; i < banInfractions.length; i++) { + const formattedDate: string = moment(banInfractions[i].date).utcOffset(0).format(); + + banFields.push( + { + name: `Ban #${i + 1}`, + value: + `**Type:** ${banInfractions[i].infractionType}\n` + + `**Moderator:** ${banModerators[i]}\n` + + `**Reason:** ${banInfractions[i].reason}\n` + + `**Date:** ${formattedDate}\n` + + `**Infraction ID:** ${banInfractions[i].infractionID}`, + }, + { + name: '', + value: '----------------------------------------', + }, + ); + } - const user = await Infraction.findOne({ userID: id }); - if (!user) { - const infractionsNotFound = makeEmbed({ - color: Colors.Red, - author: { - name: `${discordUser.tag}'s Infractions not found`, - iconURL: avatarURL || undefined, - }, - description: 'This user has no infractions stored in the database', - footer: { text: `UserID: ${discordUser.id}` }, - }); + const banEmbed = makeEmbed({ + author: { + name: `${discordUser.tag}'s Bans`, + iconURL: avatarURL || undefined, + }, + description: banFields.length > 0 ? '' : 'This user has no bans logged', + fields: banFields.flat(), + footer: { text: `UserID: ${user.userID}` }, + }); + + //Unbans + const unbanFields: { name: string; value: string }[] = []; + const unbanModerators = await fetchModerators(unbanInfractions); + for (let i = 0; i < unbanInfractions.length; i++) { + const formattedDate: string = moment(unbanInfractions[i].date).utcOffset(0).format(); + + unbanFields.push( + { + name: `Unban #${i + 1}`, + value: + `**Type:** ${unbanInfractions[i].infractionType}\n` + + `**Moderator:** ${unbanModerators[i]}\n` + + `**Reason:** ${unbanInfractions[i].reason}\n` + + `**Date:** ${formattedDate}\n` + + `**Infraction ID:** ${unbanInfractions[i].infractionID}`, + }, + { + name: '', + value: '----------------------------------------', + }, + ); + } - await interaction.reply({ embeds: [infractionsNotFound], ephemeral }); - - return; - } - - //Grab infractions from DB and make embeds - - const warnInfractions = user.infractions.filter((infraction) => infraction.infractionType === 'Warn'); - const timeoutInfractions = user.infractions.filter((infraction) => infraction.infractionType === 'Timeout'); - const scamLogInfractions = user.infractions.filter((infraction) => infraction.infractionType === 'ScamLog'); - const banInfractions = user.infractions.filter((infraction) => infraction.infractionType === 'Ban'); - const unbanInfractions = user.infractions.filter((infraction) => infraction.infractionType === 'Unban'); - const userNotes = user.infractions.filter((infraction) => infraction.infractionType === 'Note'); - - const infractionsLengths = { - warnsLength: warnInfractions.length.toString(), - timeoutsLength: timeoutInfractions.length.toString(), - scamLogsLength: scamLogInfractions.length.toString(), - bansLength: banInfractions.length.toString(), - unbansLength: unbanInfractions.length.toString(), - notesLength: userNotes.length.toString(), - }; - - type InfractionArray = - | typeof warnInfractions - | typeof timeoutInfractions - | typeof scamLogInfractions - | typeof banInfractions - | typeof unbanInfractions - | typeof userNotes; - - const fetchModerators = (infractions: InfractionArray) => { - const moderatorPromises = infractions.map((infraction) => - interaction.client.users - .fetch(infraction.moderatorID!) - // Disabled for readability - // eslint-disable-next-line arrow-body-style - .catch(() => { - return new Promise((resolve) => { - resolve(`I can't find the moderator, here is the stored ID: ${infraction.moderatorID}`); - }); - }), - ); - - return Promise.all(moderatorPromises); - }; - - // Warns - const warnFields: { name: string; value: string }[] = []; - const warnModeratorUsers = await fetchModerators(warnInfractions); - - for (let i = 0; i < warnInfractions.length; i++) { - const formattedDate: string = moment(warnInfractions[i].date).utcOffset(0).format(); - - warnFields.push( - { - name: `Warn #${i + 1}`, - value: - `**Type:** ${warnInfractions[i].infractionType}\n` + - `**Moderator:** ${warnModeratorUsers[i]}\n` + - `**Reason:** ${warnInfractions[i].reason}\n` + - `**Date:** ${formattedDate}\n` + - `**Infraction ID:** ${warnInfractions[i].infractionID}`, - }, - { - name: '', - value: '----------------------------------------', - }, - ); - } - - const warnsEmbed = makeEmbed({ - author: { - name: `${discordUser.tag}'s Warns`, - iconURL: avatarURL || undefined, - }, - description: warnFields.length > 0 ? '' : 'This user has no warns logged', - fields: warnFields.flat(), - footer: { text: `UserID: ${user.userID}` }, - }); - - //Timeouts - const timeoutFields: { name: string; value: string }[] = []; - const timeoutModeratorUsers = await fetchModerators(timeoutInfractions); - - for (let i = 0; i < timeoutInfractions.length; i++) { - const formattedDate: string = moment(timeoutInfractions[i].date).utcOffset(0).format(); - - timeoutFields.push( - { - name: `Timeout #${i + 1}`, - value: - `**Type:** ${timeoutInfractions[i].infractionType}\n` + - `**Moderator:** ${timeoutModeratorUsers[i]}\n` + - `**Reason:** ${timeoutInfractions[i].reason}\n` + - `**Duration:** ${timeoutInfractions[i].duration !== undefined ? timeoutInfractions[i].duration : 'No duration specified, this user was timed out before the bot upgrade!'}\n` + - `**Date:** ${formattedDate}\n` + - `**Infraction ID:** ${timeoutInfractions[i].infractionID}`, - }, - { - name: '', - value: '----------------------------------------', - }, - ); - } - - const timeoutsEmbed = makeEmbed({ - author: { - name: `${discordUser.tag}'s Timeouts`, - iconURL: avatarURL || undefined, - }, - description: timeoutFields.length > 0 ? '' : 'This user has no timeouts logged', - fields: timeoutFields.flat(), - footer: { text: `UserID: ${user.userID}` }, - }); - - //ScamLogs - const scamLogFields: { name: string; value: string }[] = []; - const scamLogModerators = await fetchModerators(scamLogInfractions); - - for (let i = 0; i < scamLogInfractions.length; i++) { - const formattedDate: string = moment(scamLogInfractions[i].date).utcOffset(0).format(); - - scamLogFields.push( - { - name: `Scam Log #${i + 1}`, - value: - `**Type:** ${scamLogInfractions[i].infractionType}\n` + - `**Moderator:** ${scamLogModerators[i]}\n` + - `**Message Content:** ${scamLogInfractions[i].reason}\n` + - `**Date:** ${formattedDate}\n` + - `**Infraction ID:** ${scamLogInfractions[i].infractionID}`, - }, - { - name: '', - value: '----------------------------------------', - }, - ); - } - - const scamLogEmbed = makeEmbed({ - author: { - name: `${discordUser.tag}'s Scam Log Entries`, - iconURL: avatarURL || undefined, - }, - description: scamLogFields.length > 0 ? '' : 'This user has no scam log entries logged', - fields: scamLogFields.flat(), - footer: { text: `UserID: ${user.userID}` }, - }); - - //Bans - const banFields: { name: string; value: string }[] = []; - const banModerators = await fetchModerators(banInfractions); - - for (let i = 0; i < banInfractions.length; i++) { - const formattedDate: string = moment(banInfractions[i].date).utcOffset(0).format(); - - banFields.push( - { - name: `Ban #${i + 1}`, - value: - `**Type:** ${banInfractions[i].infractionType}\n` + - `**Moderator:** ${banModerators[i]}\n` + - `**Reason:** ${banInfractions[i].reason}\n` + - `**Date:** ${formattedDate}\n` + - `**Infraction ID:** ${banInfractions[i].infractionID}`, - }, - { - name: '', - value: '----------------------------------------', - }, - ); - } - - const banEmbed = makeEmbed({ - author: { - name: `${discordUser.tag}'s Bans`, - iconURL: avatarURL || undefined, - }, - description: banFields.length > 0 ? '' : 'This user has no bans logged', - fields: banFields.flat(), - footer: { text: `UserID: ${user.userID}` }, - }); - - //Unbans - const unbanFields: { name: string; value: string }[] = []; - const unbanModerators = await fetchModerators(unbanInfractions); - for (let i = 0; i < unbanInfractions.length; i++) { - const formattedDate: string = moment(unbanInfractions[i].date).utcOffset(0).format(); - - unbanFields.push( - { - name: `Unban #${i + 1}`, - value: - `**Type:** ${unbanInfractions[i].infractionType}\n` + - `**Moderator:** ${unbanModerators[i]}\n` + - `**Reason:** ${unbanInfractions[i].reason}\n` + - `**Date:** ${formattedDate}\n` + - `**Infraction ID:** ${unbanInfractions[i].infractionID}`, - }, - { - name: '', - value: '----------------------------------------', - }, - ); - } - - const unbanEmbed = makeEmbed({ - author: { - name: `${discordUser.tag}'s Unbans`, - iconURL: avatarURL || undefined, - }, - description: unbanFields.length > 0 ? '' : 'This user has no unbans logged', - fields: unbanFields.flat(), - footer: { text: `UserID: ${user.userID}` }, - }); - - //Notes - const noteFields: { name: string; value: string }[] = []; - const userNodeModerators = await fetchModerators(userNotes); - - for (let i = 0; i < userNotes.length; i++) { - const formattedDate: string = moment(userNotes[i].date).utcOffset(0).format(); - - noteFields.push( - { - name: `Note #${i + 1}`, - value: - `**Type:** ${userNotes[i].infractionType}\n` + - `**Moderator:** ${userNodeModerators[i]}\n` + - `**Note:** ${userNotes[i].reason}\n` + - `**Date:** ${formattedDate}\n` + - `**Infraction ID:** ${userNotes[i].infractionID}`, - }, - { - name: '', - value: '----------------------------------------', - }, - ); - } - - const userNoteEmbed = makeEmbed({ - author: { - name: `${discordUser.tag}'s Notes`, - iconURL: avatarURL || undefined, - }, - description: noteFields.length > 0 ? '' : 'This user has no notes logged', - fields: noteFields.flat(), - footer: { text: `UserID: ${user.userID}` }, - }); - - //Make the about embed - const aboutEmbed = makeEmbed({ - author: { - name: `${discordUser.tag}'s Infractions`, - iconURL: avatarURL || undefined, - }, - description: "Click the buttons below to view the user's infractions in detail.", - fields: [ - { - name: 'UserID', - value: user.userID!, - inline: false, - }, - { - name: 'User Tag', - value: `<@${user.userID!}>`, - inline: false, - }, - { - name: 'Warns', - value: infractionsLengths.warnsLength, - inline: true, - }, - { - name: 'Timeouts', - value: infractionsLengths.timeoutsLength, - inline: true, - }, - { - name: 'Scam Log Entries', - value: infractionsLengths.scamLogsLength, - inline: true, - }, - { - name: 'Bans', - value: infractionsLengths.bansLength, - inline: true, - }, - { - name: 'Unbans', - value: infractionsLengths.unbansLength, - inline: true, - }, - { - name: 'Notes', - value: infractionsLengths.notesLength, - inline: true, - }, - ], - footer: { text: 'This embed will expire in two minutes from command execution.' }, - }); - - //Collect embeds and send with the paginator - const embeds = [aboutEmbed, warnsEmbed, timeoutsEmbed, scamLogEmbed, banEmbed, unbanEmbed, userNoteEmbed]; - await interaction.deferReply({ ephemeral }); - - await createPaginatedInfractionEmbedHandler(interaction, interaction.user.id, embeds, infractionsLengths); - } catch (error) { - //Error handling - User is no longer on discord (Or ID doesn't exist) - - const userNotFound = makeEmbed({ - color: Colors.Red, - title: 'User not found', - description: - 'An error occurred while fetching user information, please check the userID. If the ID is correct, this user may not exist on Discord anymore - If you need to view their infractions anyway one of the bot team can search the DB manually.', - }); - - await interaction.followUp({ embeds: [userNotFound], ephemeral }); + const unbanEmbed = makeEmbed({ + author: { + name: `${discordUser.tag}'s Unbans`, + iconURL: avatarURL || undefined, + }, + description: unbanFields.length > 0 ? '' : 'This user has no unbans logged', + fields: unbanFields.flat(), + footer: { text: `UserID: ${user.userID}` }, + }); + + //Notes + const noteFields: { name: string; value: string }[] = []; + const userNodeModerators = await fetchModerators(userNotes); + + for (let i = 0; i < userNotes.length; i++) { + const formattedDate: string = moment(userNotes[i].date).utcOffset(0).format(); + + noteFields.push( + { + name: `Note #${i + 1}`, + value: + `**Type:** ${userNotes[i].infractionType}\n` + + `**Moderator:** ${userNodeModerators[i]}\n` + + `**Note:** ${userNotes[i].reason}\n` + + `**Date:** ${formattedDate}\n` + + `**Infraction ID:** ${userNotes[i].infractionID}`, + }, + { + name: '', + value: '----------------------------------------', + }, + ); } + + const userNoteEmbed = makeEmbed({ + author: { + name: `${discordUser.tag}'s Notes`, + iconURL: avatarURL || undefined, + }, + description: noteFields.length > 0 ? '' : 'This user has no notes logged', + fields: noteFields.flat(), + footer: { text: `UserID: ${user.userID}` }, + }); + + //Make the about embed + const aboutEmbed = makeEmbed({ + author: { + name: `${discordUser.tag}'s Infractions`, + iconURL: avatarURL || undefined, + }, + description: "Click the buttons below to view the user's infractions in detail.", + fields: [ + { + name: 'UserID', + value: user.userID!, + inline: false, + }, + { + name: 'User Tag', + value: `<@${user.userID!}>`, + inline: false, + }, + { + name: 'Warns', + value: infractionsLengths.warnsLength, + inline: true, + }, + { + name: 'Timeouts', + value: infractionsLengths.timeoutsLength, + inline: true, + }, + { + name: 'Scam Log Entries', + value: infractionsLengths.scamLogsLength, + inline: true, + }, + { + name: 'Bans', + value: infractionsLengths.bansLength, + inline: true, + }, + { + name: 'Unbans', + value: infractionsLengths.unbansLength, + inline: true, + }, + { + name: 'Notes', + value: infractionsLengths.notesLength, + inline: true, + }, + ], + footer: { text: 'This embed will expire in two minutes from command execution.' }, + }); + + //Collect embeds and send with the paginator + const embeds = [aboutEmbed, warnsEmbed, timeoutsEmbed, scamLogEmbed, banEmbed, unbanEmbed, userNoteEmbed]; + await interaction.deferReply({ ephemeral }); + + await createPaginatedInfractionEmbedHandler(interaction, interaction.user.id, embeds, infractionsLengths); + } catch (error) { + //Error handling - User is no longer on discord (Or ID doesn't exist) + + const userNotFound = makeEmbed({ + color: Colors.Red, + title: 'User not found', + description: + 'An error occurred while fetching user information, please check the userID. If the ID is correct, this user may not exist on Discord anymore - If you need to view their infractions anyway one of the bot team can search the DB manually.', + }); + + await interaction.followUp({ embeds: [userNotFound], ephemeral }); + } } diff --git a/src/commands/moderation/infractions/functions/removeTimeout.ts b/src/commands/moderation/infractions/functions/removeTimeout.ts index 9c1e7c0f..61e93b00 100644 --- a/src/commands/moderation/infractions/functions/removeTimeout.ts +++ b/src/commands/moderation/infractions/functions/removeTimeout.ts @@ -3,88 +3,88 @@ import moment from 'moment'; import { constantsConfig, Logger, makeEmbed } from '../../../../lib'; const notTimedOutEmbed = (discordUser: User) => - makeEmbed({ - title: 'Remove Timeout - Failed', - description: `${discordUser.toString()} is not currently timed out.`, - color: Colors.Red, - }); + makeEmbed({ + title: 'Remove Timeout - Failed', + description: `${discordUser.toString()} is not currently timed out.`, + color: Colors.Red, + }); const failedRemoveTimeoutEmbed = (discordUser: User) => - makeEmbed({ - title: 'Remove Timeout - Failed', - description: `Failed to remove timeout for ${discordUser.toString()}`, - color: Colors.Red, - }); + makeEmbed({ + title: 'Remove Timeout - Failed', + description: `Failed to remove timeout for ${discordUser.toString()}`, + color: Colors.Red, + }); const modLogEmbed = (moderator: User, discordUser: User, date: string) => - makeEmbed({ - author: { - name: `[TIMEOUT REMOVED] ${discordUser.tag}`, - iconURL: discordUser.displayAvatarURL(), - }, - fields: [ - { - inline: true, - name: 'Moderator', - value: moderator.toString(), - }, - { - inline: true, - name: 'User', - value: discordUser.toString(), - }, - { - inline: false, - name: 'Date', - value: date, - }, - ], - footer: { text: `User ID: ${discordUser.id}` }, - color: Colors.Green, - }); + makeEmbed({ + author: { + name: `[TIMEOUT REMOVED] ${discordUser.tag}`, + iconURL: discordUser.displayAvatarURL(), + }, + fields: [ + { + inline: true, + name: 'Moderator', + value: moderator.toString(), + }, + { + inline: true, + name: 'User', + value: discordUser.toString(), + }, + { + inline: false, + name: 'Date', + value: date, + }, + ], + footer: { text: `User ID: ${discordUser.id}` }, + color: Colors.Green, + }); const timeoutRemovedEmbed = (discordUser: User) => - makeEmbed({ - title: `${discordUser.tag} was successfully removed from timeout`, - color: Colors.Green, - }); + makeEmbed({ + title: `${discordUser.tag} was successfully removed from timeout`, + color: Colors.Green, + }); const noModLogs = makeEmbed({ - title: 'Remove Timeout - No Mod Log', - description: 'The user was removed from timeout, but no mod log was sent. Please check the channel still exists', - color: Colors.Red, + title: 'Remove Timeout - No Mod Log', + description: 'The user was removed from timeout, but no mod log was sent. Please check the channel still exists', + color: Colors.Red, }); export async function handleRemoveTimeoutInfraction(interaction: ChatInputCommandInteraction<'cached'>) { - await interaction.deferReply({ ephemeral: true }); + await interaction.deferReply({ ephemeral: true }); - const userID = interaction.options.getUser('tag_or_id')!.id; - const discordUser = await interaction.guild.members.fetch(userID); - const moderator = interaction.user; - const modLogsChannel = interaction.guild.channels.resolve(constantsConfig.channels.MOD_LOGS) as TextChannel; - const currentDate = new Date(); - const formattedDate: string = moment(currentDate).utcOffset(0).format(); + const userID = interaction.options.getUser('tag_or_id')!.id; + const discordUser = await interaction.guild.members.fetch(userID); + const moderator = interaction.user; + const modLogsChannel = interaction.guild.channels.resolve(constantsConfig.channels.MOD_LOGS) as TextChannel; + const currentDate = new Date(); + const formattedDate: string = moment(currentDate).utcOffset(0).format(); - // Check if the user is currently timed out - if (!discordUser.isCommunicationDisabled()) { - await interaction.followUp({ embeds: [notTimedOutEmbed(discordUser.user)], ephemeral: true }); - return; - } + // Check if the user is currently timed out + if (!discordUser.isCommunicationDisabled()) { + await interaction.followUp({ embeds: [notTimedOutEmbed(discordUser.user)], ephemeral: true }); + return; + } - // Remove the timeout for the user - try { - await discordUser.timeout(1); // Set the duration to 0 to remove the timeout - } catch (error) { - Logger.error(error); - await interaction.followUp({ embeds: [failedRemoveTimeoutEmbed(discordUser.user)], ephemeral: true }); - return; - } + // Remove the timeout for the user + try { + await discordUser.timeout(1); // Set the duration to 0 to remove the timeout + } catch (error) { + Logger.error(error); + await interaction.followUp({ embeds: [failedRemoveTimeoutEmbed(discordUser.user)], ephemeral: true }); + return; + } - try { - await modLogsChannel.send({ embeds: [modLogEmbed(moderator, discordUser.user, formattedDate)] }); - } catch { - await interaction.followUp({ embeds: [noModLogs], ephemeral: true }); - } + try { + await modLogsChannel.send({ embeds: [modLogEmbed(moderator, discordUser.user, formattedDate)] }); + } catch { + await interaction.followUp({ embeds: [noModLogs], ephemeral: true }); + } - await interaction.followUp({ embeds: [timeoutRemovedEmbed(discordUser.user)], ephemeral: true }); + await interaction.followUp({ embeds: [timeoutRemovedEmbed(discordUser.user)], ephemeral: true }); } diff --git a/src/commands/moderation/infractions/functions/timeout.ts b/src/commands/moderation/infractions/functions/timeout.ts index 264647a0..0e7f35be 100644 --- a/src/commands/moderation/infractions/functions/timeout.ts +++ b/src/commands/moderation/infractions/functions/timeout.ts @@ -4,211 +4,209 @@ import mongoose from 'mongoose'; import { constantsConfig, durationInEnglish, getConn, Infraction, Logger, makeEmbed, makeLines } from '../../../../lib'; const noConnEmbed = makeEmbed({ - title: 'Timeout - No Connection', - description: 'Could not connect to the database. I will still try to timeout the user', - color: Colors.Red, + title: 'Timeout - No Connection', + description: 'Could not connect to the database. I will still try to timeout the user', + color: Colors.Red, }); const failedTimeoutEmbed = (discordUser: User, error: any) => - makeEmbed({ - title: 'Timeout - Failed', - description: makeLines([`Failed to timeout ${discordUser.toString()}`, '', error]), - color: Colors.Red, - }); + makeEmbed({ + title: 'Timeout - Failed', + description: makeLines([`Failed to timeout ${discordUser.toString()}`, '', error]), + color: Colors.Red, + }); const DMEmbed = (moderator: User, timeoutDuration: string, reason: string, guild: Guild, timedOutUntil: Date) => - makeEmbed({ - title: `You have been timed out in ${guild.name}`, - description: 'This timeout is also logged against your record.', - fields: [ - { - inline: true, - name: 'Duration', - value: durationInEnglish(timeoutDuration), - }, - { - inline: true, - name: 'Moderator', - value: moderator.toString(), - }, - { - inline: false, - name: 'Reason', - value: reason, - }, - ], - footer: { text: `Your timeout will be lifted on ${timedOutUntil.toUTCString()}` }, - }); + makeEmbed({ + title: `You have been timed out in ${guild.name}`, + description: 'This timeout is also logged against your record.', + fields: [ + { + inline: true, + name: 'Duration', + value: durationInEnglish(timeoutDuration), + }, + { + inline: true, + name: 'Moderator', + value: moderator.toString(), + }, + { + inline: false, + name: 'Reason', + value: reason, + }, + ], + footer: { text: `Your timeout will be lifted on ${timedOutUntil.toUTCString()}` }, + }); const timeoutEmbed = (discordUser: User) => - makeEmbed({ - title: `${discordUser.tag} was timed out successfully`, - color: Colors.Green, - }); + makeEmbed({ + title: `${discordUser.tag} was timed out successfully`, + color: Colors.Green, + }); const DMFailed = (discordUser: User) => - makeEmbed({ - title: 'Timeout - DM not sent', - description: `DM was not sent to ${discordUser.toString()}, they either have DMs closed or share no mutual servers with the bot.`, - color: Colors.Red, - }); + makeEmbed({ + title: 'Timeout - DM not sent', + description: `DM was not sent to ${discordUser.toString()}, they either have DMs closed or share no mutual servers with the bot.`, + color: Colors.Red, + }); const modLogEmbed = ( - moderator: User, - discordUser: User, - timeoutReason: string, - timeoutDuration: string, - formattedDate: string, + moderator: User, + discordUser: User, + timeoutReason: string, + timeoutDuration: string, + formattedDate: string, ) => - makeEmbed({ - author: { - name: `[TIMED OUT] ${discordUser.tag}`, - iconURL: discordUser.displayAvatarURL(), - }, - fields: [ - { - name: 'User', - value: discordUser.toString(), - }, - { - name: 'Moderator', - value: `${moderator}`, - }, - { - name: 'Reason', - value: `\u200B${timeoutReason}`, - }, - { - name: 'Duration', - value: durationInEnglish(timeoutDuration), - }, - { - name: 'Date', - value: formattedDate, - }, - ], - footer: { text: `User ID: ${discordUser.id}` }, - color: Colors.Red, - }); + makeEmbed({ + author: { + name: `[TIMED OUT] ${discordUser.tag}`, + iconURL: discordUser.displayAvatarURL(), + }, + fields: [ + { + name: 'User', + value: discordUser.toString(), + }, + { + name: 'Moderator', + value: `${moderator}`, + }, + { + name: 'Reason', + value: `\u200B${timeoutReason}`, + }, + { + name: 'Duration', + value: durationInEnglish(timeoutDuration), + }, + { + name: 'Date', + value: formattedDate, + }, + ], + footer: { text: `User ID: ${discordUser.id}` }, + color: Colors.Red, + }); const noModLogs = makeEmbed({ - title: 'Timeout - No Mod Log', - description: 'The user was timed out, but no mod log was sent. Please check the channel still exists', - color: Colors.Red, + title: 'Timeout - No Mod Log', + description: 'The user was timed out, but no mod log was sent. Please check the channel still exists', + color: Colors.Red, }); const logFailed = makeEmbed({ - title: 'Timeot - Failed to log', - description: 'Failed to log the timeout to the database.', - color: Colors.Red, + title: 'Timeot - Failed to log', + description: 'Failed to log the timeout to the database.', + color: Colors.Red, }); const communicationNotDisabledEmbed = (discordUser: User) => - makeEmbed({ - title: 'Timeout - Communication not disabled', - description: `Bot has not detected that ${discordUser.toString()} was successfully timed out. Timeout may have failed.`, - color: Colors.Red, - }); + makeEmbed({ + title: 'Timeout - Communication not disabled', + description: `Bot has not detected that ${discordUser.toString()} was successfully timed out. Timeout may have failed.`, + color: Colors.Red, + }); export async function handleTimeoutInfraction(interaction: ChatInputCommandInteraction<'cached'>) { - await interaction.deferReply({ ephemeral: true }); - - const conn = getConn(); - - if (!conn) { - await interaction.editReply({ embeds: [noConnEmbed] }); - return; + await interaction.deferReply({ ephemeral: true }); + + const conn = getConn(); + + if (!conn) { + await interaction.editReply({ embeds: [noConnEmbed] }); + return; + } + + const userID = interaction.options.getUser('tag_or_id')!.id; + const timeoutDuration = interaction.options.getNumber('duration')!; + const timeoutReason = interaction.options.getString('reason')!; + + const discordUser = await interaction.guild.members.fetch(userID); + const moderator = interaction.user; + const currentDate = new Date(); + const formattedDate: string = moment(currentDate).utcOffset(0).format(); + const modLogsChannel = interaction.guild.channels.resolve(constantsConfig.channels.MOD_LOGS) as TextChannel; + + //Try to timeout the user + + try { + await discordUser.timeout(timeoutDuration, timeoutReason); + } catch (error) { + await interaction.editReply({ embeds: [failedTimeoutEmbed(discordUser.user, error)] }); + Logger.error(error); + return; + } + + if (discordUser.isCommunicationDisabled()) { + //Timeout was successful + await interaction.editReply({ embeds: [timeoutEmbed(discordUser.user)] }); + //Try and send a Dm to the user + try { + await discordUser.send({ + embeds: [ + DMEmbed( + moderator, + timeoutDuration.toString(), + timeoutReason, + interaction.guild, + discordUser.communicationDisabledUntil, + ), + ], + }); + } catch { + if (modLogsChannel) { + await interaction.followUp({ embeds: [DMFailed(discordUser.user)], ephemeral: true }); + } } - - const userID = interaction.options.getUser('tag_or_id')!.id; - const timeoutDuration = interaction.options.getNumber('duration')!; - const timeoutReason = interaction.options.getString('reason')!; - - const discordUser = await interaction.guild.members.fetch(userID); - const moderator = interaction.user; - const currentDate = new Date(); - const formattedDate: string = moment(currentDate).utcOffset(0).format(); - const modLogsChannel = interaction.guild.channels.resolve(constantsConfig.channels.MOD_LOGS) as TextChannel; - - //Try to timeout the user - + //Send a mod log to the mod logs channel try { - await discordUser.timeout(timeoutDuration, timeoutReason); - } catch (error) { - await interaction.editReply({ embeds: [failedTimeoutEmbed(discordUser.user, error)] }); - Logger.error(error); - return; + await modLogsChannel.send({ + embeds: [modLogEmbed(moderator, discordUser.user, timeoutReason, timeoutDuration.toString(), formattedDate)], + }); + } catch { + await interaction.followUp({ embeds: [noModLogs], ephemeral: true }); + return; } - - if (discordUser.isCommunicationDisabled()) { - //Timeout was successful - await interaction.editReply({ embeds: [timeoutEmbed(discordUser.user)] }); - //Try and send a Dm to the user - try { - await discordUser.send({ - embeds: [ - DMEmbed( - moderator, - timeoutDuration.toString(), - timeoutReason, - interaction.guild, - discordUser.communicationDisabledUntil, - ), - ], - }); - } catch { - if (modLogsChannel) { - await interaction.followUp({ embeds: [DMFailed(discordUser.user)], ephemeral: true }); - } - } - //Send a mod log to the mod logs channel - try { - await modLogsChannel.send({ - embeds: [ - modLogEmbed(moderator, discordUser.user, timeoutReason, timeoutDuration.toString(), formattedDate), - ], - }); - } catch { - await interaction.followUp({ embeds: [noModLogs], ephemeral: true }); - return; - } - //Log to the DB - - Logger.info('Starting Infraction process'); - - const newInfraction = { - infractionType: 'Timeout', - moderatorID: moderator.id, - reason: timeoutReason, - duration: durationInEnglish(timeoutDuration), - date: currentDate, - infractionID: new mongoose.Types.ObjectId(), - }; - - let userData = await Infraction.findOne({ userID }); - - Logger.info(userData); - - if (!userData) { - userData = new Infraction({ - userID, - infractions: [newInfraction], - }); - Logger.info(userData); - Logger.info('New user data created'); - } else { - userData.infractions.push(newInfraction); - Logger.info('User data updated'); - } - - try { - await userData.save(); - Logger.info('Infraction process complete'); - } catch (error) { - await interaction.followUp({ embeds: [logFailed], ephemeral: true }); - Logger.error(error); - } + //Log to the DB + + Logger.info('Starting Infraction process'); + + const newInfraction = { + infractionType: 'Timeout', + moderatorID: moderator.id, + reason: timeoutReason, + duration: durationInEnglish(timeoutDuration), + date: currentDate, + infractionID: new mongoose.Types.ObjectId(), + }; + + let userData = await Infraction.findOne({ userID }); + + Logger.info(userData); + + if (!userData) { + userData = new Infraction({ + userID, + infractions: [newInfraction], + }); + Logger.info(userData); + Logger.info('New user data created'); } else { - await interaction.followUp({ embeds: [communicationNotDisabledEmbed(discordUser.user)], ephemeral: true }); + userData.infractions.push(newInfraction); + Logger.info('User data updated'); + } + + try { + await userData.save(); + Logger.info('Infraction process complete'); + } catch (error) { + await interaction.followUp({ embeds: [logFailed], ephemeral: true }); + Logger.error(error); } + } else { + await interaction.followUp({ embeds: [communicationNotDisabledEmbed(discordUser.user)], ephemeral: true }); + } } diff --git a/src/commands/moderation/infractions/functions/unbanInfractions.ts b/src/commands/moderation/infractions/functions/unbanInfractions.ts index 964566e1..2924ff29 100644 --- a/src/commands/moderation/infractions/functions/unbanInfractions.ts +++ b/src/commands/moderation/infractions/functions/unbanInfractions.ts @@ -4,131 +4,131 @@ import mongoose from 'mongoose'; import { constantsConfig, getConn, Infraction, Logger, makeEmbed } from '../../../../lib'; const noConnEmbed = makeEmbed({ - title: 'Unban - No Connection', - description: 'Could not connect to the database. I will still try to unban the user', - color: Colors.Red, + title: 'Unban - No Connection', + description: 'Could not connect to the database. I will still try to unban the user', + color: Colors.Red, }); const failedUnbanEmbed = (userID: string) => - makeEmbed({ - title: 'Unban - Failed', - description: `Failed to Unban ${userID}, this user may not be banned.`, - color: Colors.Red, - }); + makeEmbed({ + title: 'Unban - Failed', + description: `Failed to Unban ${userID}, this user may not be banned.`, + color: Colors.Red, + }); const unbanEmbed = (userID: string) => - makeEmbed({ - title: `${userID} was unbanned successfully`, - color: Colors.Green, - }); + makeEmbed({ + title: `${userID} was unbanned successfully`, + color: Colors.Green, + }); const modLogEmbed = (moderator: User, userID: string, banReason: string, formattedDate: string) => - makeEmbed({ - author: { name: `[UNBANNED] ${userID}` }, - fields: [ - { - name: 'User', - value: userID, - }, - { - name: 'Moderator', - value: `${moderator}`, - }, - { - name: 'Reason', - value: `\u200B${banReason}`, - }, - { - name: 'Date', - value: formattedDate, - }, - ], - footer: { text: `User ID: ${userID}` }, - color: Colors.Red, - }); + makeEmbed({ + author: { name: `[UNBANNED] ${userID}` }, + fields: [ + { + name: 'User', + value: userID, + }, + { + name: 'Moderator', + value: `${moderator}`, + }, + { + name: 'Reason', + value: `\u200B${banReason}`, + }, + { + name: 'Date', + value: formattedDate, + }, + ], + footer: { text: `User ID: ${userID}` }, + color: Colors.Red, + }); const noModLogs = makeEmbed({ - title: 'Unban - No Mod Log', - description: - "I can't find the mod logs channel. I will still try to unban the user. Please check the channel still exists.", - color: Colors.Red, + title: 'Unban - No Mod Log', + description: + "I can't find the mod logs channel. I will still try to unban the user. Please check the channel still exists.", + color: Colors.Red, }); const logFailed = makeEmbed({ - title: 'Unban - Failed to log', - description: 'Failed to log the unban to the database.', - color: Colors.Red, + title: 'Unban - Failed to log', + description: 'Failed to log the unban to the database.', + color: Colors.Red, }); export async function handleUnbanInfraction(interaction: ChatInputCommandInteraction<'cached'>) { - await interaction.deferReply({ ephemeral: true }); + await interaction.deferReply({ ephemeral: true }); - const conn = getConn(); + const conn = getConn(); - if (!conn) { - await interaction.followUp({ embeds: [noConnEmbed], ephemeral: true }); - return; - } + if (!conn) { + await interaction.followUp({ embeds: [noConnEmbed], ephemeral: true }); + return; + } - const userID = interaction.options.getUser('id')!.id; + const userID = interaction.options.getUser('id')!.id; - const unbanReason = interaction.options.getString('reason')!; + const unbanReason = interaction.options.getString('reason')!; - const moderator = interaction.user; - const currentDate = new Date(); - const formattedDate: string = moment(currentDate).utcOffset(0).format(); - const modLogsChannel = interaction.guild.channels.resolve(constantsConfig.channels.MOD_LOGS) as TextChannel; + const moderator = interaction.user; + const currentDate = new Date(); + const formattedDate: string = moment(currentDate).utcOffset(0).format(); + const modLogsChannel = interaction.guild.channels.resolve(constantsConfig.channels.MOD_LOGS) as TextChannel; - //Check if the mod logs channel exists + //Check if the mod logs channel exists - if (!modLogsChannel) { - await interaction.followUp({ embeds: [noModLogs], ephemeral: true }); - } + if (!modLogsChannel) { + await interaction.followUp({ embeds: [noModLogs], ephemeral: true }); + } - try { - await interaction.guild.members.unban(userID, unbanReason); - if (modLogsChannel) { - await modLogsChannel.send({ embeds: [modLogEmbed(moderator, userID, unbanReason, formattedDate)] }); - } - await interaction.followUp({ embeds: [unbanEmbed(userID)], ephemeral: true }); - } catch (error) { - Logger.error(error); - await interaction.followUp({ embeds: [failedUnbanEmbed(userID)], ephemeral: true }); - return; + try { + await interaction.guild.members.unban(userID, unbanReason); + if (modLogsChannel) { + await modLogsChannel.send({ embeds: [modLogEmbed(moderator, userID, unbanReason, formattedDate)] }); } - - //Log to the DB - Logger.info('Starting Infraction process'); - - const newInfraction = { - infractionType: 'Unban', - moderatorID: moderator.id, - reason: unbanReason, - date: currentDate, - infractionID: new mongoose.Types.ObjectId(), - }; - - let userData = await Infraction.findOne({ userID }); - + await interaction.followUp({ embeds: [unbanEmbed(userID)], ephemeral: true }); + } catch (error) { + Logger.error(error); + await interaction.followUp({ embeds: [failedUnbanEmbed(userID)], ephemeral: true }); + return; + } + + //Log to the DB + Logger.info('Starting Infraction process'); + + const newInfraction = { + infractionType: 'Unban', + moderatorID: moderator.id, + reason: unbanReason, + date: currentDate, + infractionID: new mongoose.Types.ObjectId(), + }; + + let userData = await Infraction.findOne({ userID }); + + Logger.info(userData); + + if (!userData) { + userData = new Infraction({ + userID, + infractions: [newInfraction], + }); Logger.info(userData); - - if (!userData) { - userData = new Infraction({ - userID, - infractions: [newInfraction], - }); - Logger.info(userData); - Logger.info('New user data created'); - } else { - userData.infractions.push(newInfraction); - Logger.info('User data updated'); - } - - try { - await userData.save(); - Logger.info('Infraction process complete'); - } catch (error) { - await interaction.followUp({ embeds: [logFailed], ephemeral: true }); - Logger.error(error); - } + Logger.info('New user data created'); + } else { + userData.infractions.push(newInfraction); + Logger.info('User data updated'); + } + + try { + await userData.save(); + Logger.info('Infraction process complete'); + } catch (error) { + await interaction.followUp({ embeds: [logFailed], ephemeral: true }); + Logger.error(error); + } } diff --git a/src/commands/moderation/infractions/functions/userNote.ts b/src/commands/moderation/infractions/functions/userNote.ts index 4e2ef024..e66c4920 100644 --- a/src/commands/moderation/infractions/functions/userNote.ts +++ b/src/commands/moderation/infractions/functions/userNote.ts @@ -4,136 +4,136 @@ import mongoose from 'mongoose'; import { constantsConfig, getConn, Infraction, Logger, makeEmbed } from '../../../../lib'; const noConnEmbed = makeEmbed({ - title: 'Note - No Connection', - description: 'Could not connect to the database', - color: Colors.Red, + title: 'Note - No Connection', + description: 'Could not connect to the database', + color: Colors.Red, }); const noteFailed = makeEmbed({ - title: 'Note - Failed', - description: 'Failed to add user note, doc not saved to mongoDB', - color: Colors.Red, + title: 'Note - Failed', + description: 'Failed to add user note, doc not saved to mongoDB', + color: Colors.Red, }); const modLogEmbed = (formattedDate: any, moderator: User, discordUser: User, note: string) => - makeEmbed({ - author: { - name: `[NOTE] ${discordUser.tag}`, - iconURL: discordUser.displayAvatarURL(), - }, - fields: [ - { - inline: false, - name: 'User', - value: discordUser.toString(), - }, - { - inline: false, - name: 'Moderator', - value: moderator.toString(), - }, - { - inline: false, - name: 'Note', - value: note, - }, - { - inline: false, - name: 'Date', - value: formattedDate, - }, - ], - footer: { text: `User ID: ${discordUser.id}` }, - color: Colors.Red, - }); + makeEmbed({ + author: { + name: `[NOTE] ${discordUser.tag}`, + iconURL: discordUser.displayAvatarURL(), + }, + fields: [ + { + inline: false, + name: 'User', + value: discordUser.toString(), + }, + { + inline: false, + name: 'Moderator', + value: moderator.toString(), + }, + { + inline: false, + name: 'Note', + value: note, + }, + { + inline: false, + name: 'Date', + value: formattedDate, + }, + ], + footer: { text: `User ID: ${discordUser.id}` }, + color: Colors.Red, + }); const noteEmbed = (user: User) => - makeEmbed({ - title: `Note for ${user.tag} has been added successfully`, - color: Colors.Green, - }); + makeEmbed({ + title: `Note for ${user.tag} has been added successfully`, + color: Colors.Green, + }); const noModLogs = makeEmbed({ - title: 'Note - No Mod Log', - description: 'The user note was added, but no mod log was sent. Please check the channel still exists', - color: Colors.Red, + title: 'Note - No Mod Log', + description: 'The user note was added, but no mod log was sent. Please check the channel still exists', + color: Colors.Red, }); export async function handleUserNoteInfraction(interaction: ChatInputCommandInteraction<'cached'>) { - const conn = getConn(); + const conn = getConn(); - if (!conn) { - await interaction.reply({ embeds: [noConnEmbed], ephemeral: true }); - return; - } + if (!conn) { + await interaction.reply({ embeds: [noConnEmbed], ephemeral: true }); + return; + } - const userID = interaction.options.getUser('tag_or_id')?.id; + const userID = interaction.options.getUser('tag_or_id')?.id; - if (!userID) { - await interaction.reply({ content: 'Please provide a user tag or ID.', ephemeral: true }); - return; - } + if (!userID) { + await interaction.reply({ content: 'Please provide a user tag or ID.', ephemeral: true }); + return; + } - const note = interaction.options.getString('note'); + const note = interaction.options.getString('note'); - if (!note) { - await interaction.reply({ content: 'Please provide a note.', ephemeral: true }); - return; - } + if (!note) { + await interaction.reply({ content: 'Please provide a note.', ephemeral: true }); + return; + } - const discordUser = await interaction.client.users.fetch(userID); + const discordUser = await interaction.client.users.fetch(userID); - const moderator = interaction.user; + const moderator = interaction.user; - const currentDate = new Date(); + const currentDate = new Date(); - const formattedDate: string = moment(currentDate).utcOffset(0).format(); + const formattedDate: string = moment(currentDate).utcOffset(0).format(); - const modLogsChannel = interaction.guild.channels.resolve(constantsConfig.channels.MOD_LOGS) as TextChannel; + const modLogsChannel = interaction.guild.channels.resolve(constantsConfig.channels.MOD_LOGS) as TextChannel; - //Try to save to the database + //Try to save to the database - Logger.info('Starting Infraction process'); + Logger.info('Starting Infraction process'); - const newInfraction = { - infractionType: 'Note', - moderatorID: moderator.id, - reason: note, - date: currentDate, - infractionID: new mongoose.Types.ObjectId(), - }; + const newInfraction = { + infractionType: 'Note', + moderatorID: moderator.id, + reason: note, + date: currentDate, + infractionID: new mongoose.Types.ObjectId(), + }; - let userData = await Infraction.findOne({ userID }); + let userData = await Infraction.findOne({ userID }); - Logger.info(userData); + Logger.info(userData); - if (!userData) { - userData = new Infraction({ - userID, - infractions: [newInfraction], - }); - Logger.info(userData); - Logger.info('New user data created'); - } else { - userData.infractions.push(newInfraction); - Logger.info('User data updated'); - } - - try { - await userData.save(); - Logger.info('Infraction process complete'); - } catch (error) { - await interaction.reply({ embeds: [noteFailed], ephemeral: true }); - Logger.error(error); - } - - //Send embed to mod-logs channel - - try { - await modLogsChannel.send({ embeds: [modLogEmbed(formattedDate, moderator, discordUser, note)] }); - } catch { - await interaction.reply({ embeds: [noModLogs], ephemeral: true }); - return; - } - await interaction.reply({ embeds: [noteEmbed(discordUser)], ephemeral: true }); + if (!userData) { + userData = new Infraction({ + userID, + infractions: [newInfraction], + }); + Logger.info(userData); + Logger.info('New user data created'); + } else { + userData.infractions.push(newInfraction); + Logger.info('User data updated'); + } + + try { + await userData.save(); + Logger.info('Infraction process complete'); + } catch (error) { + await interaction.reply({ embeds: [noteFailed], ephemeral: true }); + Logger.error(error); + } + + //Send embed to mod-logs channel + + try { + await modLogsChannel.send({ embeds: [modLogEmbed(formattedDate, moderator, discordUser, note)] }); + } catch { + await interaction.reply({ embeds: [noModLogs], ephemeral: true }); + return; + } + await interaction.reply({ embeds: [noteEmbed(discordUser)], ephemeral: true }); } diff --git a/src/commands/moderation/infractions/functions/warn.ts b/src/commands/moderation/infractions/functions/warn.ts index 62a76dac..f9e498ec 100644 --- a/src/commands/moderation/infractions/functions/warn.ts +++ b/src/commands/moderation/infractions/functions/warn.ts @@ -4,177 +4,177 @@ import mongoose from 'mongoose'; import { constantsConfig, getConn, Infraction, Logger, makeEmbed } from '../../../../lib'; const noConnEmbed = makeEmbed({ - title: 'Warn - No Connection', - description: 'Could not connect to the database', - color: Colors.Red, + title: 'Warn - No Connection', + description: 'Could not connect to the database', + color: Colors.Red, }); const warnFailed = (discordUser: User) => - makeEmbed({ - title: 'Warn - Failed', - description: `Failed to warn ${discordUser.toString()}, doc not saved to mongoDB`, - color: Colors.Red, - }); + makeEmbed({ + title: 'Warn - Failed', + description: `Failed to warn ${discordUser.toString()}, doc not saved to mongoDB`, + color: Colors.Red, + }); const dmEmbed = (guild: Guild, formattedDate: any, moderator: User, reason: string) => - makeEmbed({ - title: `You have been warned in ${guild.name}`, - fields: [ - { - inline: false, - name: 'Moderator', - value: moderator.toString(), - }, - { - inline: false, - name: 'Reason', - value: reason, - }, - { - inline: false, - name: 'Date', - value: formattedDate, - }, - ], - }); + makeEmbed({ + title: `You have been warned in ${guild.name}`, + fields: [ + { + inline: false, + name: 'Moderator', + value: moderator.toString(), + }, + { + inline: false, + name: 'Reason', + value: reason, + }, + { + inline: false, + name: 'Date', + value: formattedDate, + }, + ], + }); const noDM = (discordUser: User) => - makeEmbed({ - title: 'Warn - DM not sent', - description: `DM was not sent to ${discordUser.toString()}, they either have DMs closed or share no mutual servers with the bot.`, - color: Colors.Red, - }); + makeEmbed({ + title: 'Warn - DM not sent', + description: `DM was not sent to ${discordUser.toString()}, they either have DMs closed or share no mutual servers with the bot.`, + color: Colors.Red, + }); const modLogEmbed = (formattedDate: any, moderator: User, discordUser: User, reason: string) => - makeEmbed({ - author: { - name: `[WARNED] ${discordUser.tag}`, - iconURL: discordUser.displayAvatarURL(), - }, - fields: [ - { - inline: false, - name: 'User', - value: discordUser.toString(), - }, - { - inline: false, - name: 'Moderator', - value: moderator.toString(), - }, - { - inline: false, - name: 'Reason', - value: reason, - }, - { - inline: false, - name: 'Date', - value: formattedDate, - }, - ], - footer: { text: `User ID: ${discordUser.id}` }, - color: Colors.Red, - }); + makeEmbed({ + author: { + name: `[WARNED] ${discordUser.tag}`, + iconURL: discordUser.displayAvatarURL(), + }, + fields: [ + { + inline: false, + name: 'User', + value: discordUser.toString(), + }, + { + inline: false, + name: 'Moderator', + value: moderator.toString(), + }, + { + inline: false, + name: 'Reason', + value: reason, + }, + { + inline: false, + name: 'Date', + value: formattedDate, + }, + ], + footer: { text: `User ID: ${discordUser.id}` }, + color: Colors.Red, + }); const warnEmbed = (discordUser: User) => - makeEmbed({ - title: `${discordUser.tag} was warned successfully`, - color: Colors.Green, - }); + makeEmbed({ + title: `${discordUser.tag} was warned successfully`, + color: Colors.Green, + }); const noModLogs = makeEmbed({ - title: 'Warn - No Mod Log', - description: 'The user was warned, but no mod log was sent. Please check the channel still exists', - color: Colors.Red, + title: 'Warn - No Mod Log', + description: 'The user was warned, but no mod log was sent. Please check the channel still exists', + color: Colors.Red, }); export async function handleWarnInfraction(interaction: ChatInputCommandInteraction<'cached'>) { - await interaction.deferReply({ ephemeral: true }); + await interaction.deferReply({ ephemeral: true }); - const conn = getConn(); + const conn = getConn(); - if (!conn) { - await interaction.editReply({ embeds: [noConnEmbed] }); - return; - } + if (!conn) { + await interaction.editReply({ embeds: [noConnEmbed] }); + return; + } - const userID = interaction.options.getUser('tag_or_id')?.id; + const userID = interaction.options.getUser('tag_or_id')?.id; - if (!userID) { - await interaction.editReply({ content: 'Please provide a user tag or ID.' }); - return; - } + if (!userID) { + await interaction.editReply({ content: 'Please provide a user tag or ID.' }); + return; + } - const reason = interaction.options.getString('reason'); + const reason = interaction.options.getString('reason'); - if (!reason) { - await interaction.editReply({ content: 'Please provide a reason.' }); - return; - } + if (!reason) { + await interaction.editReply({ content: 'Please provide a reason.' }); + return; + } - const discordUser = await interaction.client.users.fetch(userID); + const discordUser = await interaction.client.users.fetch(userID); - const moderator = interaction.user; + const moderator = interaction.user; - const currentDate = new Date(); + const currentDate = new Date(); - const formattedDate: string = moment(currentDate).utcOffset(0).format(); + const formattedDate: string = moment(currentDate).utcOffset(0).format(); - const modLogsChannel = interaction.guild.channels.resolve(constantsConfig.channels.MOD_LOGS) as TextChannel; + const modLogsChannel = interaction.guild.channels.resolve(constantsConfig.channels.MOD_LOGS) as TextChannel; - //Try to save to the database + //Try to save to the database - Logger.info('Starting Infraction process'); + Logger.info('Starting Infraction process'); - const newInfraction = { - infractionType: 'Warn', - moderatorID: moderator.id, - reason, - date: currentDate, - infractionID: new mongoose.Types.ObjectId(), - }; + const newInfraction = { + infractionType: 'Warn', + moderatorID: moderator.id, + reason, + date: currentDate, + infractionID: new mongoose.Types.ObjectId(), + }; - let userData = await Infraction.findOne({ userID }); + let userData = await Infraction.findOne({ userID }); - Logger.info(userData); + Logger.info(userData); - if (!userData) { - userData = new Infraction({ - userID, - infractions: [newInfraction], - }); - Logger.info(userData); - Logger.info('New user data created'); - } else { - userData.infractions.push(newInfraction); - Logger.info('User data updated'); - } - - try { - await userData.save(); - Logger.info('Infraction process complete'); - } catch (error) { - await interaction.editReply({ embeds: [warnFailed(discordUser)] }); - Logger.error(error); - return; - } - - await interaction.editReply({ embeds: [warnEmbed(discordUser)] }); - - //Send DM to user - - try { - await discordUser.send({ embeds: [dmEmbed(interaction.guild, formattedDate, moderator, reason)] }); - } catch { - await interaction.followUp({ embeds: [noDM(discordUser)], ephemeral: true }); - } - - //Send embed to mod-logs channel - - try { - await modLogsChannel.send({ embeds: [modLogEmbed(formattedDate, moderator, discordUser, reason)] }); - } catch { - await interaction.followUp({ embeds: [noModLogs], ephemeral: true }); - } + if (!userData) { + userData = new Infraction({ + userID, + infractions: [newInfraction], + }); + Logger.info(userData); + Logger.info('New user data created'); + } else { + userData.infractions.push(newInfraction); + Logger.info('User data updated'); + } + + try { + await userData.save(); + Logger.info('Infraction process complete'); + } catch (error) { + await interaction.editReply({ embeds: [warnFailed(discordUser)] }); + Logger.error(error); + return; + } + + await interaction.editReply({ embeds: [warnEmbed(discordUser)] }); + + //Send DM to user + + try { + await discordUser.send({ embeds: [dmEmbed(interaction.guild, formattedDate, moderator, reason)] }); + } catch { + await interaction.followUp({ embeds: [noDM(discordUser)], ephemeral: true }); + } + + //Send embed to mod-logs channel + + try { + await modLogsChannel.send({ embeds: [modLogEmbed(formattedDate, moderator, discordUser, reason)] }); + } catch { + await interaction.followUp({ embeds: [noModLogs], ephemeral: true }); + } } diff --git a/src/commands/moderation/infractions/infractions.ts b/src/commands/moderation/infractions/infractions.ts index 7aa8e177..b0c4790d 100644 --- a/src/commands/moderation/infractions/infractions.ts +++ b/src/commands/moderation/infractions/infractions.ts @@ -14,216 +14,216 @@ import { handleUnbanInfraction } from './functions/unbanInfractions'; // Unban const data = slashCommandStructure({ - name: 'infractions', - description: 'Command to manage infractions.', - type: ApplicationCommandType.ChatInput, - default_member_permissions: constantsConfig.commandPermission.MANAGE_SERVER, //Overrides need to be added for admin and moderator roles - dm_permission: false, - options: [ - { - name: 'list', - description: 'Get infractions for a user.', - type: ApplicationCommandOptionType.Subcommand, - options: [ - { - name: 'tag_or_id', - description: 'Please provide a user tag or ID.', - type: ApplicationCommandOptionType.User, - required: true, - }, - ], - }, - { - name: 'delete', - description: 'Deletes the specified infraction.', - type: ApplicationCommandOptionType.Subcommand, - options: [ - { - name: 'tag_or_id', - description: 'Please provide the user tag or ID for the user of the infraction you wish to delete.', - type: ApplicationCommandOptionType.User, - required: true, - }, - { - name: 'infraction_id', - description: 'Please provide the ID of the infraction you wish to delete.', - type: ApplicationCommandOptionType.String, - max_length: 100, - required: true, - }, - ], - }, - { - name: 'note', - description: 'Adds a logging note to a user.', - type: ApplicationCommandOptionType.Subcommand, - options: [ - { - name: 'tag_or_id', - description: 'Please provide a user tag or ID.', - type: ApplicationCommandOptionType.User, - required: true, - }, - { - name: 'note', - description: 'Please provide a note.', - type: ApplicationCommandOptionType.String, - required: true, - }, - ], - }, - { - name: 'warn', - description: 'Warns a user.', - type: ApplicationCommandOptionType.Subcommand, - options: [ - { - name: 'tag_or_id', - description: 'Please provide a user tag or ID.', - type: ApplicationCommandOptionType.User, - required: true, - }, - { - name: 'reason', - description: 'Please provide a reason.', - type: ApplicationCommandOptionType.String, - required: true, - }, - ], - }, - { - name: 'timeout', - description: 'Timeouts a user.', - type: ApplicationCommandOptionType.Subcommand, - options: [ - { - name: 'tag_or_id', - description: 'Please provide a user tag or ID.', - type: ApplicationCommandOptionType.User, - required: true, - }, - { - name: 'duration', - description: 'Please provide a duration.', - type: ApplicationCommandOptionType.Number, - required: true, - choices: [ - { name: '1 minute', value: 60000 }, - { name: '5 minutes', value: 300000 }, - { name: '15 minutes', value: 900000 }, - { name: '30 minutes', value: 1800000 }, - { name: '1 hour', value: 3600000 }, - { name: '6 hours', value: 21600000 }, - { name: '12 hours', value: 43200000 }, - { name: '1 day', value: 86400000 }, - { name: '3 days', value: 259200000 }, - { name: '1 week', value: 604800000 }, - { name: '2 weeks', value: 1209600000 }, - { name: '3 weeks', value: 1814400000 }, - { name: '4 weeks', value: 2419200000 }, - ], - }, - { - name: 'reason', - description: 'Please provide a reason.', - type: ApplicationCommandOptionType.String, - required: true, - }, - ], - }, - { - name: 'remove-timeout', - description: 'Removes a timeout from a user.', - type: ApplicationCommandOptionType.Subcommand, - options: [ - { - name: 'tag_or_id', - description: 'Please provide a user tag or ID.', - type: ApplicationCommandOptionType.User, - required: true, - }, - ], - }, - { - name: 'ban', - description: 'Bans a user.', - type: ApplicationCommandOptionType.Subcommand, - options: [ - { - name: 'tag_or_id', - description: 'Please provide a user tag or ID.', - type: ApplicationCommandOptionType.User, - required: true, - }, - { - name: 'reason', - description: 'Please provide a reason.', - type: ApplicationCommandOptionType.String, - required: true, - }, - { - name: 'days_deleted', - description: 'Please provide the number of days of messages to delete.', - type: ApplicationCommandOptionType.Integer, - required: false, - min_value: 0, - max_value: 7, - }, - ], - }, - { - name: 'unban', - description: 'Unbans a user.', - type: ApplicationCommandOptionType.Subcommand, - options: [ - { - name: 'id', - description: 'Please provide a userID only.', - type: ApplicationCommandOptionType.User, - required: true, - }, - { - name: 'reason', - description: 'Please provide a reason.', - type: ApplicationCommandOptionType.String, - required: true, - }, - ], - }, - ], + name: 'infractions', + description: 'Command to manage infractions.', + type: ApplicationCommandType.ChatInput, + default_member_permissions: constantsConfig.commandPermission.MANAGE_SERVER, //Overrides need to be added for admin and moderator roles + dm_permission: false, + options: [ + { + name: 'list', + description: 'Get infractions for a user.', + type: ApplicationCommandOptionType.Subcommand, + options: [ + { + name: 'tag_or_id', + description: 'Please provide a user tag or ID.', + type: ApplicationCommandOptionType.User, + required: true, + }, + ], + }, + { + name: 'delete', + description: 'Deletes the specified infraction.', + type: ApplicationCommandOptionType.Subcommand, + options: [ + { + name: 'tag_or_id', + description: 'Please provide the user tag or ID for the user of the infraction you wish to delete.', + type: ApplicationCommandOptionType.User, + required: true, + }, + { + name: 'infraction_id', + description: 'Please provide the ID of the infraction you wish to delete.', + type: ApplicationCommandOptionType.String, + max_length: 100, + required: true, + }, + ], + }, + { + name: 'note', + description: 'Adds a logging note to a user.', + type: ApplicationCommandOptionType.Subcommand, + options: [ + { + name: 'tag_or_id', + description: 'Please provide a user tag or ID.', + type: ApplicationCommandOptionType.User, + required: true, + }, + { + name: 'note', + description: 'Please provide a note.', + type: ApplicationCommandOptionType.String, + required: true, + }, + ], + }, + { + name: 'warn', + description: 'Warns a user.', + type: ApplicationCommandOptionType.Subcommand, + options: [ + { + name: 'tag_or_id', + description: 'Please provide a user tag or ID.', + type: ApplicationCommandOptionType.User, + required: true, + }, + { + name: 'reason', + description: 'Please provide a reason.', + type: ApplicationCommandOptionType.String, + required: true, + }, + ], + }, + { + name: 'timeout', + description: 'Timeouts a user.', + type: ApplicationCommandOptionType.Subcommand, + options: [ + { + name: 'tag_or_id', + description: 'Please provide a user tag or ID.', + type: ApplicationCommandOptionType.User, + required: true, + }, + { + name: 'duration', + description: 'Please provide a duration.', + type: ApplicationCommandOptionType.Number, + required: true, + choices: [ + { name: '1 minute', value: 60000 }, + { name: '5 minutes', value: 300000 }, + { name: '15 minutes', value: 900000 }, + { name: '30 minutes', value: 1800000 }, + { name: '1 hour', value: 3600000 }, + { name: '6 hours', value: 21600000 }, + { name: '12 hours', value: 43200000 }, + { name: '1 day', value: 86400000 }, + { name: '3 days', value: 259200000 }, + { name: '1 week', value: 604800000 }, + { name: '2 weeks', value: 1209600000 }, + { name: '3 weeks', value: 1814400000 }, + { name: '4 weeks', value: 2419200000 }, + ], + }, + { + name: 'reason', + description: 'Please provide a reason.', + type: ApplicationCommandOptionType.String, + required: true, + }, + ], + }, + { + name: 'remove-timeout', + description: 'Removes a timeout from a user.', + type: ApplicationCommandOptionType.Subcommand, + options: [ + { + name: 'tag_or_id', + description: 'Please provide a user tag or ID.', + type: ApplicationCommandOptionType.User, + required: true, + }, + ], + }, + { + name: 'ban', + description: 'Bans a user.', + type: ApplicationCommandOptionType.Subcommand, + options: [ + { + name: 'tag_or_id', + description: 'Please provide a user tag or ID.', + type: ApplicationCommandOptionType.User, + required: true, + }, + { + name: 'reason', + description: 'Please provide a reason.', + type: ApplicationCommandOptionType.String, + required: true, + }, + { + name: 'days_deleted', + description: 'Please provide the number of days of messages to delete.', + type: ApplicationCommandOptionType.Integer, + required: false, + min_value: 0, + max_value: 7, + }, + ], + }, + { + name: 'unban', + description: 'Unbans a user.', + type: ApplicationCommandOptionType.Subcommand, + options: [ + { + name: 'id', + description: 'Please provide a userID only.', + type: ApplicationCommandOptionType.User, + required: true, + }, + { + name: 'reason', + description: 'Please provide a reason.', + type: ApplicationCommandOptionType.String, + required: true, + }, + ], + }, + ], }); export default slashCommand(data, async ({ interaction }) => { - const subcommandName = interaction.options.getSubcommand(); + const subcommandName = interaction.options.getSubcommand(); - switch (subcommandName) { - case 'list': - const userID = interaction.options.getUser('tag_or_id')?.id; - await handleListInfraction(interaction, userID, false); - break; - case 'delete': - await handleDeleteInfraction(interaction); - break; - case 'note': - await handleUserNoteInfraction(interaction); - break; - case 'warn': - await handleWarnInfraction(interaction); - break; - case 'timeout': - await handleTimeoutInfraction(interaction); - break; - case 'remove-timeout': - await handleRemoveTimeoutInfraction(interaction); - break; - case 'ban': - await handleBanInfraction(interaction); - break; - case 'unban': - await handleUnbanInfraction(interaction); - break; + switch (subcommandName) { + case 'list': + const userID = interaction.options.getUser('tag_or_id')?.id; + await handleListInfraction(interaction, userID, false); + break; + case 'delete': + await handleDeleteInfraction(interaction); + break; + case 'note': + await handleUserNoteInfraction(interaction); + break; + case 'warn': + await handleWarnInfraction(interaction); + break; + case 'timeout': + await handleTimeoutInfraction(interaction); + break; + case 'remove-timeout': + await handleRemoveTimeoutInfraction(interaction); + break; + case 'ban': + await handleBanInfraction(interaction); + break; + case 'unban': + await handleUnbanInfraction(interaction); + break; - default: - await interaction.reply({ content: 'Unknown subcommand', ephemeral: true }); - } + default: + await interaction.reply({ content: 'Unknown subcommand', ephemeral: true }); + } }); diff --git a/src/commands/moderation/listRoleUsers.ts b/src/commands/moderation/listRoleUsers.ts index 1da6ed73..763f275d 100644 --- a/src/commands/moderation/listRoleUsers.ts +++ b/src/commands/moderation/listRoleUsers.ts @@ -1,82 +1,82 @@ import { ApplicationCommandOptionType, ApplicationCommandType } from 'discord.js'; import { - constantsConfig, - Logger, - makeEmbed, - createPaginatedEmbedHandler, - slashCommand, - slashCommandStructure, + constantsConfig, + Logger, + makeEmbed, + createPaginatedEmbedHandler, + slashCommand, + slashCommandStructure, } from '../../lib'; const data = slashCommandStructure({ - name: 'list-role-users', - description: 'Lists all users with a specific role.', - type: ApplicationCommandType.ChatInput, - default_member_permissions: constantsConfig.commandPermission.MANAGE_SERVER, //Overrides need to be added for admin, moderator roles - dm_permission: false, - options: [ - { - name: 'role', - description: 'The role to list users for.', - type: ApplicationCommandOptionType.Role, - required: true, - }, - ], + name: 'list-role-users', + description: 'Lists all users with a specific role.', + type: ApplicationCommandType.ChatInput, + default_member_permissions: constantsConfig.commandPermission.MANAGE_SERVER, //Overrides need to be added for admin, moderator roles + dm_permission: false, + options: [ + { + name: 'role', + description: 'The role to list users for.', + type: ApplicationCommandOptionType.Role, + required: true, + }, + ], }); export default slashCommand(data, async ({ interaction }) => { - await interaction.deferReply(); + await interaction.deferReply(); - const role = interaction.options.getRole('role'); + const role = interaction.options.getRole('role'); - if (!role) return interaction.editReply({ content: 'Invalid role!' }); + if (!role) return interaction.editReply({ content: 'Invalid role!' }); - const roleMembers = role.members.map((member) => ({ - tag: member.user.tag, - id: member.id, - })); + const roleMembers = role.members.map((member) => ({ + tag: member.user.tag, + id: member.id, + })); - const pageLimit = 50; // 50 per page as discord usernames have a max length of 32 characters. With the ID we don't exceed the 4096 character limit. - const embeds = []; - let currentPage = 0; - let membersAddedToPage = 0; - let description = ''; - const totalPages = Math.ceil(roleMembers.length / pageLimit); + const pageLimit = 50; // 50 per page as discord usernames have a max length of 32 characters. With the ID we don't exceed the 4096 character limit. + const embeds = []; + let currentPage = 0; + let membersAddedToPage = 0; + let description = ''; + const totalPages = Math.ceil(roleMembers.length / pageLimit); - for (const member of roleMembers) { - description += `${member.tag} - ID: ${member.id}\n`; - membersAddedToPage++; + for (const member of roleMembers) { + description += `${member.tag} - ID: ${member.id}\n`; + membersAddedToPage++; - if (membersAddedToPage >= pageLimit) { - embeds.push( - makeEmbed({ - title: `Role Users | ${role.name} - Page ${currentPage + 1} of ${totalPages}`, - description, - }), - ); - description = ''; - membersAddedToPage = 0; - currentPage++; - } + if (membersAddedToPage >= pageLimit) { + embeds.push( + makeEmbed({ + title: `Role Users | ${role.name} - Page ${currentPage + 1} of ${totalPages}`, + description, + }), + ); + description = ''; + membersAddedToPage = 0; + currentPage++; } + } - if (description.trim() !== '') { - embeds.push( - makeEmbed({ - title: `Role Users | ${role.name} - Page ${currentPage + 1} of ${totalPages}`, - description, - }), - ); - } + if (description.trim() !== '') { + embeds.push( + makeEmbed({ + title: `Role Users | ${role.name} - Page ${currentPage + 1} of ${totalPages}`, + description, + }), + ); + } - if (embeds.length === 0) { - return interaction.editReply({ content: 'No users with this role exist.' }); - } + if (embeds.length === 0) { + return interaction.editReply({ content: 'No users with this role exist.' }); + } - try { - return createPaginatedEmbedHandler(interaction, embeds); - } catch (error) { - Logger.error('Error sending paginated embed', error); - return interaction.editReply({ content: 'An error occurred while sending the paginated embed.' }); - } + try { + return createPaginatedEmbedHandler(interaction, embeds); + } catch (error) { + Logger.error('Error sending paginated embed', error); + return interaction.editReply({ content: 'An error occurred while sending the paginated embed.' }); + } }); diff --git a/src/commands/moderation/roleAssignment.ts b/src/commands/moderation/roleAssignment.ts index f5eb2b7f..fe4adab3 100644 --- a/src/commands/moderation/roleAssignment.ts +++ b/src/commands/moderation/roleAssignment.ts @@ -2,99 +2,99 @@ import { ActionRowBuilder, ApplicationCommandType, ButtonBuilder, ButtonStyle } import { constantsConfig, makeEmbed, slashCommand, slashCommandStructure } from '../../lib'; const data = slashCommandStructure({ - name: 'role-assignment', - description: 'Configures and sends the role assignment embed.', - type: ApplicationCommandType.ChatInput, - default_member_permissions: constantsConfig.commandPermission.MANAGE_SERVER, //Overrides need to be added for admin and moderator - dm_permission: false, + name: 'role-assignment', + description: 'Configures and sends the role assignment embed.', + type: ApplicationCommandType.ChatInput, + default_member_permissions: constantsConfig.commandPermission.MANAGE_SERVER, //Overrides need to be added for admin and moderator + dm_permission: false, }); const interestedInEmbed = makeEmbed({ - title: 'Role Assignment', - description: - 'Please react below to set your role according to your skill set. If you do not have the skills in any of the available roles, please do not react as this will not benefit the development of the addon.', + title: 'Role Assignment', + description: + 'Please react below to set your role according to your skill set. If you do not have the skills in any of the available roles, please do not react as this will not benefit the development of the addon.', }); const mediaAnnouncementsEmbed = makeEmbed({ - title: 'Media Announcements', - description: 'Please react to the corresponding buttons to be pinged for the various announcements.', + title: 'Media Announcements', + description: 'Please react to the corresponding buttons to be pinged for the various announcements.', }); function splitButtonsIntoRows(buttons: ButtonBuilder[], maxButtonsPerRow: number): ButtonBuilder[][] { - const rows: ButtonBuilder[][] = []; - let currentRow: ButtonBuilder[] = []; + const rows: ButtonBuilder[][] = []; + let currentRow: ButtonBuilder[] = []; - for (const button of buttons) { - currentRow.push(button); + for (const button of buttons) { + currentRow.push(button); - if (currentRow.length === maxButtonsPerRow) { - rows.push([...currentRow]); - currentRow = []; - } + if (currentRow.length === maxButtonsPerRow) { + rows.push([...currentRow]); + currentRow = []; } + } - if (currentRow.length > 0) { - rows.push([...currentRow]); - } + if (currentRow.length > 0) { + rows.push([...currentRow]); + } - return rows; + return rows; } export default slashCommand(data, async ({ interaction }) => { - const maxButtonsPerRow = 5; // Define the maximum buttons per row - - const interestedInButtons: ButtonBuilder[] = []; - const mediaAnnouncementsButtons: ButtonBuilder[] = []; - - const { roleAssignmentIds } = constantsConfig; - roleAssignmentIds.forEach((group) => { - group.roles.forEach((role) => { - const button = new ButtonBuilder() - .setCustomId(`roleAssignment_${role.id}`) - .setLabel(role.label) - .setStyle(ButtonStyle.Primary); - - if (group.group === 'interestedIn') { - interestedInButtons.push(button); - } else if (group.group === 'mediaAnnouncements') { - mediaAnnouncementsButtons.push(button); - } - }); - }); - - // Split the buttons into rows - const interestedInRows = splitButtonsIntoRows(interestedInButtons, maxButtonsPerRow); - const mediaAnnouncementsRows = splitButtonsIntoRows(mediaAnnouncementsButtons, maxButtonsPerRow); - - if (!interaction.channel) { - await interaction.reply({ content: 'Interaction channel is null.', ephemeral: true }); - return; - } - - // Create a single embed for each group type and add all rows to it - const interestedInEmbedWithRows = { - embeds: [interestedInEmbed], - components: [] as ActionRowBuilder[], - }; - - const mediaAnnouncementsEmbedWithRows = { - embeds: [mediaAnnouncementsEmbed], - components: [] as ActionRowBuilder[], - }; - - interestedInRows.forEach((row) => { - const actionRow: ActionRowBuilder = new ActionRowBuilder().addComponents(...row); - interestedInEmbedWithRows.components.push(actionRow); - }); - - mediaAnnouncementsRows.forEach((row) => { - const actionRow: ActionRowBuilder = new ActionRowBuilder().addComponents(...row); - mediaAnnouncementsEmbedWithRows.components.push(actionRow); + const maxButtonsPerRow = 5; // Define the maximum buttons per row + + const interestedInButtons: ButtonBuilder[] = []; + const mediaAnnouncementsButtons: ButtonBuilder[] = []; + + const { roleAssignmentIds } = constantsConfig; + roleAssignmentIds.forEach((group) => { + group.roles.forEach((role) => { + const button = new ButtonBuilder() + .setCustomId(`roleAssignment_${role.id}`) + .setLabel(role.label) + .setStyle(ButtonStyle.Primary); + + if (group.group === 'interestedIn') { + interestedInButtons.push(button); + } else if (group.group === 'mediaAnnouncements') { + mediaAnnouncementsButtons.push(button); + } }); - - // Send the embeds with attached rows - await interaction.channel.send(interestedInEmbedWithRows); - await interaction.channel.send(mediaAnnouncementsEmbedWithRows); - - await interaction.reply({ content: 'Role assignment embeds sent.', ephemeral: true }); + }); + + // Split the buttons into rows + const interestedInRows = splitButtonsIntoRows(interestedInButtons, maxButtonsPerRow); + const mediaAnnouncementsRows = splitButtonsIntoRows(mediaAnnouncementsButtons, maxButtonsPerRow); + + if (!interaction.channel) { + await interaction.reply({ content: 'Interaction channel is null.', ephemeral: true }); + return; + } + + // Create a single embed for each group type and add all rows to it + const interestedInEmbedWithRows = { + embeds: [interestedInEmbed], + components: [] as ActionRowBuilder[], + }; + + const mediaAnnouncementsEmbedWithRows = { + embeds: [mediaAnnouncementsEmbed], + components: [] as ActionRowBuilder[], + }; + + interestedInRows.forEach((row) => { + const actionRow: ActionRowBuilder = new ActionRowBuilder().addComponents(...row); + interestedInEmbedWithRows.components.push(actionRow); + }); + + mediaAnnouncementsRows.forEach((row) => { + const actionRow: ActionRowBuilder = new ActionRowBuilder().addComponents(...row); + mediaAnnouncementsEmbedWithRows.components.push(actionRow); + }); + + // Send the embeds with attached rows + await interaction.channel.send(interestedInEmbedWithRows); + await interaction.channel.send(mediaAnnouncementsEmbedWithRows); + + await interaction.reply({ content: 'Role assignment embeds sent.', ephemeral: true }); }); diff --git a/src/commands/moderation/rules.ts b/src/commands/moderation/rules.ts index 7cfdd839..8da14c9a 100644 --- a/src/commands/moderation/rules.ts +++ b/src/commands/moderation/rules.ts @@ -2,76 +2,76 @@ import { ApplicationCommandType } from 'discord.js'; import { constantsConfig, slashCommand, slashCommandStructure, makeEmbed, makeLines } from '../../lib'; const data = slashCommandStructure({ - name: 'rules', - description: 'Lists server rules.', - type: ApplicationCommandType.ChatInput, - default_member_permissions: constantsConfig.commandPermission.MANAGE_SERVER, //Overrides need to be added for admin and moderator - dm_permission: false, + name: 'rules', + description: 'Lists server rules.', + type: ApplicationCommandType.ChatInput, + default_member_permissions: constantsConfig.commandPermission.MANAGE_SERVER, //Overrides need to be added for admin and moderator + dm_permission: false, }); const RULES_EMBED = makeEmbed({ - title: 'FlyByWire Simulations Server Rules', - description: makeLines([ - 'Below are the rules you must follow to participate in this discord server. Failure to abide by these rules could result in a removal from the server. Mute/ban evasions will result in a permanent ban.', - '', - `The <@&${constantsConfig.roles.MODERATION_TEAM}> reserve the right to action at discretion.`, - ]), + title: 'FlyByWire Simulations Server Rules', + description: makeLines([ + 'Below are the rules you must follow to participate in this discord server. Failure to abide by these rules could result in a removal from the server. Mute/ban evasions will result in a permanent ban.', + '', + `The <@&${constantsConfig.roles.MODERATION_TEAM}> reserve the right to action at discretion.`, + ]), }); const FAQ_EMBED = makeEmbed({ - title: '<:question:759405702044975114> Frequently Asked Questions', - description: `Check the <#${constantsConfig.channels.FAQ}> for the answers to your questions prior to asking in the channels below, post your question in the appropriate channel.`, + title: '<:question:759405702044975114> Frequently Asked Questions', + description: `Check the <#${constantsConfig.channels.FAQ}> for the answers to your questions prior to asking in the channels below, post your question in the appropriate channel.`, }); const POLICIES_EMBED = makeEmbed({ - title: '<:bookmark_tabs:759405704644788256> Discord Policies', - description: 'Whilst using Discord, you are subject to both the Terms of Service, and its Community Guidelines:', - fields: [ - { - name: 'ToS -', - value: 'https://discordapp.com/terms', - }, - { - name: 'Guidelines -', - value: 'https://discordapp.com/guidelines', - }, - ], + title: '<:bookmark_tabs:759405704644788256> Discord Policies', + description: 'Whilst using Discord, you are subject to both the Terms of Service, and its Community Guidelines:', + fields: [ + { + name: 'ToS -', + value: 'https://discordapp.com/terms', + }, + { + name: 'Guidelines -', + value: 'https://discordapp.com/guidelines', + }, + ], }); const DISCUSSION_EMBED = makeEmbed({ - title: '<:speech_balloon:759405706804723742> Appropriate Discussion', - description: makeLines([ - 'The prime purpose of this server is to discuss flight sim and aviation topics. Respectful and friendly discussions of general topics in the server are welcome; however, we expect everyone to follow Discord policies and good housekeeping.', - '', - '- If you have a message, please post it in the appropriate channel', - '- Send your message once; do not repeat messages', - '- Do not send malicious or illegal content', - '- Use of slurs or any form of bigotry is not tolerated', - '- No inappropriate, NSFW or NSFL content like (but not limited to) nudity, pornography, gore, ...', - '- No general spam', - "- Do not send multiple unsolicited DM's", - '- No troll or insensitive messaging, including insensitive inside jokes', - '- Inappropriate/offensive profile information/picture will not be tolerated', - '- Certain topics like politics, religion and other sensitive subjects will only be tolerated if a careful and respectful conversation is held', - `- Self promotion is not permitted except in the case of YouTube/Twitch content etc. which can be promoted in <#${constantsConfig.channels.VIDEOS}>`, - '- To help with moderation and set a standard the server language is English', - '', - 'Moderators and admins will intervene when there is a risk for escalation or when the situation requires to keep the server friendly and tolerant.', - ]), + title: '<:speech_balloon:759405706804723742> Appropriate Discussion', + description: makeLines([ + 'The prime purpose of this server is to discuss flight sim and aviation topics. Respectful and friendly discussions of general topics in the server are welcome; however, we expect everyone to follow Discord policies and good housekeeping.', + '', + '- If you have a message, please post it in the appropriate channel', + '- Send your message once; do not repeat messages', + '- Do not send malicious or illegal content', + '- Use of slurs or any form of bigotry is not tolerated', + '- No inappropriate, NSFW or NSFL content like (but not limited to) nudity, pornography, gore, ...', + '- No general spam', + "- Do not send multiple unsolicited DM's", + '- No troll or insensitive messaging, including insensitive inside jokes', + '- Inappropriate/offensive profile information/picture will not be tolerated', + '- Certain topics like politics, religion and other sensitive subjects will only be tolerated if a careful and respectful conversation is held', + `- Self promotion is not permitted except in the case of YouTube/Twitch content etc. which can be promoted in <#${constantsConfig.channels.VIDEOS}>`, + '- To help with moderation and set a standard the server language is English', + '', + 'Moderators and admins will intervene when there is a risk for escalation or when the situation requires to keep the server friendly and tolerant.', + ]), }); const ROLE_EMBED = makeEmbed({ - title: '<:person_raising_hand:759405708994281493> Role Assignment', - description: `We encourage people to use their vast experience and knowledge to help us create a highly detailed addon. If you have skills in Documentation, Modelling and/or Programming, please assign your <#${constantsConfig.channels.ROLES}> and get started with the conversation to help us develop the addon.`, + title: '<:person_raising_hand:759405708994281493> Role Assignment', + description: `We encourage people to use their vast experience and knowledge to help us create a highly detailed addon. If you have skills in Documentation, Modelling and/or Programming, please assign your <#${constantsConfig.channels.ROLES}> and get started with the conversation to help us develop the addon.`, }); export default slashCommand(data, async ({ interaction }) => { - if (interaction.channel) { - await interaction.channel.send({ - embeds: [RULES_EMBED, FAQ_EMBED, POLICIES_EMBED, DISCUSSION_EMBED, ROLE_EMBED], - }); - } else { - await interaction.reply({ content: 'This command can only be used in a server.', ephemeral: true }); - } - await interaction.reply({ content: 'Rules sent.', ephemeral: true }); + if (interaction.channel) { + await interaction.channel.send({ + embeds: [RULES_EMBED, FAQ_EMBED, POLICIES_EMBED, DISCUSSION_EMBED, ROLE_EMBED], + }); + } else { + await interaction.reply({ content: 'This command can only be used in a server.', ephemeral: true }); + } + await interaction.reply({ content: 'Rules sent.', ephemeral: true }); }); diff --git a/src/commands/moderation/slowmode/functions/disable.ts b/src/commands/moderation/slowmode/functions/disable.ts index f9f3fb30..290786c0 100644 --- a/src/commands/moderation/slowmode/functions/disable.ts +++ b/src/commands/moderation/slowmode/functions/disable.ts @@ -2,47 +2,47 @@ import { ChannelType, ChatInputCommandInteraction, Colors } from 'discord.js'; import { Logger } from '../../../../lib'; export async function handleDisableSlowmode( - interaction: ChatInputCommandInteraction<'cached'>, - slowmodeChannel: any, - modLogsChannel: any, - scheduler: any, - failedEmbed: any, - noChannelEmbed: any, - successEmbed: any, - modLogEmbed: any, - slowModeEmbedField: any, + interaction: ChatInputCommandInteraction<'cached'>, + slowmodeChannel: any, + modLogsChannel: any, + scheduler: any, + failedEmbed: any, + noChannelEmbed: any, + successEmbed: any, + modLogEmbed: any, + slowModeEmbedField: any, ) { - try { - if ( - slowmodeChannel.type === ChannelType.GuildForum || - slowmodeChannel.type === ChannelType.GuildText || - slowmodeChannel.type === ChannelType.PrivateThread || - slowmodeChannel.type === ChannelType.PublicThread - ) { - await slowmodeChannel.setRateLimitPerUser(0, 'Slow mode disabled through bot'); - if (scheduler) { - await scheduler.cancel({ name: 'autoDisableSlowMode', data: { channelId: slowmodeChannel.id } }); - } - } - } catch (error) { - Logger.error(error); - await interaction.reply({ embeds: [failedEmbed('Disable', slowmodeChannel.id)] }); - return; + try { + if ( + slowmodeChannel.type === ChannelType.GuildForum || + slowmodeChannel.type === ChannelType.GuildText || + slowmodeChannel.type === ChannelType.PrivateThread || + slowmodeChannel.type === ChannelType.PublicThread + ) { + await slowmodeChannel.setRateLimitPerUser(0, 'Slow mode disabled through bot'); + if (scheduler) { + await scheduler.cancel({ name: 'autoDisableSlowMode', data: { channelId: slowmodeChannel.id } }); + } } + } catch (error) { + Logger.error(error); + await interaction.reply({ embeds: [failedEmbed('Disable', slowmodeChannel.id)] }); + return; + } - try { - await modLogsChannel.send({ - embeds: [ - modLogEmbed( - 'disabled', - slowModeEmbedField(interaction.user.toString(), slowmodeChannel.id, 0, 0), - Colors.Green, - ), - ], - }); - } catch { - await interaction.reply({ embeds: [noChannelEmbed('Disable', 'Mod Log')] }); - } + try { + await modLogsChannel.send({ + embeds: [ + modLogEmbed( + 'disabled', + slowModeEmbedField(interaction.user.toString(), slowmodeChannel.id, 0, 0), + Colors.Green, + ), + ], + }); + } catch { + await interaction.reply({ embeds: [noChannelEmbed('Disable', 'Mod Log')] }); + } - await interaction.reply({ embeds: [successEmbed('Disable', slowmodeChannel.id)], ephemeral: true }); + await interaction.reply({ embeds: [successEmbed('Disable', slowmodeChannel.id)], ephemeral: true }); } diff --git a/src/commands/moderation/slowmode/functions/set.ts b/src/commands/moderation/slowmode/functions/set.ts index e31199f7..bf4e83c1 100644 --- a/src/commands/moderation/slowmode/functions/set.ts +++ b/src/commands/moderation/slowmode/functions/set.ts @@ -1,58 +1,58 @@ import { ChannelType, ChatInputCommandInteraction, Colors } from 'discord.js'; export async function handleSetSlowmode( - interaction: ChatInputCommandInteraction<'cached'>, - duration: number, - slowmodeChannel: any, - autoDisable: any, - modLogsChannel: any, - scheduler: any, - failedEmbed: any, - noChannelEmbed: any, - successEmbed: any, - modLogEmbed: any, - slowModeEmbedField: any, + interaction: ChatInputCommandInteraction<'cached'>, + duration: number, + slowmodeChannel: any, + autoDisable: any, + modLogsChannel: any, + scheduler: any, + failedEmbed: any, + noChannelEmbed: any, + successEmbed: any, + modLogEmbed: any, + slowModeEmbedField: any, ) { - try { - if ( - slowmodeChannel.type === ChannelType.GuildForum || - slowmodeChannel.type === ChannelType.GuildText || - slowmodeChannel.type === ChannelType.PrivateThread || - slowmodeChannel.type === ChannelType.PublicThread - ) { - await slowmodeChannel.setRateLimitPerUser(duration / 1000, 'Slow mode enabled through bot'); - if (scheduler) { - await scheduler.cancel({ name: 'autoDisableSlowMode', data: { channelId: slowmodeChannel.id } }); - if (autoDisable) { - const executionDate: Date = new Date(Date.now() + autoDisable); - await scheduler.schedule(executionDate, 'autoDisableSlowMode', { channelId: slowmodeChannel.id }); - } - } + try { + if ( + slowmodeChannel.type === ChannelType.GuildForum || + slowmodeChannel.type === ChannelType.GuildText || + slowmodeChannel.type === ChannelType.PrivateThread || + slowmodeChannel.type === ChannelType.PublicThread + ) { + await slowmodeChannel.setRateLimitPerUser(duration / 1000, 'Slow mode enabled through bot'); + if (scheduler) { + await scheduler.cancel({ name: 'autoDisableSlowMode', data: { channelId: slowmodeChannel.id } }); + if (autoDisable) { + const executionDate: Date = new Date(Date.now() + autoDisable); + await scheduler.schedule(executionDate, 'autoDisableSlowMode', { channelId: slowmodeChannel.id }); } - } catch { - await interaction.reply({ embeds: [failedEmbed('set', slowmodeChannel.id)], ephemeral: true }); - return; + } } + } catch { + await interaction.reply({ embeds: [failedEmbed('set', slowmodeChannel.id)], ephemeral: true }); + return; + } - try { - await modLogsChannel.send({ - embeds: [ - modLogEmbed( - 'Set', - slowModeEmbedField( - interaction.user.toString(), - slowmodeChannel.id, - duration, - autoDisable && scheduler ? autoDisable.toString() : 0, - ), - Colors.Green, - ), - ], - }); - } catch { - await interaction.reply({ embeds: [noChannelEmbed('set', 'mod logs')], ephemeral: true }); - return; - } + try { + await modLogsChannel.send({ + embeds: [ + modLogEmbed( + 'Set', + slowModeEmbedField( + interaction.user.toString(), + slowmodeChannel.id, + duration, + autoDisable && scheduler ? autoDisable.toString() : 0, + ), + Colors.Green, + ), + ], + }); + } catch { + await interaction.reply({ embeds: [noChannelEmbed('set', 'mod logs')], ephemeral: true }); + return; + } - await interaction.reply({ embeds: [successEmbed('set', slowmodeChannel.id)], ephemeral: true }); + await interaction.reply({ embeds: [successEmbed('set', slowmodeChannel.id)], ephemeral: true }); } diff --git a/src/commands/moderation/slowmode/slowmode.ts b/src/commands/moderation/slowmode/slowmode.ts index 85522a0b..1c863f8a 100644 --- a/src/commands/moderation/slowmode/slowmode.ts +++ b/src/commands/moderation/slowmode/slowmode.ts @@ -1,197 +1,197 @@ import { ApplicationCommandOptionType, ApplicationCommandType, Colors, EmbedField, TextChannel } from 'discord.js'; import { - constantsConfig, - slashCommand, - slashCommandStructure, - makeEmbed, - durationInEnglish, - getScheduler, + constantsConfig, + slashCommand, + slashCommandStructure, + makeEmbed, + durationInEnglish, + getScheduler, } from '../../../lib'; import { handleSetSlowmode } from './functions/set'; import { handleDisableSlowmode } from './functions/disable'; const data = slashCommandStructure({ - name: 'slowmode', - description: 'Command to manage slowmode.', - type: ApplicationCommandType.ChatInput, - default_member_permissions: constantsConfig.commandPermission.MANAGE_SERVER, //Overrides need to be added for admin and moderator roles - dm_permission: false, - options: [ + name: 'slowmode', + description: 'Command to manage slowmode.', + type: ApplicationCommandType.ChatInput, + default_member_permissions: constantsConfig.commandPermission.MANAGE_SERVER, //Overrides need to be added for admin and moderator roles + dm_permission: false, + options: [ + { + name: 'set', + description: 'Set the slowmode for the channel.', + type: ApplicationCommandOptionType.Subcommand, + options: [ + { + name: 'duration', + description: 'Please provide a duration.', + type: ApplicationCommandOptionType.Number, + required: true, + choices: [ + { name: '5 Seconds', value: 5000 }, + { name: '10 Seconds', value: 10000 }, + { name: '15 Seconds', value: 15000 }, + { name: '30 Seconds', value: 30000 }, + { name: '1 Minute', value: 60000 }, + { name: '5 minutes', value: 300000 }, + { name: '10 minutes', value: 600000 }, + { name: '15 minutes', value: 900000 }, + { name: '30 minutes', value: 1800000 }, + { name: '1 hour', value: 3600000 }, + { name: '3 hours', value: 10800000 }, + { name: '6 hours', value: 21600000 }, + ], + }, { - name: 'set', - description: 'Set the slowmode for the channel.', - type: ApplicationCommandOptionType.Subcommand, - options: [ - { - name: 'duration', - description: 'Please provide a duration.', - type: ApplicationCommandOptionType.Number, - required: true, - choices: [ - { name: '5 Seconds', value: 5000 }, - { name: '10 Seconds', value: 10000 }, - { name: '15 Seconds', value: 15000 }, - { name: '30 Seconds', value: 30000 }, - { name: '1 Minute', value: 60000 }, - { name: '5 minutes', value: 300000 }, - { name: '10 minutes', value: 600000 }, - { name: '15 minutes', value: 900000 }, - { name: '30 minutes', value: 1800000 }, - { name: '1 hour', value: 3600000 }, - { name: '3 hours', value: 10800000 }, - { name: '6 hours', value: 21600000 }, - ], - }, - { - name: 'channel', - description: 'Please provide a channel.', - type: ApplicationCommandOptionType.Channel, - required: false, - }, - { - name: 'auto-disable', - description: 'Please provide a duration.', - type: ApplicationCommandOptionType.Number, - required: false, - choices: [ - { name: '1 Minute', value: 60000 }, - { name: '5 minutes', value: 300000 }, - { name: '10 minutes', value: 600000 }, - { name: '15 minutes', value: 900000 }, - { name: '30 minutes', value: 1800000 }, - { name: '1 hour', value: 3600000 }, - { name: '3 hours', value: 10800000 }, - { name: '6 hours', value: 21600000 }, - { name: '12 hours', value: 43200000 }, - { name: '1 day', value: 86400000 }, - { name: '3 days', value: 259200000 }, - { name: '1 week', value: 604800000 }, - ], - }, - ], + name: 'channel', + description: 'Please provide a channel.', + type: ApplicationCommandOptionType.Channel, + required: false, }, { - name: 'disable', - description: 'Disable the slowmode for the channel.', - type: ApplicationCommandOptionType.Subcommand, - options: [ - { - name: 'channel', - description: 'Please provide a channel.', - type: ApplicationCommandOptionType.Channel, - required: false, - }, - ], + name: 'auto-disable', + description: 'Please provide a duration.', + type: ApplicationCommandOptionType.Number, + required: false, + choices: [ + { name: '1 Minute', value: 60000 }, + { name: '5 minutes', value: 300000 }, + { name: '10 minutes', value: 600000 }, + { name: '15 minutes', value: 900000 }, + { name: '30 minutes', value: 1800000 }, + { name: '1 hour', value: 3600000 }, + { name: '3 hours', value: 10800000 }, + { name: '6 hours', value: 21600000 }, + { name: '12 hours', value: 43200000 }, + { name: '1 day', value: 86400000 }, + { name: '3 days', value: 259200000 }, + { name: '1 week', value: 604800000 }, + ], }, - ], + ], + }, + { + name: 'disable', + description: 'Disable the slowmode for the channel.', + type: ApplicationCommandOptionType.Subcommand, + options: [ + { + name: 'channel', + description: 'Please provide a channel.', + type: ApplicationCommandOptionType.Channel, + required: false, + }, + ], + }, + ], }); const noSchedulerEmbed = makeEmbed({ - title: 'Slow Mode - No scheduler', - description: 'Could not find an active scheduler. No automatic disable can be scheduled.', - color: Colors.Red, + title: 'Slow Mode - No scheduler', + description: 'Could not find an active scheduler. No automatic disable can be scheduled.', + color: Colors.Red, }); const failedEmbed = (action: string, channel: string) => - makeEmbed({ - title: `Slow Mode - ${action} failed`, - description: `Failed to ${action} the slow mode for channel <@${channel}>.`, - color: Colors.Red, - }); + makeEmbed({ + title: `Slow Mode - ${action} failed`, + description: `Failed to ${action} the slow mode for channel <@${channel}>.`, + color: Colors.Red, + }); const modLogEmbed = (action: string, fields: any, color: number) => - makeEmbed({ - title: `Slow Mode - ${action}`, - fields, - color, - }); + makeEmbed({ + title: `Slow Mode - ${action}`, + fields, + color, + }); const slowModeEmbedField = ( - moderator: string, - channel: string, - duration: number, - autoDisable: string, + moderator: string, + channel: string, + duration: number, + autoDisable: string, ): EmbedField[] => [ - { - inline: true, - name: 'Channel', - value: `<#${channel}>`, - }, - { - inline: true, - name: 'Slow mode limit', - value: durationInEnglish(duration), - }, - { - inline: true, - name: 'Auto disable timeout', - value: durationInEnglish(autoDisable), - }, - { - inline: true, - name: 'Moderator', - value: moderator, - }, + { + inline: true, + name: 'Channel', + value: `<#${channel}>`, + }, + { + inline: true, + name: 'Slow mode limit', + value: durationInEnglish(duration), + }, + { + inline: true, + name: 'Auto disable timeout', + value: durationInEnglish(autoDisable), + }, + { + inline: true, + name: 'Moderator', + value: moderator, + }, ]; const noChannelEmbed = (action: string, channelName: string) => - makeEmbed({ - title: `Slow Mode - ${action} - No ${channelName} channel`, - description: `The command was successful, but no message to ${channelName} was sent. Please check the channel still exists.`, - color: Colors.Yellow, - }); + makeEmbed({ + title: `Slow Mode - ${action} - No ${channelName} channel`, + description: `The command was successful, but no message to ${channelName} was sent. Please check the channel still exists.`, + color: Colors.Yellow, + }); const successEmbed = (action: string, channel: string) => - makeEmbed({ - title: `Slow Mode - ${action} successful`, - description: `Slow mode for channel <#${channel}> has been ${action} successfully.`, - color: Colors.Green, - }); + makeEmbed({ + title: `Slow Mode - ${action} successful`, + description: `Slow mode for channel <#${channel}> has been ${action} successfully.`, + color: Colors.Green, + }); export default slashCommand(data, async ({ interaction }) => { - const scheduler = getScheduler(); - if (!scheduler) { - await interaction.reply({ embeds: [noSchedulerEmbed] }); - } + const scheduler = getScheduler(); + if (!scheduler) { + await interaction.reply({ embeds: [noSchedulerEmbed] }); + } - const duration = interaction.options.getNumber('duration')!; - const slowmodeChannel = interaction.options.getChannel('channel')! ?? interaction.channel; - const autoDisable = interaction.options.getNumber('auto-disable'); - const modLogsChannel = interaction.guild.channels.resolve(constantsConfig.channels.MOD_LOGS) as TextChannel; + const duration = interaction.options.getNumber('duration')!; + const slowmodeChannel = interaction.options.getChannel('channel')! ?? interaction.channel; + const autoDisable = interaction.options.getNumber('auto-disable'); + const modLogsChannel = interaction.guild.channels.resolve(constantsConfig.channels.MOD_LOGS) as TextChannel; - const subcommandName = interaction.options.getSubcommand(); + const subcommandName = interaction.options.getSubcommand(); - switch (subcommandName) { - case 'set': - await handleSetSlowmode( - interaction, - duration, - slowmodeChannel, - autoDisable, - modLogsChannel, - scheduler, - failedEmbed, - noChannelEmbed, - successEmbed, - modLogEmbed, - slowModeEmbedField, - ); - break; - case 'disable': - await handleDisableSlowmode( - interaction, - slowmodeChannel, - modLogsChannel, - scheduler, - failedEmbed, - noChannelEmbed, - successEmbed, - modLogEmbed, - slowModeEmbedField, - ); - break; + switch (subcommandName) { + case 'set': + await handleSetSlowmode( + interaction, + duration, + slowmodeChannel, + autoDisable, + modLogsChannel, + scheduler, + failedEmbed, + noChannelEmbed, + successEmbed, + modLogEmbed, + slowModeEmbedField, + ); + break; + case 'disable': + await handleDisableSlowmode( + interaction, + slowmodeChannel, + modLogsChannel, + scheduler, + failedEmbed, + noChannelEmbed, + successEmbed, + modLogEmbed, + slowModeEmbedField, + ); + break; - default: - await interaction.reply({ content: 'Unknown subcommand', ephemeral: true }); - } + default: + await interaction.reply({ content: 'Unknown subcommand', ephemeral: true }); + } }); diff --git a/src/commands/moderation/welcome.ts b/src/commands/moderation/welcome.ts index bb6889c1..8a276fdc 100644 --- a/src/commands/moderation/welcome.ts +++ b/src/commands/moderation/welcome.ts @@ -2,11 +2,11 @@ import { ApplicationCommandType } from 'discord.js'; import { constantsConfig, imageBaseUrl, slashCommand, slashCommandStructure, makeEmbed, makeLines } from '../../lib'; const data = slashCommandStructure({ - name: 'welcome', - description: 'Displays the welcome message for the server.', - type: ApplicationCommandType.ChatInput, - default_member_permissions: constantsConfig.commandPermission.MANAGE_SERVER, //Overrides need to be added for admin and moderator - dm_permission: false, + name: 'welcome', + description: 'Displays the welcome message for the server.', + type: ApplicationCommandType.ChatInput, + default_member_permissions: constantsConfig.commandPermission.MANAGE_SERVER, //Overrides need to be added for admin and moderator + dm_permission: false, }); const HEADER_IMAGE_URL = `${imageBaseUrl}/moderation/welcome_discord_banner.png`; @@ -16,111 +16,111 @@ const HELP_IMAGE_URL = `${imageBaseUrl}/moderation/welcome_help_and_support.png` const IMPORTANT_INFO_IMAGE_URL = `${imageBaseUrl}/moderation/welcome_impt_info.png`; const WELCOME_EMBED = makeEmbed({ - description: makeLines([ - 'Welcome to the **Official Discord Server** of **FlyByWire Simulations!**', - '', - 'The A32NX Project is a community-driven open source project to create a free Airbus A320neo in Microsoft Flight Simulator that is as close to reality as possible. It started out as an enhancement project to the default A320neo and is now proceeding as an independent add-on project aiming to bring the FlyByWire A32NX up to payware-level systems depth and functionality, all for free.', - '', - 'We are also developing an A380 from scratch which will be aiming to produce a high fidelity freeware aircraft.', - '', - `Feel free to download, test, and share your feedback, or if you are interested in developing, assign your <#${constantsConfig.channels.ROLES}>, and get cracking!`, - ]), + description: makeLines([ + 'Welcome to the **Official Discord Server** of **FlyByWire Simulations!**', + '', + 'The A32NX Project is a community-driven open source project to create a free Airbus A320neo in Microsoft Flight Simulator that is as close to reality as possible. It started out as an enhancement project to the default A320neo and is now proceeding as an independent add-on project aiming to bring the FlyByWire A32NX up to payware-level systems depth and functionality, all for free.', + '', + 'We are also developing an A380 from scratch which will be aiming to produce a high fidelity freeware aircraft.', + '', + `Feel free to download, test, and share your feedback, or if you are interested in developing, assign your <#${constantsConfig.channels.ROLES}>, and get cracking!`, + ]), }); const SOCIAL_EMBED = makeEmbed({ - title: '<:Partnered:921520970123059231> FlyByWireSimulations | Socials', - description: makeLines([ - '<:FBW:921521552699310141> ', - '<:Twitter:921521552942571601> ', - '<:Facebook:921521552984539146> ', - '<:Youtube:921521552829329488> ', - '<:Twitch:921521552623804506> ', - ]), + title: '<:Partnered:921520970123059231> FlyByWireSimulations | Socials', + description: makeLines([ + '<:FBW:921521552699310141> ', + '<:Twitter:921521552942571601> ', + '<:Facebook:921521552984539146> ', + '<:Youtube:921521552829329488> ', + '<:Twitch:921521552623804506> ', + ]), }); const SUPPORT_EMBED = makeEmbed({ - title: '<:Partnered:921520970123059231> FlyByWireSimulations | Support Us', - description: makeLines([ - 'You are able to voluntarily support us financially to ensure we are able to cover the costs of servers and developmental resources.', - '', - 'https://opencollective.com/flybywire', - ]), + title: '<:Partnered:921520970123059231> FlyByWireSimulations | Support Us', + description: makeLines([ + 'You are able to voluntarily support us financially to ensure we are able to cover the costs of servers and developmental resources.', + '', + 'https://opencollective.com/flybywire', + ]), }); const IMPORTANT_INFO_EMBED = makeEmbed({ - title: '<:Partnered:921520970123059231> FlyByWireSimulations | Important Info', - description: - 'By being a member of our Discord Server, you agree to the following, and failure to do so can result in removal from the server.', - fields: [ - { - name: 'Appropriate Content', - value: makeLines([ - 'We want to promote a healthy environment in our Discord server. To maintain this, we will not tolerate inappropriate names, profile pictures, messages or emotes that may offend others in the community. Alongside this we do not welcome any form of spam, the distribution or conversation of pirated material, or general disturbances in our channels and voice chat.', - '', - 'Moderators and Admins reserve the right to mute or remove any member they see violating the rules without prior notice.', - '', - 'Avoiding mutes or bans will result in further action being taken to safeguard the Discord community.', - ]), - }, - { - name: 'Discord Policies', - value: makeLines([ - 'Please read the Discord TOS and Guidelines listed below!', - '', - 'Discord Terms of Service & Guidelines', - '', - 'https://discordapp.com/terms', - '', - 'https://discordapp.com/guidelines', - ]), - }, - ], + title: '<:Partnered:921520970123059231> FlyByWireSimulations | Important Info', + description: + 'By being a member of our Discord Server, you agree to the following, and failure to do so can result in removal from the server.', + fields: [ + { + name: 'Appropriate Content', + value: makeLines([ + 'We want to promote a healthy environment in our Discord server. To maintain this, we will not tolerate inappropriate names, profile pictures, messages or emotes that may offend others in the community. Alongside this we do not welcome any form of spam, the distribution or conversation of pirated material, or general disturbances in our channels and voice chat.', + '', + 'Moderators and Admins reserve the right to mute or remove any member they see violating the rules without prior notice.', + '', + 'Avoiding mutes or bans will result in further action being taken to safeguard the Discord community.', + ]), + }, + { + name: 'Discord Policies', + value: makeLines([ + 'Please read the Discord TOS and Guidelines listed below!', + '', + 'Discord Terms of Service & Guidelines', + '', + 'https://discordapp.com/terms', + '', + 'https://discordapp.com/guidelines', + ]), + }, + ], }); const HELP_EMBED = makeEmbed({ - title: '<:Partnered:921520970123059231> FlyByWireSimulations | Help and Support', - fields: [ - { - name: 'Documentation', - value: 'Guides & Support Information: https://docs.flybywiresim.com/', - }, - { - name: 'FAQ', - value: `Always check <#${constantsConfig.channels.FAQ}>, <#${constantsConfig.channels.KNOWN_ISSUES}>, and our documentation site to see if your question has already been answered. If not head over to <#${constantsConfig.channels.A32NX_SUPPORT}> for assistance.`, - }, - { - name: 'Flight School', - value: `We've opened our <#${constantsConfig.channels.FLIGHT_SCHOOL}> channel for any questions you have pertaining to the operation of the A32NX in the simulator.`, - }, - ], + title: '<:Partnered:921520970123059231> FlyByWireSimulations | Help and Support', + fields: [ + { + name: 'Documentation', + value: 'Guides & Support Information: https://docs.flybywiresim.com/', + }, + { + name: 'FAQ', + value: `Always check <#${constantsConfig.channels.FAQ}>, <#${constantsConfig.channels.KNOWN_ISSUES}>, and our documentation site to see if your question has already been answered. If not head over to <#${constantsConfig.channels.A32NX_SUPPORT}> for assistance.`, + }, + { + name: 'Flight School', + value: `We've opened our <#${constantsConfig.channels.FLIGHT_SCHOOL}> channel for any questions you have pertaining to the operation of the A32NX in the simulator.`, + }, + ], }); export default slashCommand(data, async ({ interaction }) => { - await interaction.deferReply({ ephemeral: true }); + await interaction.deferReply({ ephemeral: true }); - if (interaction.channel) { - await interaction.channel.send({ files: [HEADER_IMAGE_URL] }); + if (interaction.channel) { + await interaction.channel.send({ files: [HEADER_IMAGE_URL] }); - await interaction.channel.send({ embeds: [WELCOME_EMBED] }); + await interaction.channel.send({ embeds: [WELCOME_EMBED] }); - await interaction.channel.send({ files: [SOCIAL_IMAGE_URL] }); + await interaction.channel.send({ files: [SOCIAL_IMAGE_URL] }); - await interaction.channel.send({ embeds: [SOCIAL_EMBED] }); + await interaction.channel.send({ embeds: [SOCIAL_EMBED] }); - await interaction.channel.send({ files: [SUPPORT_IMAGE_URL] }); + await interaction.channel.send({ files: [SUPPORT_IMAGE_URL] }); - await interaction.channel.send({ embeds: [SUPPORT_EMBED] }); + await interaction.channel.send({ embeds: [SUPPORT_EMBED] }); - await interaction.channel.send({ files: [HELP_IMAGE_URL] }); + await interaction.channel.send({ files: [HELP_IMAGE_URL] }); - await interaction.channel.send({ embeds: [HELP_EMBED] }); + await interaction.channel.send({ embeds: [HELP_EMBED] }); - await interaction.channel.send({ files: [IMPORTANT_INFO_IMAGE_URL] }); + await interaction.channel.send({ files: [IMPORTANT_INFO_IMAGE_URL] }); - await interaction.channel.send({ embeds: [IMPORTANT_INFO_EMBED] }); - } else { - await interaction.followUp({ content: 'This command can only be used in a server.', ephemeral: true }); - } + await interaction.channel.send({ embeds: [IMPORTANT_INFO_EMBED] }); + } else { + await interaction.followUp({ content: 'This command can only be used in a server.', ephemeral: true }); + } - await interaction.followUp({ content: 'Welcome message sent.', ephemeral: true }); + await interaction.followUp({ content: 'Welcome message sent.', ephemeral: true }); }); diff --git a/src/commands/moderation/whois.ts b/src/commands/moderation/whois.ts index 23a3fd5f..46e5e731 100644 --- a/src/commands/moderation/whois.ts +++ b/src/commands/moderation/whois.ts @@ -3,87 +3,87 @@ import moment from 'moment'; import { constantsConfig, slashCommand, slashCommandStructure, makeEmbed } from '../../lib'; const data = slashCommandStructure({ - name: 'whois', - description: 'Provides information about a user.', - type: ApplicationCommandType.ChatInput, - default_member_permissions: constantsConfig.commandPermission.MANAGE_SERVER, //Overrides need to be added for admin and moderator roles - dm_permission: false, - options: [ - { - name: 'tag_or_id', - description: "Provide a user's tag or id to get information about them.", - type: ApplicationCommandOptionType.User, - required: false, - }, - ], + name: 'whois', + description: 'Provides information about a user.', + type: ApplicationCommandType.ChatInput, + default_member_permissions: constantsConfig.commandPermission.MANAGE_SERVER, //Overrides need to be added for admin and moderator roles + dm_permission: false, + options: [ + { + name: 'tag_or_id', + description: "Provide a user's tag or id to get information about them.", + type: ApplicationCommandOptionType.User, + required: false, + }, + ], }); const beautifiedStatus: { [key: string]: string } = { - ONLINE: 'Online', - IDLE: 'Idle', - DND: 'Do Not Disturb', - OFFLINE: 'Offline', + ONLINE: 'Online', + IDLE: 'Idle', + DND: 'Do Not Disturb', + OFFLINE: 'Offline', }; export default slashCommand(data, async ({ interaction }) => { - const targetMember = interaction.options.getMember('tag_or_id') ?? interaction.member; + const targetMember = interaction.options.getMember('tag_or_id') ?? interaction.member; - const filteredRoles = targetMember.roles.cache.filter((role) => role.id !== interaction.guild.id); - const listedRoles = filteredRoles.sort((a, b) => b.position - a.position).map((role) => role.toString()); + const filteredRoles = targetMember.roles.cache.filter((role) => role.id !== interaction.guild.id); + const listedRoles = filteredRoles.sort((a, b) => b.position - a.position).map((role) => role.toString()); - const onlineStatus = beautifiedStatus[targetMember.presence?.status?.toUpperCase() ?? 'OFFLINE']; + const onlineStatus = beautifiedStatus[targetMember.presence?.status?.toUpperCase() ?? 'OFFLINE']; - let status; - if (targetMember.presence == null) { - status = 'Offline'; - } else { - status = onlineStatus; - } + let status; + if (targetMember.presence == null) { + status = 'Offline'; + } else { + status = onlineStatus; + } - const whoisEmbed = makeEmbed({ - author: { - name: targetMember.user.username, - iconURL: targetMember.user.avatarURL()!, - }, - description: `${targetMember}`, - thumbnail: { url: targetMember.user.avatarURL()! }, - fields: [ - { - name: 'Username', - value: targetMember.user.tag, - inline: true, - }, - { - name: 'Status', - value: status, - inline: true, - }, - { - name: 'Joined', - value: moment(targetMember.joinedTimestamp).format('llll'), - inline: true, - }, - { - name: 'Registered', - value: moment(targetMember.user.createdTimestamp).format('llll'), - inline: false, - }, - { - name: 'Roles', - value: `\u200B${listedRoles.join(', ')}`, - }, - { - name: 'Permissions', - value: targetMember.permissions - .toArray() - .join(', ') - .toLowerCase() - .replace(/_/g, ' ') - .replace(/(^\w)|(\s+\w)/g, (char) => char.toUpperCase()), - }, - ], - footer: { text: `User ID: ${targetMember.id}` }, - }); + const whoisEmbed = makeEmbed({ + author: { + name: targetMember.user.username, + iconURL: targetMember.user.avatarURL()!, + }, + description: `${targetMember}`, + thumbnail: { url: targetMember.user.avatarURL()! }, + fields: [ + { + name: 'Username', + value: targetMember.user.tag, + inline: true, + }, + { + name: 'Status', + value: status, + inline: true, + }, + { + name: 'Joined', + value: moment(targetMember.joinedTimestamp).format('llll'), + inline: true, + }, + { + name: 'Registered', + value: moment(targetMember.user.createdTimestamp).format('llll'), + inline: false, + }, + { + name: 'Roles', + value: `\u200B${listedRoles.join(', ')}`, + }, + { + name: 'Permissions', + value: targetMember.permissions + .toArray() + .join(', ') + .toLowerCase() + .replace(/_/g, ' ') + .replace(/(^\w)|(\s+\w)/g, (char) => char.toUpperCase()), + }, + ], + footer: { text: `User ID: ${targetMember.id}` }, + }); - return interaction.reply({ embeds: [whoisEmbed] }); + return interaction.reply({ embeds: [whoisEmbed] }); }); diff --git a/src/commands/utils/avatar.ts b/src/commands/utils/avatar.ts index 6c3f1bb6..0cea08c1 100644 --- a/src/commands/utils/avatar.ts +++ b/src/commands/utils/avatar.ts @@ -2,26 +2,26 @@ import { ApplicationCommandOptionType, ApplicationCommandType } from 'discord.js import { slashCommand, slashCommandStructure, makeEmbed } from '../../lib'; const data = slashCommandStructure({ - name: 'avatar', - description: "Shows the selected user's avatar", - type: ApplicationCommandType.ChatInput, - options: [ - { - name: 'tag_or_id', - description: 'Please provide a user tag or ID.', - type: ApplicationCommandOptionType.User, - required: false, - }, - ], + name: 'avatar', + description: "Shows the selected user's avatar", + type: ApplicationCommandType.ChatInput, + options: [ + { + name: 'tag_or_id', + description: 'Please provide a user tag or ID.', + type: ApplicationCommandOptionType.User, + required: false, + }, + ], }); export default slashCommand(data, async ({ interaction }) => { - const user = interaction.options.getUser('tag_or_id') || interaction.user; + const user = interaction.options.getUser('tag_or_id') || interaction.user; - const avatarEmbed = makeEmbed({ - title: `${user.tag}'s avatar`, - image: { url: user.displayAvatarURL({ size: 4096 }) }, - }); + const avatarEmbed = makeEmbed({ + title: `${user.tag}'s avatar`, + image: { url: user.displayAvatarURL({ size: 4096 }) }, + }); - return interaction.reply({ embeds: [avatarEmbed] }); + return interaction.reply({ embeds: [avatarEmbed] }); }); diff --git a/src/commands/utils/birthday/birthday.ts b/src/commands/utils/birthday/birthday.ts index 1efc77e7..3fbfa2ef 100644 --- a/src/commands/utils/birthday/birthday.ts +++ b/src/commands/utils/birthday/birthday.ts @@ -5,96 +5,96 @@ import { handleListBirthday } from './functions/listBirthday'; import { handleRemoveBirthday } from './functions/removeBirthday'; const data = slashCommandStructure({ - name: 'birthday', - description: 'Command to manage birthdays.', - type: ApplicationCommandType.ChatInput, - default_member_permissions: constantsConfig.commandPermission.MANAGE_SERVER, //Needs overrides adding for team members and lock to birthday thread - dm_permission: false, - options: [ + name: 'birthday', + description: 'Command to manage birthdays.', + type: ApplicationCommandType.ChatInput, + default_member_permissions: constantsConfig.commandPermission.MANAGE_SERVER, //Needs overrides adding for team members and lock to birthday thread + dm_permission: false, + options: [ + { + name: 'set', + description: 'Sets your birthday.', + type: ApplicationCommandOptionType.Subcommand, + options: [ { - name: 'set', - description: 'Sets your birthday.', - type: ApplicationCommandOptionType.Subcommand, - options: [ - { - name: 'day', - description: 'The day of your birthday.', - type: ApplicationCommandOptionType.Integer, - min_value: 1, - max_value: 31, - required: true, - }, - { - name: 'month', - description: 'The month of your birthday.', - type: ApplicationCommandOptionType.Integer, - required: true, - choices: [ - { name: 'January', value: 1 }, - { name: 'February', value: 2 }, - { name: 'March', value: 3 }, - { name: 'April', value: 4 }, - { name: 'May', value: 5 }, - { name: 'June', value: 6 }, - { name: 'July', value: 7 }, - { name: 'August', value: 8 }, - { name: 'September', value: 9 }, - { name: 'October', value: 10 }, - { name: 'November', value: 11 }, - { name: 'December', value: 12 }, - ], - }, - { - name: 'timezone', - description: 'Your timezone in relation to UTC. e.g. 2 or -6.', - type: ApplicationCommandOptionType.Integer, - max_value: +14, - min_value: -12, - required: true, - }, - ], + name: 'day', + description: 'The day of your birthday.', + type: ApplicationCommandOptionType.Integer, + min_value: 1, + max_value: 31, + required: true, }, { - name: 'remove', - description: 'Removes your birthday.', - type: ApplicationCommandOptionType.Subcommand, + name: 'month', + description: 'The month of your birthday.', + type: ApplicationCommandOptionType.Integer, + required: true, + choices: [ + { name: 'January', value: 1 }, + { name: 'February', value: 2 }, + { name: 'March', value: 3 }, + { name: 'April', value: 4 }, + { name: 'May', value: 5 }, + { name: 'June', value: 6 }, + { name: 'July', value: 7 }, + { name: 'August', value: 8 }, + { name: 'September', value: 9 }, + { name: 'October', value: 10 }, + { name: 'November', value: 11 }, + { name: 'December', value: 12 }, + ], }, { - name: 'list', - description: 'Lists all birthdays.', - type: ApplicationCommandOptionType.Subcommand, + name: 'timezone', + description: 'Your timezone in relation to UTC. e.g. 2 or -6.', + type: ApplicationCommandOptionType.Integer, + max_value: +14, + min_value: -12, + required: true, }, - ], + ], + }, + { + name: 'remove', + description: 'Removes your birthday.', + type: ApplicationCommandOptionType.Subcommand, + }, + { + name: 'list', + description: 'Lists all birthdays.', + type: ApplicationCommandOptionType.Subcommand, + }, + ], }); const noConnEmbed = makeEmbed({ - title: 'Birthday - No Connection', - description: 'Could not connect to the database', - color: Colors.Red, + title: 'Birthday - No Connection', + description: 'Could not connect to the database', + color: Colors.Red, }); export default slashCommand(data, async ({ interaction }) => { - const conn = await getConn(); + const conn = await getConn(); - if (!conn) { - await interaction.reply({ embeds: [noConnEmbed], ephemeral: true }); - return; - } + if (!conn) { + await interaction.reply({ embeds: [noConnEmbed], ephemeral: true }); + return; + } - const subcommandName = interaction.options.getSubcommand(); + const subcommandName = interaction.options.getSubcommand(); - switch (subcommandName) { - case 'set': - await handleSetBirthday(interaction); - break; - case 'remove': - await handleRemoveBirthday(interaction); - break; - case 'list': - await handleListBirthday(interaction); - break; + switch (subcommandName) { + case 'set': + await handleSetBirthday(interaction); + break; + case 'remove': + await handleRemoveBirthday(interaction); + break; + case 'list': + await handleListBirthday(interaction); + break; - default: - await interaction.reply({ content: 'Unknown subcommand', ephemeral: true }); - } + default: + await interaction.reply({ content: 'Unknown subcommand', ephemeral: true }); + } }); diff --git a/src/commands/utils/birthday/functions/listBirthday.ts b/src/commands/utils/birthday/functions/listBirthday.ts index 9dfe9359..acdbafb7 100644 --- a/src/commands/utils/birthday/functions/listBirthday.ts +++ b/src/commands/utils/birthday/functions/listBirthday.ts @@ -2,58 +2,58 @@ import { ChatInputCommandInteraction } from 'discord.js'; import { Birthday, Logger, makeEmbed } from '../../../../lib'; const birthdayListEmbed = (fields: Array) => - makeEmbed({ - title: 'Birthday - Birthday List', - description: fields.length > 0 ? undefined : 'No birthdays set', - fields, - }); + makeEmbed({ + title: 'Birthday - Birthday List', + description: fields.length > 0 ? undefined : 'No birthdays set', + fields, + }); export async function handleListBirthday(interaction: ChatInputCommandInteraction<'cached'>) { - await interaction.deferReply(); - - try { - const birthdays = await Birthday.find({}).sort({ day: 1 }); // Only day sort required, months are bucketized - const members = await interaction.guild!.members.fetch(); - - const monthBuckets: Array> = [ - ['January', []], - ['February', []], - ['March', []], - ['April', []], - ['May', []], - ['June', []], - ['July', []], - ['August', []], - ['September', []], - ['October', []], - ['November', []], - ['December', []], - ]; - - for (const birthday of birthdays) { - const member = members.get(birthday.userID!); - - if (member) { - monthBuckets[birthday.utcDatetime!.getUTCMonth()][1].push( - `${member.displayName} - ${birthday.day}/${birthday.month} (Z${birthday.timezone! < 0 ? '' : '+'}${birthday.timezone})`, - ); - } - } - - const fields = []; - - for (const monthBucket of monthBuckets) { - if (monthBucket[1].length > 0) { - fields.push({ - name: monthBucket[0], - value: monthBucket[1].join('\n'), - }); - } - } - - await interaction.editReply({ embeds: [birthdayListEmbed(fields)] }); - } catch (error) { - Logger.error(error); - await interaction.followUp({ content: 'An error occurred while processing this command.', ephemeral: true }); + await interaction.deferReply(); + + try { + const birthdays = await Birthday.find({}).sort({ day: 1 }); // Only day sort required, months are bucketized + const members = await interaction.guild!.members.fetch(); + + const monthBuckets: Array> = [ + ['January', []], + ['February', []], + ['March', []], + ['April', []], + ['May', []], + ['June', []], + ['July', []], + ['August', []], + ['September', []], + ['October', []], + ['November', []], + ['December', []], + ]; + + for (const birthday of birthdays) { + const member = members.get(birthday.userID!); + + if (member) { + monthBuckets[birthday.utcDatetime!.getUTCMonth()][1].push( + `${member.displayName} - ${birthday.day}/${birthday.month} (Z${birthday.timezone! < 0 ? '' : '+'}${birthday.timezone})`, + ); + } } + + const fields = []; + + for (const monthBucket of monthBuckets) { + if (monthBucket[1].length > 0) { + fields.push({ + name: monthBucket[0], + value: monthBucket[1].join('\n'), + }); + } + } + + await interaction.editReply({ embeds: [birthdayListEmbed(fields)] }); + } catch (error) { + Logger.error(error); + await interaction.followUp({ content: 'An error occurred while processing this command.', ephemeral: true }); + } } diff --git a/src/commands/utils/birthday/functions/removeBirthday.ts b/src/commands/utils/birthday/functions/removeBirthday.ts index a2d6d90b..a891bb09 100644 --- a/src/commands/utils/birthday/functions/removeBirthday.ts +++ b/src/commands/utils/birthday/functions/removeBirthday.ts @@ -2,28 +2,28 @@ import { ChatInputCommandInteraction, Colors, User } from 'discord.js'; import { Birthday, makeEmbed } from '../../../../lib'; const noBirthdayEmbed = (discordUser: User) => - makeEmbed({ - title: 'Birthday remove failed', - description: `${discordUser} doesn't have a birthday set`, - color: Colors.Red, - }); + makeEmbed({ + title: 'Birthday remove failed', + description: `${discordUser} doesn't have a birthday set`, + color: Colors.Red, + }); const birthdayRemovedEmbed = (discordUser: User) => - makeEmbed({ - title: 'Birthday removed', - description: `${discordUser}'s birthday has been removed`, - }); + makeEmbed({ + title: 'Birthday removed', + description: `${discordUser}'s birthday has been removed`, + }); export async function handleRemoveBirthday(interaction: ChatInputCommandInteraction<'cached'>) { - const userID = interaction.user.id; - const discordUser = interaction.user; + const userID = interaction.user.id; + const discordUser = interaction.user; - const birthday = await Birthday.findOne({ userID }); + const birthday = await Birthday.findOne({ userID }); - if (!birthday) { - await interaction.reply({ embeds: [noBirthdayEmbed(discordUser)] }); - } else { - await Birthday.deleteOne({ userID }); - await interaction.reply({ embeds: [birthdayRemovedEmbed(discordUser)] }); - } + if (!birthday) { + await interaction.reply({ embeds: [noBirthdayEmbed(discordUser)] }); + } else { + await Birthday.deleteOne({ userID }); + await interaction.reply({ embeds: [birthdayRemovedEmbed(discordUser)] }); + } } diff --git a/src/commands/utils/birthday/functions/setBirthday.ts b/src/commands/utils/birthday/functions/setBirthday.ts index e55879db..682fcb38 100644 --- a/src/commands/utils/birthday/functions/setBirthday.ts +++ b/src/commands/utils/birthday/functions/setBirthday.ts @@ -2,85 +2,85 @@ import { ChatInputCommandInteraction, Colors, User } from 'discord.js'; import { Birthday, makeEmbed } from '../../../../lib'; function isDateValid(day: number, month: number) { - if (month < 1 || month > 12) { - return false; + if (month < 1 || month > 12) { + return false; + } + + if (day < 1) { + return false; + } + + if (month === 2) { + // Check for February + if (day > 29) { + return false; } - - if (day < 1) { - return false; - } - - if (month === 2) { - // Check for February - if (day > 29) { - return false; - } - } else if ((month <= 7 && month % 2 === 0) || (month >= 8 && month % 2 === 1)) { - // Check for months with 30 days - if (day > 30) { - return false; - } + } else if ((month <= 7 && month % 2 === 0) || (month >= 8 && month % 2 === 1)) { + // Check for months with 30 days + if (day > 30) { + return false; } + } - return true; + return true; } const invalidDateEmbed = makeEmbed({ - title: 'Birthday - Invalid Date', - description: 'Please provide a valid date.', - color: Colors.Red, + title: 'Birthday - Invalid Date', + description: 'Please provide a valid date.', + color: Colors.Red, }); const birthdaySetEmbed = (discordUser: User, birthdayDay: number, birthdayMonth: number, birthdayTimezone: number) => - makeEmbed({ - title: 'Birthday - Birthday Set', - description: `${discordUser}'s birthday has been set to ${birthdayDay}/${birthdayMonth} and their timezone is UTC${birthdayTimezone < 0 ? '' : '+'}${birthdayTimezone}`, - }); + makeEmbed({ + title: 'Birthday - Birthday Set', + description: `${discordUser}'s birthday has been set to ${birthdayDay}/${birthdayMonth} and their timezone is UTC${birthdayTimezone < 0 ? '' : '+'}${birthdayTimezone}`, + }); export async function handleSetBirthday(interaction: ChatInputCommandInteraction<'cached'>) { - const selectedDay = interaction.options.getInteger('day')!; - const selectedMonth = interaction.options.getInteger('month')!; - const selectedTimezone = interaction.options.getInteger('timezone')!; - - if (!isDateValid(selectedDay, selectedMonth)) { - await interaction.reply({ embeds: [invalidDateEmbed], ephemeral: true }); - return; - } - - const userID = interaction.user.id; - const discordUser = interaction.user; - - // Determine UTC datetime to send birthday message - - const currentDate = new Date(); - const utcDatetime = new Date(Date.UTC(currentDate.getUTCFullYear(), selectedMonth - 1, selectedDay)); - utcDatetime.setUTCHours(10 - selectedTimezone); - - let birthdayDoc = await Birthday.findOne({ userID }); - - if (birthdayDoc) { - birthdayDoc.month = selectedMonth; - birthdayDoc.day = selectedDay; - birthdayDoc.utcDatetime = utcDatetime; - birthdayDoc.timezone = selectedTimezone; - } else { - birthdayDoc = new Birthday({ - userID, - month: selectedMonth, - day: selectedDay, - utcDatetime, - timezone: selectedTimezone, - }); - } + const selectedDay = interaction.options.getInteger('day')!; + const selectedMonth = interaction.options.getInteger('month')!; + const selectedTimezone = interaction.options.getInteger('timezone')!; + + if (!isDateValid(selectedDay, selectedMonth)) { + await interaction.reply({ embeds: [invalidDateEmbed], ephemeral: true }); + return; + } + + const userID = interaction.user.id; + const discordUser = interaction.user; + + // Determine UTC datetime to send birthday message + + const currentDate = new Date(); + const utcDatetime = new Date(Date.UTC(currentDate.getUTCFullYear(), selectedMonth - 1, selectedDay)); + utcDatetime.setUTCHours(10 - selectedTimezone); + + let birthdayDoc = await Birthday.findOne({ userID }); + + if (birthdayDoc) { + birthdayDoc.month = selectedMonth; + birthdayDoc.day = selectedDay; + birthdayDoc.utcDatetime = utcDatetime; + birthdayDoc.timezone = selectedTimezone; + } else { + birthdayDoc = new Birthday({ + userID, + month: selectedMonth, + day: selectedDay, + utcDatetime, + timezone: selectedTimezone, + }); + } - // If birthday already passed this year then set next year's birthday + // If birthday already passed this year then set next year's birthday - if (currentDate > utcDatetime) { - utcDatetime.setUTCFullYear(utcDatetime.getUTCFullYear() + 1); - birthdayDoc.utcDatetime = utcDatetime; - } + if (currentDate > utcDatetime) { + utcDatetime.setUTCFullYear(utcDatetime.getUTCFullYear() + 1); + birthdayDoc.utcDatetime = utcDatetime; + } - await birthdayDoc.save(); + await birthdayDoc.save(); - await interaction.reply({ embeds: [birthdaySetEmbed(discordUser, selectedDay, selectedMonth, selectedTimezone)] }); + await interaction.reply({ embeds: [birthdaySetEmbed(discordUser, selectedDay, selectedMonth, selectedTimezone)] }); } diff --git a/src/commands/utils/count.ts b/src/commands/utils/count.ts index 0ca98801..5bc7447a 100644 --- a/src/commands/utils/count.ts +++ b/src/commands/utils/count.ts @@ -2,39 +2,39 @@ import { ApplicationCommandOptionType, ApplicationCommandType, TextChannel } fro import { constantsConfig, slashCommand, slashCommandStructure } from '../../lib'; const data = slashCommandStructure({ - name: 'count', - description: 'Counts for me.', - type: ApplicationCommandType.ChatInput, - default_member_permissions: constantsConfig.commandPermission.MANAGE_SERVER, // Overrides needed for bot dev team - options: [ - { - name: 'number', - description: 'The number to count as.', - type: ApplicationCommandOptionType.Integer, - required: true, - }, - ], + name: 'count', + description: 'Counts for me.', + type: ApplicationCommandType.ChatInput, + default_member_permissions: constantsConfig.commandPermission.MANAGE_SERVER, // Overrides needed for bot dev team + options: [ + { + name: 'number', + description: 'The number to count as.', + type: ApplicationCommandOptionType.Integer, + required: true, + }, + ], }); export default slashCommand(data, async ({ interaction }) => { - // check if user has the role - const hasRole = interaction.member.roles.cache.has(constantsConfig.roles.BOT_DEVELOPER); + // check if user has the role + const hasRole = interaction.member.roles.cache.has(constantsConfig.roles.BOT_DEVELOPER); - if (!hasRole) { - await interaction.reply({ content: 'Go count yourself ;)', ephemeral: true }); - return; - } + if (!hasRole) { + await interaction.reply({ content: 'Go count yourself ;)', ephemeral: true }); + return; + } - const countThread = interaction.guild.channels.resolve(constantsConfig.threads.COUNT_THREAD) as TextChannel | null; + const countThread = interaction.guild.channels.resolve(constantsConfig.threads.COUNT_THREAD) as TextChannel | null; - if (!countThread) { - await interaction.reply({ content: 'Count thread not found.', ephemeral: true }); - return; - } + if (!countThread) { + await interaction.reply({ content: 'Count thread not found.', ephemeral: true }); + return; + } - const countNumber = interaction.options.getInteger('number'); + const countNumber = interaction.options.getInteger('number'); - await countThread.send(`${interaction.user} says ${countNumber}`); + await countThread.send(`${interaction.user} says ${countNumber}`); - await interaction.reply({ content: 'Counted!', ephemeral: true }); + await interaction.reply({ content: 'Counted!', ephemeral: true }); }); diff --git a/src/commands/utils/docSearch.ts b/src/commands/utils/docSearch.ts index fc941422..f87d1639 100644 --- a/src/commands/utils/docSearch.ts +++ b/src/commands/utils/docSearch.ts @@ -3,60 +3,60 @@ import Filter from 'bad-words'; import { slashCommand, slashCommandStructure, makeEmbed } from '../../lib'; const data = slashCommandStructure({ - name: 'doc-search', - description: 'Searches the FlyByWire Documentation for a given query.', - type: ApplicationCommandType.ChatInput, - options: [ - { - name: 'query', - description: 'The query to search for.', - type: ApplicationCommandOptionType.String, - max_length: 100, - required: true, - }, - ], + name: 'doc-search', + description: 'Searches the FlyByWire Documentation for a given query.', + type: ApplicationCommandType.ChatInput, + options: [ + { + name: 'query', + description: 'The query to search for.', + type: ApplicationCommandOptionType.String, + max_length: 100, + required: true, + }, + ], }); const DOCS_BASE_URL = 'https://docs.flybywiresim.com'; export default slashCommand(data, async ({ interaction }) => { - const query = interaction.options.getString('query')!; - - // Separates the query into an array. - const words = query.split(/\s+/); - - // Itterate through the array and check if any of the words are a URL. Then check if any of the words are profanity. - for (const searchWord of words) { - try { - const _ = new URL(searchWord); - const URLEmbed = makeEmbed({ - title: 'FlyByWire Documentation | Error', - description: 'Providing URLs to the Documentation search command is not allowed.', - color: Colors.Red, - }); - return interaction.reply({ embeds: [URLEmbed] }); - } catch (_) { - /**/ - } - - const filter = new Filter(); - if (filter.isProfane(searchWord)) { - const profanityEmbed = makeEmbed({ - title: 'FlyByWire Documentation | Error', - description: 'Providing profanity to the Documentation search command is not allowed.', - color: Colors.Red, - }); - - return interaction.reply({ embeds: [profanityEmbed] }); - } + const query = interaction.options.getString('query')!; + + // Separates the query into an array. + const words = query.split(/\s+/); + + // Itterate through the array and check if any of the words are a URL. Then check if any of the words are profanity. + for (const searchWord of words) { + try { + const _ = new URL(searchWord); + const URLEmbed = makeEmbed({ + title: 'FlyByWire Documentation | Error', + description: 'Providing URLs to the Documentation search command is not allowed.', + color: Colors.Red, + }); + return interaction.reply({ embeds: [URLEmbed] }); + } catch (_) { + /**/ } - // Safety to prevent users from entering unexpected data that might result in strange behavior in a URL. - const encodedSearchQuery = encodeURIComponent(query); + const filter = new Filter(); + if (filter.isProfane(searchWord)) { + const profanityEmbed = makeEmbed({ + title: 'FlyByWire Documentation | Error', + description: 'Providing profanity to the Documentation search command is not allowed.', + color: Colors.Red, + }); - const queryEmbed = makeEmbed({ - title: 'FlyByWire Documentation Search', - description: `Search the FlyByWire Documentation for "${query}" [here](${DOCS_BASE_URL}/?q=${encodedSearchQuery}).`, - }); - return interaction.reply({ embeds: [queryEmbed] }); + return interaction.reply({ embeds: [profanityEmbed] }); + } + } + + // Safety to prevent users from entering unexpected data that might result in strange behavior in a URL. + const encodedSearchQuery = encodeURIComponent(query); + + const queryEmbed = makeEmbed({ + title: 'FlyByWire Documentation Search', + description: `Search the FlyByWire Documentation for "${query}" [here](${DOCS_BASE_URL}/?q=${encodedSearchQuery}).`, + }); + return interaction.reply({ embeds: [queryEmbed] }); }); diff --git a/src/commands/utils/github/functions/githubPullRequest.ts b/src/commands/utils/github/functions/githubPullRequest.ts index f656d479..84ed6faf 100644 --- a/src/commands/utils/github/functions/githubPullRequest.ts +++ b/src/commands/utils/github/functions/githubPullRequest.ts @@ -5,42 +5,42 @@ import { makeEmbed } from '../../../../lib'; const syntaxHelp = '\nSyntax:\nAircraft repo: `/github pr `\nAny FBW repo: `/github pr `'; const noQueryEmbed = makeEmbed({ - title: 'PR Error | Missing Query', - description: `Invalid command!${syntaxHelp}`, - color: Colors.Red, + title: 'PR Error | Missing Query', + description: `Invalid command!${syntaxHelp}`, + color: Colors.Red, }); const invalidEmbed = makeEmbed({ - title: 'PR Error | Invalid', - description: `Something went wrong! Did you provide the correct repo/PR id?${syntaxHelp}`, - color: Colors.Red, + title: 'PR Error | Invalid', + description: `Something went wrong! Did you provide the correct repo/PR id?${syntaxHelp}`, + color: Colors.Red, }); export async function handleGithubPullRequest(interaction: ChatInputCommandInteraction<'cached'>) { - const prNumber = interaction.options.getString('pr_number'); - const repoName = interaction.options.getString('repo'); + const prNumber = interaction.options.getString('pr_number'); + const repoName = interaction.options.getString('repo'); - if (!prNumber) return interaction.reply({ embeds: [noQueryEmbed] }); + if (!prNumber) return interaction.reply({ embeds: [noQueryEmbed] }); - const cleanedPrNumber = prNumber.replace('#', ''); + const cleanedPrNumber = prNumber.replace('#', ''); - if (repoName) { - try { - const response = await request('GET /repos/flybywiresim/{repo}/pulls/{pull_number}', { - repo: repoName, - pull_number: cleanedPrNumber, - }); - return interaction.reply(response.data.html_url); - } catch { - return interaction.reply({ embeds: [invalidEmbed] }); - } - } else { - try { - const response = await request('GET /repos/flybywiresim/a32nx/pulls/{pull_number}', { - pull_number: cleanedPrNumber, - }); - return interaction.reply(response.data.html_url); - } catch { - return interaction.reply({ embeds: [invalidEmbed] }); - } + if (repoName) { + try { + const response = await request('GET /repos/flybywiresim/{repo}/pulls/{pull_number}', { + repo: repoName, + pull_number: cleanedPrNumber, + }); + return interaction.reply(response.data.html_url); + } catch { + return interaction.reply({ embeds: [invalidEmbed] }); } + } else { + try { + const response = await request('GET /repos/flybywiresim/a32nx/pulls/{pull_number}', { + pull_number: cleanedPrNumber, + }); + return interaction.reply(response.data.html_url); + } catch { + return interaction.reply({ embeds: [invalidEmbed] }); + } + } } diff --git a/src/commands/utils/github/functions/handleGithubIssue.ts b/src/commands/utils/github/functions/handleGithubIssue.ts index 0611e36b..3cf9d330 100644 --- a/src/commands/utils/github/functions/handleGithubIssue.ts +++ b/src/commands/utils/github/functions/handleGithubIssue.ts @@ -5,42 +5,42 @@ import { makeEmbed } from '../../../../lib'; const syntaxHelp = '\nSyntax:\nAircraft repo: `/github issue `\nAny FBW repo: `/github issue `'; const noQueryEmbed = makeEmbed({ - title: 'Issue Error | Missing Query', - description: `Invalid command!${syntaxHelp}`, - color: Colors.Red, + title: 'Issue Error | Missing Query', + description: `Invalid command!${syntaxHelp}`, + color: Colors.Red, }); const invalidEmbed = makeEmbed({ - title: 'Issue Error | Invalid', - description: `Something went wrong! Did you provide the correct repo/Issue id?${syntaxHelp}`, - color: Colors.Red, + title: 'Issue Error | Invalid', + description: `Something went wrong! Did you provide the correct repo/Issue id?${syntaxHelp}`, + color: Colors.Red, }); export async function handleGithubIssue(interaction: ChatInputCommandInteraction<'cached'>) { - const issueNumber = interaction.options.getString('issue_number'); - const repoName = interaction.options.getString('repo'); + const issueNumber = interaction.options.getString('issue_number'); + const repoName = interaction.options.getString('repo'); - if (!issueNumber) return interaction.reply({ embeds: [noQueryEmbed] }); + if (!issueNumber) return interaction.reply({ embeds: [noQueryEmbed] }); - const cleanedIssueNumber = issueNumber.replace('#', ''); + const cleanedIssueNumber = issueNumber.replace('#', ''); - if (repoName) { - try { - const response = await request('GET /repos/flybywiresim/{repo}/issues/{issue_number}', { - repo: repoName, - issue_number: cleanedIssueNumber, - }); - return interaction.reply(response.data.html_url); - } catch { - return interaction.reply({ embeds: [invalidEmbed] }); - } - } else { - try { - const response = await request('GET /repos/flybywiresim/a32nx/issues/{issue_number}', { - issue_number: cleanedIssueNumber, - }); - return interaction.reply(response.data.html_url); - } catch { - return interaction.reply({ embeds: [invalidEmbed] }); - } + if (repoName) { + try { + const response = await request('GET /repos/flybywiresim/{repo}/issues/{issue_number}', { + repo: repoName, + issue_number: cleanedIssueNumber, + }); + return interaction.reply(response.data.html_url); + } catch { + return interaction.reply({ embeds: [invalidEmbed] }); } + } else { + try { + const response = await request('GET /repos/flybywiresim/a32nx/issues/{issue_number}', { + issue_number: cleanedIssueNumber, + }); + return interaction.reply(response.data.html_url); + } catch { + return interaction.reply({ embeds: [invalidEmbed] }); + } + } } diff --git a/src/commands/utils/github/github.ts b/src/commands/utils/github/github.ts index 0de351c8..f36e44bf 100644 --- a/src/commands/utils/github/github.ts +++ b/src/commands/utils/github/github.ts @@ -4,63 +4,63 @@ import { handleGithubPullRequest } from './functions/githubPullRequest'; import { handleGithubIssue } from './functions/handleGithubIssue'; const data = slashCommandStructure({ - name: 'github', - description: 'Retrieve links for a GitHub pull request or issue.', - type: ApplicationCommandType.ChatInput, - options: [ + name: 'github', + description: 'Retrieve links for a GitHub pull request or issue.', + type: ApplicationCommandType.ChatInput, + options: [ + { + name: 'pr', + description: 'Retrieves the link of the provided GitHub pull request.', + type: ApplicationCommandOptionType.Subcommand, + options: [ { - name: 'pr', - description: 'Retrieves the link of the provided GitHub pull request.', - type: ApplicationCommandOptionType.Subcommand, - options: [ - { - name: 'pr_number', - description: 'Please provide the pull request number.', - type: ApplicationCommandOptionType.String, - required: true, - }, - { - name: 'repo', - description: 'Please provide the repo name.', - type: ApplicationCommandOptionType.String, - required: false, - }, - ], + name: 'pr_number', + description: 'Please provide the pull request number.', + type: ApplicationCommandOptionType.String, + required: true, }, { - name: 'issue', - description: 'Retrieves the link of the provided GitHub issue.', - type: ApplicationCommandOptionType.Subcommand, - options: [ - { - name: 'issue_number', - description: 'Please provide the issue number.', - type: ApplicationCommandOptionType.String, - required: true, - }, - { - name: 'repo', - description: 'Please provide the repo name.', - type: ApplicationCommandOptionType.String, - required: false, - }, - ], + name: 'repo', + description: 'Please provide the repo name.', + type: ApplicationCommandOptionType.String, + required: false, }, - ], + ], + }, + { + name: 'issue', + description: 'Retrieves the link of the provided GitHub issue.', + type: ApplicationCommandOptionType.Subcommand, + options: [ + { + name: 'issue_number', + description: 'Please provide the issue number.', + type: ApplicationCommandOptionType.String, + required: true, + }, + { + name: 'repo', + description: 'Please provide the repo name.', + type: ApplicationCommandOptionType.String, + required: false, + }, + ], + }, + ], }); export default slashCommand(data, async ({ interaction }) => { - const subcommandName = interaction.options.getSubcommand(); + const subcommandName = interaction.options.getSubcommand(); - switch (subcommandName) { - case 'pr': - await handleGithubPullRequest(interaction); - break; - case 'issue': - await handleGithubIssue(interaction); - break; + switch (subcommandName) { + case 'pr': + await handleGithubPullRequest(interaction); + break; + case 'issue': + await handleGithubIssue(interaction); + break; - default: - await interaction.reply({ content: 'Unknown subcommand', ephemeral: true }); - } + default: + await interaction.reply({ content: 'Unknown subcommand', ephemeral: true }); + } }); diff --git a/src/commands/utils/help.ts b/src/commands/utils/help.ts index 3c92ee1e..4daed07b 100644 --- a/src/commands/utils/help.ts +++ b/src/commands/utils/help.ts @@ -4,113 +4,111 @@ import { Logger, makeEmbed, createPaginatedEmbedHandler, slashCommand, slashComm // May need re wrting to pull commands from index instead of the API const data = slashCommandStructure({ - name: 'help', - description: 'Display a list of all commands and subcommands.', - type: ApplicationCommandType.ChatInput, + name: 'help', + description: 'Display a list of all commands and subcommands.', + type: ApplicationCommandType.ChatInput, }); export default slashCommand(data, async ({ interaction }: { interaction: CommandInteraction }) => { - try { - // Fetch all commands from the API based on the environment - - let commands; - - if (process.env.NODE_ENV === 'production') { - commands = await interaction.client.application?.commands.fetch(); - } else { - commands = await interaction.guild?.commands.fetch(); - } - - // Check if the commands were fetched successfully - - if (!commands) { - return interaction.reply({ - content: 'An error occurred while fetching commands.', - ephemeral: true, - }); - } - - // Convert the iterable of commands into an array - const commandArray = Array.from(commands.values()); - - // Sort the commands alphabetically by name - const sortedCommands = commandArray.sort((a, b) => a.name.localeCompare(b.name)); - - // Generate an array of embeds for all pages - const pageLimit = 10; - const embeds = []; - for (let page = 0; page * pageLimit < sortedCommands.length; page++) { - const startIndex = page * pageLimit; - const endIndex = startIndex + pageLimit; - const currentCommands = sortedCommands.slice(startIndex, endIndex); - const totalPages = Math.ceil(sortedCommands.length / pageLimit); - - // Build the description with subcommands and subcommand groups - const description = currentCommands - .map((command) => { - let { description } = command; - - // Check if it's a context-specific message command - const isMessageCommand = command.type === ApplicationCommandType.Message; - - // Check if it's a context-specific user command - const isUserCommand = command.type === ApplicationCommandType.User; - - const subcommandList = command.options?.filter( - (option) => - option.type === ApplicationCommandOptionType.Subcommand || - option.type === ApplicationCommandOptionType.SubcommandGroup, - ); - - if (subcommandList && subcommandList.length > 0) { - const subcommandDescription = subcommandList - .map((subcommand) => { - if (subcommand.type === ApplicationCommandOptionType.Subcommand) { - return subcommand.name; - } - if (subcommand.type === ApplicationCommandOptionType.SubcommandGroup) { - const groupSubcommands = subcommand.options?.filter( - (sub) => sub.type === ApplicationCommandOptionType.Subcommand, - ); - if (groupSubcommands && groupSubcommands.length > 0) { - return `${subcommand.name} [${groupSubcommands - .map((sub) => sub.name) - .join(', ')}]`; - } - return `${subcommand.name} [None]`; - } - return ''; - }) - .join(', '); // Use a comma to separate subcommands - description += `\n**Subcommands and Groups:** \n${subcommandDescription}`; - } - - // Append a label for context-specific message and user commands - if (isMessageCommand) { - description += '\n(Context Command - Message)'; - } else if (isUserCommand) { - description += '\n(Context Command - User)'; - } - - return `**${command.name}**: ${description}`; - }) - .join('\n\n'); - - const embed = makeEmbed({ - title: `Bot Commands - Page ${page + 1} of ${totalPages}`, - description, - }); - embeds.push(embed); - } - - // Use the pagination function to send the paginated embeds - return createPaginatedEmbedHandler(interaction, embeds); - } catch (error) { - Logger.error(error); - return interaction.reply({ - content: 'An error occurred while fetching commands.', - ephemeral: true, - }); - // Handle errors appropriately + try { + // Fetch all commands from the API based on the environment + + let commands; + + if (process.env.NODE_ENV === 'production') { + commands = await interaction.client.application?.commands.fetch(); + } else { + commands = await interaction.guild?.commands.fetch(); + } + + // Check if the commands were fetched successfully + + if (!commands) { + return interaction.reply({ + content: 'An error occurred while fetching commands.', + ephemeral: true, + }); + } + + // Convert the iterable of commands into an array + const commandArray = Array.from(commands.values()); + + // Sort the commands alphabetically by name + const sortedCommands = commandArray.sort((a, b) => a.name.localeCompare(b.name)); + + // Generate an array of embeds for all pages + const pageLimit = 10; + const embeds = []; + for (let page = 0; page * pageLimit < sortedCommands.length; page++) { + const startIndex = page * pageLimit; + const endIndex = startIndex + pageLimit; + const currentCommands = sortedCommands.slice(startIndex, endIndex); + const totalPages = Math.ceil(sortedCommands.length / pageLimit); + + // Build the description with subcommands and subcommand groups + const description = currentCommands + .map((command) => { + let { description } = command; + + // Check if it's a context-specific message command + const isMessageCommand = command.type === ApplicationCommandType.Message; + + // Check if it's a context-specific user command + const isUserCommand = command.type === ApplicationCommandType.User; + + const subcommandList = command.options?.filter( + (option) => + option.type === ApplicationCommandOptionType.Subcommand || + option.type === ApplicationCommandOptionType.SubcommandGroup, + ); + + if (subcommandList && subcommandList.length > 0) { + const subcommandDescription = subcommandList + .map((subcommand) => { + if (subcommand.type === ApplicationCommandOptionType.Subcommand) { + return subcommand.name; + } + if (subcommand.type === ApplicationCommandOptionType.SubcommandGroup) { + const groupSubcommands = subcommand.options?.filter( + (sub) => sub.type === ApplicationCommandOptionType.Subcommand, + ); + if (groupSubcommands && groupSubcommands.length > 0) { + return `${subcommand.name} [${groupSubcommands.map((sub) => sub.name).join(', ')}]`; + } + return `${subcommand.name} [None]`; + } + return ''; + }) + .join(', '); // Use a comma to separate subcommands + description += `\n**Subcommands and Groups:** \n${subcommandDescription}`; + } + + // Append a label for context-specific message and user commands + if (isMessageCommand) { + description += '\n(Context Command - Message)'; + } else if (isUserCommand) { + description += '\n(Context Command - User)'; + } + + return `**${command.name}**: ${description}`; + }) + .join('\n\n'); + + const embed = makeEmbed({ + title: `Bot Commands - Page ${page + 1} of ${totalPages}`, + description, + }); + embeds.push(embed); } + + // Use the pagination function to send the paginated embeds + return createPaginatedEmbedHandler(interaction, embeds); + } catch (error) { + Logger.error(error); + return interaction.reply({ + content: 'An error occurred while fetching commands.', + ephemeral: true, + }); + // Handle errors appropriately + } }); diff --git a/src/commands/utils/liveFlights.ts b/src/commands/utils/liveFlights.ts index cc0e0b96..cf296a09 100644 --- a/src/commands/utils/liveFlights.ts +++ b/src/commands/utils/liveFlights.ts @@ -2,33 +2,33 @@ import { ApplicationCommandType, Colors } from 'discord.js'; import { slashCommand, slashCommandStructure, makeEmbed, Logger } from '../../lib'; const data = slashCommandStructure({ - name: 'live-flights', - description: 'Get the current live flights for FlyByWire Simulations.', - type: ApplicationCommandType.ChatInput, + name: 'live-flights', + description: 'Get the current live flights for FlyByWire Simulations.', + type: ApplicationCommandType.ChatInput, }); const FBW_WEB_MAP_URL = 'https://flybywiresim.com/map'; const FBW_API_BASE_URL = 'https://api.flybywiresim.com'; export default slashCommand(data, async ({ interaction }) => { - try { - const flights = await fetch(`${FBW_API_BASE_URL}/txcxn/_count`).then((res) => res.json()); - const flightsEmbed = makeEmbed({ - title: 'Live Flights', - description: `There are currently **${flights}** active flights with TELEX enabled.`, - footer: { text: 'Note: This includes the A32NX, and other aircraft using FlyByWire systems' }, - url: FBW_WEB_MAP_URL, - timestamp: new Date().toISOString(), - }); - return interaction.reply({ embeds: [flightsEmbed] }); - } catch (e) { - const error = e as Error; - Logger.error(error); - const errorEmbed = makeEmbed({ - title: 'Error | Live Flights', - description: error.message, - color: Colors.Red, - }); - return interaction.reply({ embeds: [errorEmbed] }); - } + try { + const flights = await fetch(`${FBW_API_BASE_URL}/txcxn/_count`).then((res) => res.json()); + const flightsEmbed = makeEmbed({ + title: 'Live Flights', + description: `There are currently **${flights}** active flights with TELEX enabled.`, + footer: { text: 'Note: This includes the A32NX, and other aircraft using FlyByWire systems' }, + url: FBW_WEB_MAP_URL, + timestamp: new Date().toISOString(), + }); + return interaction.reply({ embeds: [flightsEmbed] }); + } catch (e) { + const error = e as Error; + Logger.error(error); + const errorEmbed = makeEmbed({ + title: 'Error | Live Flights', + description: error.message, + color: Colors.Red, + }); + return interaction.reply({ embeds: [errorEmbed] }); + } }); diff --git a/src/commands/utils/locate/base-urls.ts b/src/commands/utils/locate/base-urls.ts index 1d13756a..0600da93 100644 --- a/src/commands/utils/locate/base-urls.ts +++ b/src/commands/utils/locate/base-urls.ts @@ -7,16 +7,16 @@ const LOCATE_DOCS_BASE_URL = 'https://docs.flybywiresim.com'; const LOCATE_A32NX_DOCS_BASE_URL = `${LOCATE_DOCS_BASE_URL}/pilots-corner/a32nx-briefing/flight-deck`; export const LOCATE_DOCS_BASE_URLS = { - a32nx: { - flightdeck: 'https://docs.flybywiresim.com/pilots-corner/a32nx-briefing/flight-deck/', - flypad: 'https://docs.flybywiresim.com/fbw-a32nx/feature-guides/flypados3/', - rearCb: `${LOCATE_A32NX_DOCS_BASE_URL}/ovhd-aft/circuit/#rear-right-back-panel`, - overhead: `${LOCATE_A32NX_DOCS_BASE_URL}/ovhd`, - aftOverhead: `${LOCATE_A32NX_DOCS_BASE_URL}/ovhd-aft`, - glareshield: `${LOCATE_A32NX_DOCS_BASE_URL}/glareshield`, - front: `${LOCATE_A32NX_DOCS_BASE_URL}/front`, - pedestal: `${LOCATE_A32NX_DOCS_BASE_URL}/pedestal`, - }, + a32nx: { + flightdeck: 'https://docs.flybywiresim.com/pilots-corner/a32nx-briefing/flight-deck/', + flypad: 'https://docs.flybywiresim.com/fbw-a32nx/feature-guides/flypados3/', + rearCb: `${LOCATE_A32NX_DOCS_BASE_URL}/ovhd-aft/circuit/#rear-right-back-panel`, + overhead: `${LOCATE_A32NX_DOCS_BASE_URL}/ovhd`, + aftOverhead: `${LOCATE_A32NX_DOCS_BASE_URL}/ovhd-aft`, + glareshield: `${LOCATE_A32NX_DOCS_BASE_URL}/glareshield`, + front: `${LOCATE_A32NX_DOCS_BASE_URL}/front`, + pedestal: `${LOCATE_A32NX_DOCS_BASE_URL}/pedestal`, + }, }; // Base URL for all locate-cmd images. @@ -26,13 +26,13 @@ const LOCATE_IMAGE_BASE_URL = `${imageBaseUrl}/utils/locate-cmd`; const LOCATE_A32NX_IMAGE_BASE_URL = `${LOCATE_IMAGE_BASE_URL}/a32nx`; export const LOCATE_IMAGE_BASE_URLS = { - a32nx: { - flypad: `${LOCATE_A32NX_IMAGE_BASE_URL}`, - rearCb: `${LOCATE_A32NX_IMAGE_BASE_URL}`, - overhead: `${LOCATE_A32NX_IMAGE_BASE_URL}/overhead`, - aftOverhead: `${LOCATE_A32NX_IMAGE_BASE_URL}/aft-overhead`, - front: `${LOCATE_A32NX_IMAGE_BASE_URL}/front`, - glareshield: `${LOCATE_A32NX_IMAGE_BASE_URL}/glareshield`, - pedestal: `${LOCATE_A32NX_IMAGE_BASE_URL}/pedestal`, - }, + a32nx: { + flypad: `${LOCATE_A32NX_IMAGE_BASE_URL}`, + rearCb: `${LOCATE_A32NX_IMAGE_BASE_URL}`, + overhead: `${LOCATE_A32NX_IMAGE_BASE_URL}/overhead`, + aftOverhead: `${LOCATE_A32NX_IMAGE_BASE_URL}/aft-overhead`, + front: `${LOCATE_A32NX_IMAGE_BASE_URL}/front`, + glareshield: `${LOCATE_A32NX_IMAGE_BASE_URL}/glareshield`, + pedestal: `${LOCATE_A32NX_IMAGE_BASE_URL}/pedestal`, + }, }; diff --git a/src/commands/utils/locate/functions/filterSearchResults.ts b/src/commands/utils/locate/functions/filterSearchResults.ts index ceb1d4f6..29957185 100644 --- a/src/commands/utils/locate/functions/filterSearchResults.ts +++ b/src/commands/utils/locate/functions/filterSearchResults.ts @@ -2,28 +2,28 @@ import { ApplicationCommandOptionChoiceData } from 'discord.js'; import { Panel } from '../panels/panel'; export const filterSearchResults = (query: string, source: Map) => { - // Get any target that includes the query string. - const possibleTargets = Array.from(source.keys()).filter((current) => - current.toLowerCase().includes(query.toLowerCase()), - ); + // Get any target that includes the query string. + const possibleTargets = Array.from(source.keys()).filter((current) => + current.toLowerCase().includes(query.toLowerCase()), + ); - // Sort possible targets based on the length of the match. -> More equal characters between query and target = higher ranking - possibleTargets.sort((a, b) => a.indexOf(query) - b.indexOf(query)); + // Sort possible targets based on the length of the match. -> More equal characters between query and target = higher ranking + possibleTargets.sort((a, b) => a.indexOf(query) - b.indexOf(query)); - // Remove all targets that are not preceded by a hyphen, or where .substring(0) !== query. - const filteredTargets = possibleTargets.filter((current) => { - const indexOfQuery = current.indexOf(query); + // Remove all targets that are not preceded by a hyphen, or where .substring(0) !== query. + const filteredTargets = possibleTargets.filter((current) => { + const indexOfQuery = current.indexOf(query); - if (indexOfQuery === 0) return true; + if (indexOfQuery === 0) return true; - return current.charAt(indexOfQuery - 1) === '-'; - }); + return current.charAt(indexOfQuery - 1) === '-'; + }); - // Limit the number of returned targets to 25. (Discord limitation) - const choices: ApplicationCommandOptionChoiceData[] = []; - for (let i = 0; i < filteredTargets.length && i < 25; i++) { - choices.push({ name: filteredTargets[i], value: filteredTargets[i] }); - } + // Limit the number of returned targets to 25. (Discord limitation) + const choices: ApplicationCommandOptionChoiceData[] = []; + for (let i = 0; i < filteredTargets.length && i < 25; i++) { + choices.push({ name: filteredTargets[i], value: filteredTargets[i] }); + } - return choices; + return choices; }; diff --git a/src/commands/utils/locate/functions/handleCommand.ts b/src/commands/utils/locate/functions/handleCommand.ts index 35ae8e24..e4fe303f 100644 --- a/src/commands/utils/locate/functions/handleCommand.ts +++ b/src/commands/utils/locate/functions/handleCommand.ts @@ -4,42 +4,42 @@ import { makeEmbed, makeLines } from '../../../../lib'; import { cleanTargetQuery } from './cleanTargetQuery'; const emptyTargetEmbed = makeEmbed({ - title: 'Locate - Empty target', - description: 'Please provide a switch, system or panel that you want to locate.', - color: Colors.Red, + title: 'Locate - Empty target', + description: 'Please provide a switch, system or panel that you want to locate.', + color: Colors.Red, }); const invalidTargetEmbed = makeEmbed({ - title: 'Locate - Invalid target', - description: 'The target you provided is invalid. Please type your search query and choose one from the list.', - color: Colors.Red, + title: 'Locate - Invalid target', + description: 'The target you provided is invalid. Please type your search query and choose one from the list.', + color: Colors.Red, }); const locateEmbed = (panel: Panel) => - makeEmbed({ - title: panel.title, - url: panel.docsUrl, - description: makeLines([ - `Learn more about the ${panel.name} and the flight deck:`, - `* [${panel.name} Documentation](${panel.docsUrl})`, - `* [Flight Deck Overview](${panel.flightDeckUrl})`, - ]), - image: { url: panel.imageUrl }, - footer: { text: 'Tip: Click the image to view in full size' }, - }); + makeEmbed({ + title: panel.title, + url: panel.docsUrl, + description: makeLines([ + `Learn more about the ${panel.name} and the flight deck:`, + `* [${panel.name} Documentation](${panel.docsUrl})`, + `* [Flight Deck Overview](${panel.flightDeckUrl})`, + ]), + image: { url: panel.imageUrl }, + footer: { text: 'Tip: Click the image to view in full size' }, + }); export async function handleCommand(interaction: ChatInputCommandInteraction<'cached'>, panelMap: Map) { - const target = interaction.options.getString('target'); + const target = interaction.options.getString('target'); - if (!target) return interaction.editReply({ embeds: [emptyTargetEmbed] }); + if (!target) return interaction.editReply({ embeds: [emptyTargetEmbed] }); - // Replace whitespace characters with a hyphen. - const cleanTarget = cleanTargetQuery(target); + // Replace whitespace characters with a hyphen. + const cleanTarget = cleanTargetQuery(target); - if (!Array.from(panelMap.keys()).includes(cleanTarget)) { - return interaction.editReply({ embeds: [invalidTargetEmbed] }); - } - const panel = panelMap.get(cleanTarget)!; + if (!Array.from(panelMap.keys()).includes(cleanTarget)) { + return interaction.editReply({ embeds: [invalidTargetEmbed] }); + } + const panel = panelMap.get(cleanTarget)!; - return interaction.editReply({ embeds: [locateEmbed(panel)] }); + return interaction.editReply({ embeds: [locateEmbed(panel)] }); } diff --git a/src/commands/utils/locate/locate.ts b/src/commands/utils/locate/locate.ts index a50b4838..6fa996cd 100644 --- a/src/commands/utils/locate/locate.ts +++ b/src/commands/utils/locate/locate.ts @@ -8,9 +8,9 @@ import { cleanTargetQuery } from './functions/cleanTargetQuery'; const a32nxPanelMap: Map = new Map(); for (const panel of a32nxPanels) { - for (const identifier of panel.identifiers) { - a32nxPanelMap.set(identifier, panel); - } + for (const identifier of panel.identifiers) { + a32nxPanelMap.set(identifier, panel); + } } /* const a380xPanelMap: Map = new Map(); @@ -21,25 +21,25 @@ for (const panel of a380xPanel) { } */ const data = slashCommandStructure({ - name: 'locate', - description: 'Locate any switch or panel on the flight decks of our aircraft.', - type: ApplicationCommandType.ChatInput, - options: [ + name: 'locate', + description: 'Locate any switch or panel on the flight decks of our aircraft.', + type: ApplicationCommandType.ChatInput, + options: [ + { + name: 'a32nx', + description: 'Locate any switch or panel on the A32NX flight deck.', + type: ApplicationCommandOptionType.Subcommand, + options: [ { - name: 'a32nx', - description: 'Locate any switch or panel on the A32NX flight deck.', - type: ApplicationCommandOptionType.Subcommand, - options: [ - { - name: 'target', - description: 'Specify the component to locate.', - type: ApplicationCommandOptionType.String, - autocomplete: true, - required: true, - }, - ], + name: 'target', + description: 'Specify the component to locate.', + type: ApplicationCommandOptionType.String, + autocomplete: true, + required: true, }, - /* { + ], + }, + /* { name: 'a380x', description: 'Locate any switch or panel on the A380X flight deck.', type: ApplicationCommandOptionType.Subcommand, @@ -53,53 +53,53 @@ const data = slashCommandStructure({ }, ], }, */ - ], + ], }); const autocompleteCallback: AutocompleteCallback = ({ interaction }) => { - const subcommand = interaction.options.getSubcommand(); - const target = interaction.options.getString('target')!; + const subcommand = interaction.options.getSubcommand(); + const target = interaction.options.getString('target')!; - // If target is empty, trigger 'no values match your query' UI state in discord client. - if (target.length < 1) return interaction.respond([]); + // If target is empty, trigger 'no values match your query' UI state in discord client. + if (target.length < 1) return interaction.respond([]); - // Replace whitespace characters with a hyphen. - const cleanTarget = cleanTargetQuery(target); + // Replace whitespace characters with a hyphen. + const cleanTarget = cleanTargetQuery(target); - let choices: ApplicationCommandOptionChoiceData[]; - switch (subcommand) { - case 'a32nx': - choices = filterSearchResults(cleanTarget, a32nxPanelMap); - break; - /* case 'a380x': + let choices: ApplicationCommandOptionChoiceData[]; + switch (subcommand) { + case 'a32nx': + choices = filterSearchResults(cleanTarget, a32nxPanelMap); + break; + /* case 'a380x': choices = filterSearchResults(cleanTarget, a380xPanelMap); break; */ - default: - return interaction.respond([]); - } + default: + return interaction.respond([]); + } - return interaction.respond(choices); + return interaction.respond(choices); }; export default slashCommand( - data, - async ({ interaction }) => { - await interaction.deferReply(); + data, + async ({ interaction }) => { + await interaction.deferReply(); - const subcommand = interaction.options.getSubcommand(); + const subcommand = interaction.options.getSubcommand(); - switch (subcommand) { - case 'a32nx': - await handleCommand(interaction, a32nxPanelMap); - break; - /* case 'a380x': + switch (subcommand) { + case 'a32nx': + await handleCommand(interaction, a32nxPanelMap); + break; + /* case 'a380x': await handleCommand(interaction, a380xPanelMap); break; */ - default: - await interaction.editReply({ content: 'Unknown subcommand' }); - } - }, - autocompleteCallback, + default: + await interaction.editReply({ content: 'Unknown subcommand' }); + } + }, + autocompleteCallback, ); diff --git a/src/commands/utils/locate/panels/a32nx/a32nx-panels.ts b/src/commands/utils/locate/panels/a32nx/a32nx-panels.ts index 91632077..30cedccf 100644 --- a/src/commands/utils/locate/panels/a32nx/a32nx-panels.ts +++ b/src/commands/utils/locate/panels/a32nx/a32nx-panels.ts @@ -1,150 +1,150 @@ import { Panel } from '../panel'; import { flyPad } from './flyPad'; import { - accuPressPanel, - autobrakeAndGearPanel, - clockPanel, - dcdu, - ewd, - instrumentLightingPanel, - isis, - nd, - pfd, - sd, + accuPressPanel, + autobrakeAndGearPanel, + clockPanel, + dcdu, + ewd, + instrumentLightingPanel, + isis, + nd, + pfd, + sd, } from './front-panel'; import { efisPanel, fcuPanel, lightKnobsPanel, warningPanel } from './glareshield'; import { - antiIcePanel, - adirsPanel, - apuPanel, - callsPanel, - cvrPanel, - emerElecPwrPanel, - evacPanel, - extLtPanel, - fltCtlPanel, - gpwsPanel, - intLtPanel, - oxyPanel, - paVideoPanel, - signsPanel, - wiperPanel, - cabinPressPanel, - airCondPanel, - elecPanel, - fuelPanel, - hydPanel, - firePanel, - engManStartPanel, - ventilationPanel, - cargoSmokePanel, - cargoVentPanel, - thirdACP, - readingLightsJumpSeats, - cockpitDoorIndicatorPanel, - eltPanel, - pedestalLightPanel, - emerCbPanel, - fmsLoadPanel, - maintenancePanel, + antiIcePanel, + adirsPanel, + apuPanel, + callsPanel, + cvrPanel, + emerElecPwrPanel, + evacPanel, + extLtPanel, + fltCtlPanel, + gpwsPanel, + intLtPanel, + oxyPanel, + paVideoPanel, + signsPanel, + wiperPanel, + cabinPressPanel, + airCondPanel, + elecPanel, + fuelPanel, + hydPanel, + firePanel, + engManStartPanel, + ventilationPanel, + cargoSmokePanel, + cargoVentPanel, + thirdACP, + readingLightsJumpSeats, + cockpitDoorIndicatorPanel, + eltPanel, + pedestalLightPanel, + emerCbPanel, + fmsLoadPanel, + maintenancePanel, } from './overhead'; import { - aidsDfdrPanel, - atcTcasPanel, - captPedestalLightingPanel, - cockpitDoorPanel, - console, - ecamControlPanel, - engPanel, - flaps, - gravityGearExtensionPanel, - mcdu, - parkBrkPanel, - printer, - rmpAcpPanel, - rudderTrim, - speedBrake, - switchingPanel, - thrLvrPitchTrim, - wxPanel, + aidsDfdrPanel, + atcTcasPanel, + captPedestalLightingPanel, + cockpitDoorPanel, + console, + ecamControlPanel, + engPanel, + flaps, + gravityGearExtensionPanel, + mcdu, + parkBrkPanel, + printer, + rmpAcpPanel, + rudderTrim, + speedBrake, + switchingPanel, + thrLvrPitchTrim, + wxPanel, } from './pedestal'; import { rearBackCbPanel } from './rear-cb-panel'; export const a32nxPanels: Panel[] = [ - // OVERHEAD - wiperPanel, - callsPanel, - oxyPanel, - cvrPanel, - gpwsPanel, - emerElecPwrPanel, - evacPanel, - fltCtlPanel, - adirsPanel, - paVideoPanel, - extLtPanel, - apuPanel, - signsPanel, - intLtPanel, - antiIcePanel, - cabinPressPanel, - airCondPanel, - elecPanel, - fuelPanel, - hydPanel, - firePanel, - engManStartPanel, - ventilationPanel, - cargoSmokePanel, - cargoVentPanel, - thirdACP, - readingLightsJumpSeats, - cockpitDoorIndicatorPanel, - eltPanel, - pedestalLightPanel, - emerCbPanel, - rearBackCbPanel, - fmsLoadPanel, - maintenancePanel, + // OVERHEAD + wiperPanel, + callsPanel, + oxyPanel, + cvrPanel, + gpwsPanel, + emerElecPwrPanel, + evacPanel, + fltCtlPanel, + adirsPanel, + paVideoPanel, + extLtPanel, + apuPanel, + signsPanel, + intLtPanel, + antiIcePanel, + cabinPressPanel, + airCondPanel, + elecPanel, + fuelPanel, + hydPanel, + firePanel, + engManStartPanel, + ventilationPanel, + cargoSmokePanel, + cargoVentPanel, + thirdACP, + readingLightsJumpSeats, + cockpitDoorIndicatorPanel, + eltPanel, + pedestalLightPanel, + emerCbPanel, + rearBackCbPanel, + fmsLoadPanel, + maintenancePanel, - // GLARESHIELD - warningPanel, - efisPanel, - fcuPanel, - lightKnobsPanel, + // GLARESHIELD + warningPanel, + efisPanel, + fcuPanel, + lightKnobsPanel, - // FRONT PANEL - instrumentLightingPanel, - pfd, - nd, - isis, - dcdu, - ewd, - sd, - autobrakeAndGearPanel, - clockPanel, - accuPressPanel, + // FRONT PANEL + instrumentLightingPanel, + pfd, + nd, + isis, + dcdu, + ewd, + sd, + autobrakeAndGearPanel, + clockPanel, + accuPressPanel, - // PEDESTAL - console, - mcdu, - rmpAcpPanel, - captPedestalLightingPanel, - wxPanel, - speedBrake, - cockpitDoorPanel, - switchingPanel, - ecamControlPanel, - thrLvrPitchTrim, - engPanel, - rudderTrim, - parkBrkPanel, - gravityGearExtensionPanel, - aidsDfdrPanel, - atcTcasPanel, - flaps, - printer, + // PEDESTAL + console, + mcdu, + rmpAcpPanel, + captPedestalLightingPanel, + wxPanel, + speedBrake, + cockpitDoorPanel, + switchingPanel, + ecamControlPanel, + thrLvrPitchTrim, + engPanel, + rudderTrim, + parkBrkPanel, + gravityGearExtensionPanel, + aidsDfdrPanel, + atcTcasPanel, + flaps, + printer, - // flyPad - flyPad, + // flyPad + flyPad, ]; diff --git a/src/commands/utils/locate/panels/a32nx/flyPad.ts b/src/commands/utils/locate/panels/a32nx/flyPad.ts index 0b8e7194..3b290808 100644 --- a/src/commands/utils/locate/panels/a32nx/flyPad.ts +++ b/src/commands/utils/locate/panels/a32nx/flyPad.ts @@ -2,10 +2,10 @@ import { LOCATE_DOCS_BASE_URLS, LOCATE_IMAGE_BASE_URLS } from '../../base-urls'; import { Panel } from '../panel'; export const flyPad: Panel = { - name: 'flyPad', - title: 'FlyByWire A32NX | flyPad (EFB)', - docsUrl: LOCATE_DOCS_BASE_URLS.a32nx.flypad, - flightDeckUrl: LOCATE_DOCS_BASE_URLS.a32nx.flightdeck, - imageUrl: `${LOCATE_IMAGE_BASE_URLS.a32nx.flypad}/efb_downscaled.gif`, - identifiers: ['flypad', 'efb', 'electronic-flight-bag'], + name: 'flyPad', + title: 'FlyByWire A32NX | flyPad (EFB)', + docsUrl: LOCATE_DOCS_BASE_URLS.a32nx.flypad, + flightDeckUrl: LOCATE_DOCS_BASE_URLS.a32nx.flightdeck, + imageUrl: `${LOCATE_IMAGE_BASE_URLS.a32nx.flypad}/efb_downscaled.gif`, + identifiers: ['flypad', 'efb', 'electronic-flight-bag'], }; diff --git a/src/commands/utils/locate/panels/a32nx/front-panel.ts b/src/commands/utils/locate/panels/a32nx/front-panel.ts index 50c2e862..aa0a2ab7 100644 --- a/src/commands/utils/locate/panels/a32nx/front-panel.ts +++ b/src/commands/utils/locate/panels/a32nx/front-panel.ts @@ -5,133 +5,133 @@ const FRONT_DOCS_BASE_URL = LOCATE_DOCS_BASE_URLS.a32nx.front; const FRONT_IMAGE_BASE_URL = LOCATE_IMAGE_BASE_URLS.a32nx.front; export const instrumentLightingPanel: Panel = { - name: 'Instrument Lighting Control Panel', - title: 'FlyByWire A32NX | Instrument Lighting Control Panel', - docsUrl: `${FRONT_DOCS_BASE_URL}/ilcp/`, - flightDeckUrl: LOCATE_DOCS_BASE_URLS.a32nx.flightdeck, - imageUrl: `${FRONT_IMAGE_BASE_URL}/instrument_lighting.png`, - identifiers: [ - 'instrument-brightness', - 'instrument-lighting-panel', - 'gpws-gs-button', - 'pfd-brightness-knob', - 'pfd-nd-xfr-button', - 'nd-brightness-knob', - 'loudspeaker-knob', - 'console-floor-light-switch', - ], + name: 'Instrument Lighting Control Panel', + title: 'FlyByWire A32NX | Instrument Lighting Control Panel', + docsUrl: `${FRONT_DOCS_BASE_URL}/ilcp/`, + flightDeckUrl: LOCATE_DOCS_BASE_URLS.a32nx.flightdeck, + imageUrl: `${FRONT_IMAGE_BASE_URL}/instrument_lighting.png`, + identifiers: [ + 'instrument-brightness', + 'instrument-lighting-panel', + 'gpws-gs-button', + 'pfd-brightness-knob', + 'pfd-nd-xfr-button', + 'nd-brightness-knob', + 'loudspeaker-knob', + 'console-floor-light-switch', + ], }; export const pfd: Panel = { - name: 'PFD', - title: 'FlyByWire A32NX | Primary Flight Display (PFD)', - docsUrl: `${FRONT_DOCS_BASE_URL}/pfd`, - flightDeckUrl: LOCATE_DOCS_BASE_URLS.a32nx.flightdeck, - imageUrl: `${FRONT_IMAGE_BASE_URL}/pfd.png`, - identifiers: [ - 'pfd', - 'primary-flight-display', - 'fma', - 'flight-mode-annunciator', - 'speed-tape', - 'artificial-horizon', - 'compass-scale', - 'v-dev-scales', - 'loc-scale', - 'gs-scale', - 'altitude-tape', - 'vs-indicator', - 'vertical-speed-indicator', - ], + name: 'PFD', + title: 'FlyByWire A32NX | Primary Flight Display (PFD)', + docsUrl: `${FRONT_DOCS_BASE_URL}/pfd`, + flightDeckUrl: LOCATE_DOCS_BASE_URLS.a32nx.flightdeck, + imageUrl: `${FRONT_IMAGE_BASE_URL}/pfd.png`, + identifiers: [ + 'pfd', + 'primary-flight-display', + 'fma', + 'flight-mode-annunciator', + 'speed-tape', + 'artificial-horizon', + 'compass-scale', + 'v-dev-scales', + 'loc-scale', + 'gs-scale', + 'altitude-tape', + 'vs-indicator', + 'vertical-speed-indicator', + ], }; export const nd: Panel = { - name: 'ND', - title: 'FlyByWire A32NX | Navigation Display (ND)', - docsUrl: `${FRONT_DOCS_BASE_URL}/nd`, - flightDeckUrl: LOCATE_DOCS_BASE_URLS.a32nx.flightdeck, - imageUrl: `${FRONT_IMAGE_BASE_URL}/nd.png`, - identifiers: ['nd', 'navigation-display', 'weather-radar', 'terrain-map', 'terr-on-nd-switch'], + name: 'ND', + title: 'FlyByWire A32NX | Navigation Display (ND)', + docsUrl: `${FRONT_DOCS_BASE_URL}/nd`, + flightDeckUrl: LOCATE_DOCS_BASE_URLS.a32nx.flightdeck, + imageUrl: `${FRONT_IMAGE_BASE_URL}/nd.png`, + identifiers: ['nd', 'navigation-display', 'weather-radar', 'terrain-map', 'terr-on-nd-switch'], }; export const isis: Panel = { - name: 'ISIS', - title: 'FlyByWire A32NX | Integrated Standby Instrument System (ISIS)', - docsUrl: `${FRONT_DOCS_BASE_URL}/isis`, - flightDeckUrl: LOCATE_DOCS_BASE_URLS.a32nx.flightdeck, - imageUrl: `${FRONT_IMAGE_BASE_URL}/isis.png`, - identifiers: ['isis', 'integrated-standby-instrument-system', 'backup-pfd'], + name: 'ISIS', + title: 'FlyByWire A32NX | Integrated Standby Instrument System (ISIS)', + docsUrl: `${FRONT_DOCS_BASE_URL}/isis`, + flightDeckUrl: LOCATE_DOCS_BASE_URLS.a32nx.flightdeck, + imageUrl: `${FRONT_IMAGE_BASE_URL}/isis.png`, + identifiers: ['isis', 'integrated-standby-instrument-system', 'backup-pfd'], }; export const dcdu: Panel = { - name: 'DCDU', - title: 'FlyByWire A32NX | Datalink Ctl and Display Unit (DCDU)', - docsUrl: `${FRONT_DOCS_BASE_URL}/dcdu`, - flightDeckUrl: LOCATE_DOCS_BASE_URLS.a32nx.flightdeck, - imageUrl: `${FRONT_IMAGE_BASE_URL}/dcdu.png`, - identifiers: ['dcdu', 'datalink-ctl-and-display-unit', 'cpdlc'], + name: 'DCDU', + title: 'FlyByWire A32NX | Datalink Ctl and Display Unit (DCDU)', + docsUrl: `${FRONT_DOCS_BASE_URL}/dcdu`, + flightDeckUrl: LOCATE_DOCS_BASE_URLS.a32nx.flightdeck, + imageUrl: `${FRONT_IMAGE_BASE_URL}/dcdu.png`, + identifiers: ['dcdu', 'datalink-ctl-and-display-unit', 'cpdlc'], }; export const ewd: Panel = { - name: 'E/WD', - title: 'FlyByWire A32NX | Engine and Warning Display (E/WD) (Upper ECAM)', - docsUrl: `${FRONT_DOCS_BASE_URL}/upper-ecam`, - flightDeckUrl: LOCATE_DOCS_BASE_URLS.a32nx.flightdeck, - imageUrl: `${FRONT_IMAGE_BASE_URL}/ewd.png`, - identifiers: ['ecam-upper', 'upper-ecam', 'ewd', 'engine-and-warning-display', 'n1-display'], + name: 'E/WD', + title: 'FlyByWire A32NX | Engine and Warning Display (E/WD) (Upper ECAM)', + docsUrl: `${FRONT_DOCS_BASE_URL}/upper-ecam`, + flightDeckUrl: LOCATE_DOCS_BASE_URLS.a32nx.flightdeck, + imageUrl: `${FRONT_IMAGE_BASE_URL}/ewd.png`, + identifiers: ['ecam-upper', 'upper-ecam', 'ewd', 'engine-and-warning-display', 'n1-display'], }; export const sd: Panel = { - name: 'SD', - title: 'FlyByWire A32NX | System Display (SD) (Lower ECAM)', - docsUrl: `${FRONT_DOCS_BASE_URL}/lower-ecam`, - flightDeckUrl: LOCATE_DOCS_BASE_URLS.a32nx.flightdeck, - imageUrl: `${FRONT_IMAGE_BASE_URL}/sd.png`, - identifiers: [ - 'sd', - 'system-display', - 'lower-ecam', - 'ecam-lower', - 'tat-display', - 'sat-display', - 'isa-display', - 'gw-display', - 'gross-weight-display', - ], + name: 'SD', + title: 'FlyByWire A32NX | System Display (SD) (Lower ECAM)', + docsUrl: `${FRONT_DOCS_BASE_URL}/lower-ecam`, + flightDeckUrl: LOCATE_DOCS_BASE_URLS.a32nx.flightdeck, + imageUrl: `${FRONT_IMAGE_BASE_URL}/sd.png`, + identifiers: [ + 'sd', + 'system-display', + 'lower-ecam', + 'ecam-lower', + 'tat-display', + 'sat-display', + 'isa-display', + 'gw-display', + 'gross-weight-display', + ], }; export const autobrakeAndGearPanel: Panel = { - name: 'Autobrake and Gear Indicator', - title: 'FlyByWire A32NX | Autobrake and Gear Indications', - docsUrl: `${FRONT_DOCS_BASE_URL}/autobrake-gear`, - flightDeckUrl: LOCATE_DOCS_BASE_URLS.a32nx.flightdeck, - imageUrl: `${FRONT_IMAGE_BASE_URL}/autobrake_gear.png`, - identifiers: [ - 'gear', - 'ldg-gear-indicator', - 'brk-fan-switch', - 'brake-fan-switch', - 'autobrake-switch', - 'anti-skid-nosewheel-steering-switch', - 'lg-lever', - 'landing-gear-lever', - ], + name: 'Autobrake and Gear Indicator', + title: 'FlyByWire A32NX | Autobrake and Gear Indications', + docsUrl: `${FRONT_DOCS_BASE_URL}/autobrake-gear`, + flightDeckUrl: LOCATE_DOCS_BASE_URLS.a32nx.flightdeck, + imageUrl: `${FRONT_IMAGE_BASE_URL}/autobrake_gear.png`, + identifiers: [ + 'gear', + 'ldg-gear-indicator', + 'brk-fan-switch', + 'brake-fan-switch', + 'autobrake-switch', + 'anti-skid-nosewheel-steering-switch', + 'lg-lever', + 'landing-gear-lever', + ], }; export const clockPanel: Panel = { - name: 'Clock Panel', - title: 'FlyByWire A32NX | Clock', - docsUrl: `${FRONT_DOCS_BASE_URL}/clock`, - flightDeckUrl: LOCATE_DOCS_BASE_URLS.a32nx.flightdeck, - imageUrl: `${FRONT_IMAGE_BASE_URL}/clock.png`, - identifiers: ['clock', 'date'], + name: 'Clock Panel', + title: 'FlyByWire A32NX | Clock', + docsUrl: `${FRONT_DOCS_BASE_URL}/clock`, + flightDeckUrl: LOCATE_DOCS_BASE_URLS.a32nx.flightdeck, + imageUrl: `${FRONT_IMAGE_BASE_URL}/clock.png`, + identifiers: ['clock', 'date'], }; export const accuPressPanel: Panel = { - name: 'Accumulator Pressure Indicator', - title: 'FlyByWire A32NX | Accumulator Pressure Indicator', - docsUrl: `${FRONT_DOCS_BASE_URL}/accu`, - flightDeckUrl: LOCATE_DOCS_BASE_URLS.a32nx.flightdeck, - imageUrl: `${FRONT_IMAGE_BASE_URL}/accu_press.png`, - identifiers: ['accu-press', 'accumulator-pressure-indicator', 'brake-pressure-indicator'], + name: 'Accumulator Pressure Indicator', + title: 'FlyByWire A32NX | Accumulator Pressure Indicator', + docsUrl: `${FRONT_DOCS_BASE_URL}/accu`, + flightDeckUrl: LOCATE_DOCS_BASE_URLS.a32nx.flightdeck, + imageUrl: `${FRONT_IMAGE_BASE_URL}/accu_press.png`, + identifiers: ['accu-press', 'accumulator-pressure-indicator', 'brake-pressure-indicator'], }; diff --git a/src/commands/utils/locate/panels/a32nx/glareshield.ts b/src/commands/utils/locate/panels/a32nx/glareshield.ts index c49ccad7..e03cf34a 100644 --- a/src/commands/utils/locate/panels/a32nx/glareshield.ts +++ b/src/commands/utils/locate/panels/a32nx/glareshield.ts @@ -5,93 +5,93 @@ const GLARESHIELD_DOCS_BASE_URL = LOCATE_DOCS_BASE_URLS.a32nx.glareshield; const GLARESHIELD_IMAGE_BASE_URL = LOCATE_IMAGE_BASE_URLS.a32nx.glareshield; export const warningPanel: Panel = { - name: 'Warning Panel', - title: 'FlyByWire A32NX | Warning Panel', - docsUrl: `${GLARESHIELD_DOCS_BASE_URL}/warning/`, - flightDeckUrl: LOCATE_DOCS_BASE_URLS.a32nx.flightdeck, - imageUrl: `${GLARESHIELD_IMAGE_BASE_URL}/warning.png`, - identifiers: [ - 'warning', - 'warning-panel', - 'atc-msg-button', - 'autoland-warning-light', - 'master-caution', - 'master-warning', - 'chrono', - 'chrono-button', - 'sidestick-priority-indicator', - ], + name: 'Warning Panel', + title: 'FlyByWire A32NX | Warning Panel', + docsUrl: `${GLARESHIELD_DOCS_BASE_URL}/warning/`, + flightDeckUrl: LOCATE_DOCS_BASE_URLS.a32nx.flightdeck, + imageUrl: `${GLARESHIELD_IMAGE_BASE_URL}/warning.png`, + identifiers: [ + 'warning', + 'warning-panel', + 'atc-msg-button', + 'autoland-warning-light', + 'master-caution', + 'master-warning', + 'chrono', + 'chrono-button', + 'sidestick-priority-indicator', + ], }; export const efisPanel: Panel = { - name: 'EFIS', - title: 'FlyByWire A32NX | EFIS Panel', - docsUrl: `${GLARESHIELD_DOCS_BASE_URL}/efis_control/`, - flightDeckUrl: LOCATE_DOCS_BASE_URLS.a32nx.flightdeck, - imageUrl: `${GLARESHIELD_IMAGE_BASE_URL}/efis.png`, - identifiers: [ - 'efis', - 'efis-panel', - 'qnh', - 'fd', - 'flight-director-switch', - 'ls', - 'ls-switch', - 'cstr', - 'constraint-switch', - 'wpt', - 'waypoint-switch', - 'vor-d', - 'vor-dme-switch', - 'ndb', - 'ndb-switch', - 'vor', - 'adf', - 'arpt', - 'airport-switch', - 'rose-mode', - 'arc-mode', - 'plan-mode', - 'nd-range', - 'adf-switch', - 'vor-switch', - ], + name: 'EFIS', + title: 'FlyByWire A32NX | EFIS Panel', + docsUrl: `${GLARESHIELD_DOCS_BASE_URL}/efis_control/`, + flightDeckUrl: LOCATE_DOCS_BASE_URLS.a32nx.flightdeck, + imageUrl: `${GLARESHIELD_IMAGE_BASE_URL}/efis.png`, + identifiers: [ + 'efis', + 'efis-panel', + 'qnh', + 'fd', + 'flight-director-switch', + 'ls', + 'ls-switch', + 'cstr', + 'constraint-switch', + 'wpt', + 'waypoint-switch', + 'vor-d', + 'vor-dme-switch', + 'ndb', + 'ndb-switch', + 'vor', + 'adf', + 'arpt', + 'airport-switch', + 'rose-mode', + 'arc-mode', + 'plan-mode', + 'nd-range', + 'adf-switch', + 'vor-switch', + ], }; export const fcuPanel: Panel = { - name: 'FCU', - title: 'FlyByWire A32NX | Flight Control Unit (FCU)', - docsUrl: `${GLARESHIELD_DOCS_BASE_URL}/fcu/`, - flightDeckUrl: LOCATE_DOCS_BASE_URLS.a32nx.flightdeck, - imageUrl: `${GLARESHIELD_IMAGE_BASE_URL}/fcu.png`, - identifiers: [ - 'fcu', - 'flight-control-unit', - 'ap', - 'autopilot', - 'spd-mach-button', - 'spd-mach-knob', - 'hdg-trk-knob', - 'loc-switch', - 'hdg-vs', - 'trk-fpa', - 'hdg-vs-trk-fpa-button', - 'ap-1-switch', - 'ap-2-switch', - 'alt-knob', - 'exped-switch', - 'metric-alt-button', - 'vs-knob', - 'vertical-speed-knob', - 'fpa-knob', - ], + name: 'FCU', + title: 'FlyByWire A32NX | Flight Control Unit (FCU)', + docsUrl: `${GLARESHIELD_DOCS_BASE_URL}/fcu/`, + flightDeckUrl: LOCATE_DOCS_BASE_URLS.a32nx.flightdeck, + imageUrl: `${GLARESHIELD_IMAGE_BASE_URL}/fcu.png`, + identifiers: [ + 'fcu', + 'flight-control-unit', + 'ap', + 'autopilot', + 'spd-mach-button', + 'spd-mach-knob', + 'hdg-trk-knob', + 'loc-switch', + 'hdg-vs', + 'trk-fpa', + 'hdg-vs-trk-fpa-button', + 'ap-1-switch', + 'ap-2-switch', + 'alt-knob', + 'exped-switch', + 'metric-alt-button', + 'vs-knob', + 'vertical-speed-knob', + 'fpa-knob', + ], }; export const lightKnobsPanel: Panel = { - name: 'Lighting Knobs Panel', - title: 'FlyByWire A32NX | Light Knobs Panel', - docsUrl: `${GLARESHIELD_DOCS_BASE_URL}/light-knobs/`, - flightDeckUrl: LOCATE_DOCS_BASE_URLS.a32nx.flightdeck, - imageUrl: `${GLARESHIELD_IMAGE_BASE_URL}/light_knobs.png`, - identifiers: ['table-light-knob', 'integral-glareshield-lighting-knob', 'fcu-brightness-knob'], + name: 'Lighting Knobs Panel', + title: 'FlyByWire A32NX | Light Knobs Panel', + docsUrl: `${GLARESHIELD_DOCS_BASE_URL}/light-knobs/`, + flightDeckUrl: LOCATE_DOCS_BASE_URLS.a32nx.flightdeck, + imageUrl: `${GLARESHIELD_IMAGE_BASE_URL}/light_knobs.png`, + identifiers: ['table-light-knob', 'integral-glareshield-lighting-knob', 'fcu-brightness-knob'], }; diff --git a/src/commands/utils/locate/panels/a32nx/overhead.ts b/src/commands/utils/locate/panels/a32nx/overhead.ts index 05d55d0c..e82848bf 100644 --- a/src/commands/utils/locate/panels/a32nx/overhead.ts +++ b/src/commands/utils/locate/panels/a32nx/overhead.ts @@ -8,449 +8,449 @@ const OVHD_IMAGE_BASE_URL = LOCATE_IMAGE_BASE_URLS.a32nx.overhead; const AFT_OVHD_IMAGE_BASE_URL = LOCATE_IMAGE_BASE_URLS.a32nx.aftOverhead; export const wiperPanel: Panel = { - name: 'Wiper Panel', - title: 'FlyByWire A32NX | Wiper Panel', - docsUrl: `${OVHD_DOCS_BASE_URL}/wipers/`, - flightDeckUrl: LOCATE_DOCS_BASE_URLS.a32nx.flightdeck, - imageUrl: `${OVHD_IMAGE_BASE_URL}/wiper.png`, - identifiers: [ - 'wiper-panel', - 'wiper', - 'wipers', - 'rain', - 'rain-repellent', - 'repellent', - 'rplnt', - 'wiper-selector', - 'rain-rplnt-button', - ], + name: 'Wiper Panel', + title: 'FlyByWire A32NX | Wiper Panel', + docsUrl: `${OVHD_DOCS_BASE_URL}/wipers/`, + flightDeckUrl: LOCATE_DOCS_BASE_URLS.a32nx.flightdeck, + imageUrl: `${OVHD_IMAGE_BASE_URL}/wiper.png`, + identifiers: [ + 'wiper-panel', + 'wiper', + 'wipers', + 'rain', + 'rain-repellent', + 'repellent', + 'rplnt', + 'wiper-selector', + 'rain-rplnt-button', + ], }; export const callsPanel: Panel = { - name: 'Calls Panel', - title: 'FlyByWire A32NX | Calls Panel', - docsUrl: `${OVHD_DOCS_BASE_URL}/calls/`, - flightDeckUrl: LOCATE_DOCS_BASE_URLS.a32nx.flightdeck, - imageUrl: `${OVHD_IMAGE_BASE_URL}/calls.png`, - identifiers: ['calls-panel', 'call', 'calls'], + name: 'Calls Panel', + title: 'FlyByWire A32NX | Calls Panel', + docsUrl: `${OVHD_DOCS_BASE_URL}/calls/`, + flightDeckUrl: LOCATE_DOCS_BASE_URLS.a32nx.flightdeck, + imageUrl: `${OVHD_IMAGE_BASE_URL}/calls.png`, + identifiers: ['calls-panel', 'call', 'calls'], }; export const oxyPanel: Panel = { - name: 'Oxygen Panel', - title: 'FlyByWire A32NX | Oxygen Panel', - docsUrl: `${OVHD_DOCS_BASE_URL}/oxygen/`, - flightDeckUrl: LOCATE_DOCS_BASE_URLS.a32nx.flightdeck, - imageUrl: `${OVHD_IMAGE_BASE_URL}/oxygen.png`, - identifiers: ['oxy', 'oxygen-panel', 'oxygen', 'mask-man-on-switch', 'crew-supply-switch'], + name: 'Oxygen Panel', + title: 'FlyByWire A32NX | Oxygen Panel', + docsUrl: `${OVHD_DOCS_BASE_URL}/oxygen/`, + flightDeckUrl: LOCATE_DOCS_BASE_URLS.a32nx.flightdeck, + imageUrl: `${OVHD_IMAGE_BASE_URL}/oxygen.png`, + identifiers: ['oxy', 'oxygen-panel', 'oxygen', 'mask-man-on-switch', 'crew-supply-switch'], }; export const cvrPanel: Panel = { - name: 'RCDR Panel', - title: 'FlyByWire A32NX | Voice Recorder Panel', - docsUrl: `${OVHD_DOCS_BASE_URL}/voice-recorder/`, - flightDeckUrl: LOCATE_DOCS_BASE_URLS.a32nx.flightdeck, - imageUrl: `${OVHD_IMAGE_BASE_URL}/rcdr.png`, - identifiers: [ - 'voice-recorder-panel', - 'cvr', - 'fdr', - 'cockpit-voice-recorder', - 'flight-data-recorder', - 'gnd-ctl-switch', - 'cvr-erase-button', - 'cvr-test-button', - ], + name: 'RCDR Panel', + title: 'FlyByWire A32NX | Voice Recorder Panel', + docsUrl: `${OVHD_DOCS_BASE_URL}/voice-recorder/`, + flightDeckUrl: LOCATE_DOCS_BASE_URLS.a32nx.flightdeck, + imageUrl: `${OVHD_IMAGE_BASE_URL}/rcdr.png`, + identifiers: [ + 'voice-recorder-panel', + 'cvr', + 'fdr', + 'cockpit-voice-recorder', + 'flight-data-recorder', + 'gnd-ctl-switch', + 'cvr-erase-button', + 'cvr-test-button', + ], }; export const gpwsPanel: Panel = { - name: 'GPWS Panel', - title: 'FlyByWire A32NX | GPWS Panel', - docsUrl: `${OVHD_DOCS_BASE_URL}/gpws/`, - flightDeckUrl: LOCATE_DOCS_BASE_URLS.a32nx.flightdeck, - imageUrl: `${OVHD_IMAGE_BASE_URL}/gpws.png`, - identifiers: [ - 'gpws-panel', - 'gpws', - 'egpws', - 'terr-switch', - 'sys-switch', - 'gs-mode-switch', - 'flap-mode-switch', - 'ldg-flap-3-switch', - ], + name: 'GPWS Panel', + title: 'FlyByWire A32NX | GPWS Panel', + docsUrl: `${OVHD_DOCS_BASE_URL}/gpws/`, + flightDeckUrl: LOCATE_DOCS_BASE_URLS.a32nx.flightdeck, + imageUrl: `${OVHD_IMAGE_BASE_URL}/gpws.png`, + identifiers: [ + 'gpws-panel', + 'gpws', + 'egpws', + 'terr-switch', + 'sys-switch', + 'gs-mode-switch', + 'flap-mode-switch', + 'ldg-flap-3-switch', + ], }; export const emerElecPwrPanel: Panel = { - name: 'EMER ELEC PWR Panel', - title: 'FlyByWire A32NX | Emergency Electric Power Panel', - docsUrl: `${OVHD_DOCS_BASE_URL}/emergency-electric/`, - flightDeckUrl: LOCATE_DOCS_BASE_URLS.a32nx.flightdeck, - imageUrl: `${OVHD_IMAGE_BASE_URL}/emer_elec_pwr.png`, - identifiers: [ - 'emergency-electrical-panel', - 'emer-elec-panel', - 'emer-elec', - 'emer-elec-pwr', - 'emer-gen-test-switch', - 'gen-1-line-switch', - 'man-on-switch', - ], + name: 'EMER ELEC PWR Panel', + title: 'FlyByWire A32NX | Emergency Electric Power Panel', + docsUrl: `${OVHD_DOCS_BASE_URL}/emergency-electric/`, + flightDeckUrl: LOCATE_DOCS_BASE_URLS.a32nx.flightdeck, + imageUrl: `${OVHD_IMAGE_BASE_URL}/emer_elec_pwr.png`, + identifiers: [ + 'emergency-electrical-panel', + 'emer-elec-panel', + 'emer-elec', + 'emer-elec-pwr', + 'emer-gen-test-switch', + 'gen-1-line-switch', + 'man-on-switch', + ], }; export const evacPanel: Panel = { - name: 'EVAC Panel', - title: 'FlyByWire A32NX | Evacuation Panel', - docsUrl: `${OVHD_DOCS_BASE_URL}/evacuation/`, - flightDeckUrl: LOCATE_DOCS_BASE_URLS.a32nx.flightdeck, - imageUrl: `${OVHD_IMAGE_BASE_URL}/evac.png`, - identifiers: ['evac-panel', 'evac', 'evacuation', 'command-switch', 'horn-shut-off-button', 'capt-purs-switch'], + name: 'EVAC Panel', + title: 'FlyByWire A32NX | Evacuation Panel', + docsUrl: `${OVHD_DOCS_BASE_URL}/evacuation/`, + flightDeckUrl: LOCATE_DOCS_BASE_URLS.a32nx.flightdeck, + imageUrl: `${OVHD_IMAGE_BASE_URL}/evac.png`, + identifiers: ['evac-panel', 'evac', 'evacuation', 'command-switch', 'horn-shut-off-button', 'capt-purs-switch'], }; export const fltCtlPanel: Panel = { - name: 'FLT CLT Panel', - title: 'FlyByWire A32NX | Flight Control Panel', - docsUrl: `${OVHD_DOCS_BASE_URL}/flight-control-computer/`, - flightDeckUrl: LOCATE_DOCS_BASE_URLS.a32nx.flightdeck, - imageUrl: `${OVHD_IMAGE_BASE_URL}/flt_ctl.png`, - identifiers: ['flight-controls', 'flight-control-panel', 'flt-ctl', 'elac', 'sec', 'fac'], + name: 'FLT CLT Panel', + title: 'FlyByWire A32NX | Flight Control Panel', + docsUrl: `${OVHD_DOCS_BASE_URL}/flight-control-computer/`, + flightDeckUrl: LOCATE_DOCS_BASE_URLS.a32nx.flightdeck, + imageUrl: `${OVHD_IMAGE_BASE_URL}/flt_ctl.png`, + identifiers: ['flight-controls', 'flight-control-panel', 'flt-ctl', 'elac', 'sec', 'fac'], }; export const adirsPanel: Panel = { - name: 'ADIRS Panel', - title: 'FlyByWire A32NX | ADIRS Panel', - docsUrl: `${OVHD_DOCS_BASE_URL}/adirs/`, - flightDeckUrl: LOCATE_DOCS_BASE_URLS.a32nx.flightdeck, - imageUrl: `${OVHD_IMAGE_BASE_URL}/adirs.png`, - identifiers: ['adirs-panel', 'adirs', 'adiru', 'irs', 'adr', 'ir-selector'], + name: 'ADIRS Panel', + title: 'FlyByWire A32NX | ADIRS Panel', + docsUrl: `${OVHD_DOCS_BASE_URL}/adirs/`, + flightDeckUrl: LOCATE_DOCS_BASE_URLS.a32nx.flightdeck, + imageUrl: `${OVHD_IMAGE_BASE_URL}/adirs.png`, + identifiers: ['adirs-panel', 'adirs', 'adiru', 'irs', 'adr', 'ir-selector'], }; export const paVideoPanel: Panel = { - name: 'PA and Cockpit Video Panel', - title: 'FlyByWire A32NX | PA and Cockpit Video Panel', - docsUrl: `${OVHD_DOCS_BASE_URL}/pa-cockpit-video/`, - flightDeckUrl: LOCATE_DOCS_BASE_URLS.a32nx.flightdeck, - imageUrl: `${OVHD_IMAGE_BASE_URL}/pa_video.png`, - identifiers: ['pa-panel', 'video', 'cockpit-video-panel', 'cockpit-door-video', 'cockpit-door-video-switch'], + name: 'PA and Cockpit Video Panel', + title: 'FlyByWire A32NX | PA and Cockpit Video Panel', + docsUrl: `${OVHD_DOCS_BASE_URL}/pa-cockpit-video/`, + flightDeckUrl: LOCATE_DOCS_BASE_URLS.a32nx.flightdeck, + imageUrl: `${OVHD_IMAGE_BASE_URL}/pa_video.png`, + identifiers: ['pa-panel', 'video', 'cockpit-video-panel', 'cockpit-door-video', 'cockpit-door-video-switch'], }; export const extLtPanel: Panel = { - name: 'EXT LT Panel', - title: 'FlyByWire A32NX | Exterior Lighting Panel', - docsUrl: `${OVHD_DOCS_BASE_URL}/ext-lt/`, - flightDeckUrl: LOCATE_DOCS_BASE_URLS.a32nx.flightdeck, - imageUrl: `${OVHD_IMAGE_BASE_URL}/ext_lt.png`, - identifiers: [ - 'ext-lt-panel', - 'ext-lt', - 'exterior-lights', - 'strobe-switch', - 'beacon-switch', - 'wing-switch', - 'nav-logo-switch', - 'rwy-turn-off-switch', - 'land-switch', - 'taxi-switch', - 'strobes', - 'wing-lights', - 'runway-turnoff-lights', - 'landing-lights', - 'taxi-lights', - 'logo-lights', - ], + name: 'EXT LT Panel', + title: 'FlyByWire A32NX | Exterior Lighting Panel', + docsUrl: `${OVHD_DOCS_BASE_URL}/ext-lt/`, + flightDeckUrl: LOCATE_DOCS_BASE_URLS.a32nx.flightdeck, + imageUrl: `${OVHD_IMAGE_BASE_URL}/ext_lt.png`, + identifiers: [ + 'ext-lt-panel', + 'ext-lt', + 'exterior-lights', + 'strobe-switch', + 'beacon-switch', + 'wing-switch', + 'nav-logo-switch', + 'rwy-turn-off-switch', + 'land-switch', + 'taxi-switch', + 'strobes', + 'wing-lights', + 'runway-turnoff-lights', + 'landing-lights', + 'taxi-lights', + 'logo-lights', + ], }; export const apuPanel: Panel = { - name: 'APU Panel', - title: 'FlyByWire A32NX | APU Panel', - docsUrl: `${OVHD_DOCS_BASE_URL}/apu/`, - flightDeckUrl: LOCATE_DOCS_BASE_URLS.a32nx.flightdeck, - imageUrl: `${OVHD_IMAGE_BASE_URL}/apu.png`, - identifiers: ['apu-panel', 'apu', 'auxiliary-power-unit', 'apu-master-switch', 'apu-start-button'], + name: 'APU Panel', + title: 'FlyByWire A32NX | APU Panel', + docsUrl: `${OVHD_DOCS_BASE_URL}/apu/`, + flightDeckUrl: LOCATE_DOCS_BASE_URLS.a32nx.flightdeck, + imageUrl: `${OVHD_IMAGE_BASE_URL}/apu.png`, + identifiers: ['apu-panel', 'apu', 'auxiliary-power-unit', 'apu-master-switch', 'apu-start-button'], }; export const signsPanel: Panel = { - name: 'Signs Panel', - title: 'FlyByWire A32NX | Signs Panel', - docsUrl: `${OVHD_DOCS_BASE_URL}/signs/`, - flightDeckUrl: LOCATE_DOCS_BASE_URLS.a32nx.flightdeck, - imageUrl: `${OVHD_IMAGE_BASE_URL}/signs.png`, - identifiers: [ - 'signs-panel', - 'signs', - 'seat-belts', - 'no-smoking', - 'no-portable-devices', - 'emergency-exit-lights', - 'emer-exit-lights', - ], + name: 'Signs Panel', + title: 'FlyByWire A32NX | Signs Panel', + docsUrl: `${OVHD_DOCS_BASE_URL}/signs/`, + flightDeckUrl: LOCATE_DOCS_BASE_URLS.a32nx.flightdeck, + imageUrl: `${OVHD_IMAGE_BASE_URL}/signs.png`, + identifiers: [ + 'signs-panel', + 'signs', + 'seat-belts', + 'no-smoking', + 'no-portable-devices', + 'emergency-exit-lights', + 'emer-exit-lights', + ], }; export const intLtPanel: Panel = { - name: 'INT LT Panel', - title: 'FlyByWire A32NX | Internal Lights Panel', - docsUrl: `${OVHD_DOCS_BASE_URL}/int-lt/`, - flightDeckUrl: LOCATE_DOCS_BASE_URLS.a32nx.flightdeck, - imageUrl: `${OVHD_IMAGE_BASE_URL}/int_lt.png`, - identifiers: [ - 'int-lt', - 'int-lt-panel', - 'dome-light', - 'overhead-integrated-light', - 'ovhd-integ-lt-knob', - 'ice-ind-stby-compass-switch', - 'dome-switch', - 'annunciator-lights', - 'ann-lt-switch', - ], + name: 'INT LT Panel', + title: 'FlyByWire A32NX | Internal Lights Panel', + docsUrl: `${OVHD_DOCS_BASE_URL}/int-lt/`, + flightDeckUrl: LOCATE_DOCS_BASE_URLS.a32nx.flightdeck, + imageUrl: `${OVHD_IMAGE_BASE_URL}/int_lt.png`, + identifiers: [ + 'int-lt', + 'int-lt-panel', + 'dome-light', + 'overhead-integrated-light', + 'ovhd-integ-lt-knob', + 'ice-ind-stby-compass-switch', + 'dome-switch', + 'annunciator-lights', + 'ann-lt-switch', + ], }; export const antiIcePanel: Panel = { - name: 'Anti Ice Panel', - title: 'FlyByWire A32NX | Anti Ice Panel', - docsUrl: `${OVHD_DOCS_BASE_URL}/anti-ice/`, - flightDeckUrl: LOCATE_DOCS_BASE_URLS.a32nx.flightdeck, - imageUrl: `${OVHD_IMAGE_BASE_URL}/anti_ice.png`, - identifiers: [ - 'icing', - 'anti-ice-panel', - 'anti-ice', - 'window-heat', - 'probe-heat', - 'wing-anti-ice-switch', - 'engine-anti-ice-switch', - 'probe-window-heat-switch', - ], + name: 'Anti Ice Panel', + title: 'FlyByWire A32NX | Anti Ice Panel', + docsUrl: `${OVHD_DOCS_BASE_URL}/anti-ice/`, + flightDeckUrl: LOCATE_DOCS_BASE_URLS.a32nx.flightdeck, + imageUrl: `${OVHD_IMAGE_BASE_URL}/anti_ice.png`, + identifiers: [ + 'icing', + 'anti-ice-panel', + 'anti-ice', + 'window-heat', + 'probe-heat', + 'wing-anti-ice-switch', + 'engine-anti-ice-switch', + 'probe-window-heat-switch', + ], }; export const cabinPressPanel: Panel = { - name: 'CABIN PRESS Panel', - title: 'FlyByWire A32NX | Cabin Pressurization Panel', - docsUrl: `${OVHD_DOCS_BASE_URL}/cab-press/`, - flightDeckUrl: LOCATE_DOCS_BASE_URLS.a32nx.flightdeck, - imageUrl: `${OVHD_IMAGE_BASE_URL}/cabin_press.png`, - identifiers: [ - 'cabin-press', - 'cabin-press-panel', - 'pressurization', - 'cabin-pressure', - 'pressure', - 'landing-elevation', - 'man-vs-ctl-switch', - 'cabin-press-mode-sel-switch', - 'ldg-elev-knob', - 'ditching-switch', - ], + name: 'CABIN PRESS Panel', + title: 'FlyByWire A32NX | Cabin Pressurization Panel', + docsUrl: `${OVHD_DOCS_BASE_URL}/cab-press/`, + flightDeckUrl: LOCATE_DOCS_BASE_URLS.a32nx.flightdeck, + imageUrl: `${OVHD_IMAGE_BASE_URL}/cabin_press.png`, + identifiers: [ + 'cabin-press', + 'cabin-press-panel', + 'pressurization', + 'cabin-pressure', + 'pressure', + 'landing-elevation', + 'man-vs-ctl-switch', + 'cabin-press-mode-sel-switch', + 'ldg-elev-knob', + 'ditching-switch', + ], }; export const airCondPanel: Panel = { - name: 'AIR COND Panel', - title: 'FlyByWire A32NX | Air Condition Control Panel', - docsUrl: `${OVHD_DOCS_BASE_URL}/ac/`, - flightDeckUrl: LOCATE_DOCS_BASE_URLS.a32nx.flightdeck, - imageUrl: `${OVHD_IMAGE_BASE_URL}/air_cond.png`, - identifiers: [ - 'air-cond', - 'air-cond-panel', - 'ac-panel', - 'air-cond-panel', - 'packs', - 'bleed', - 'bleed-air', - 'pack-flow-selector', - 'pack-switch', - 'pack-flow-switch', - 'eng-bleed-switch', - 'engine-bleed-switch', - 'ram-air-switch', - 'apu-bleed', - 'x-bleed-selector', - 'cross-bleed-selector', - 'hot-air-switch', - 'cabin-temp-selector', - ], + name: 'AIR COND Panel', + title: 'FlyByWire A32NX | Air Condition Control Panel', + docsUrl: `${OVHD_DOCS_BASE_URL}/ac/`, + flightDeckUrl: LOCATE_DOCS_BASE_URLS.a32nx.flightdeck, + imageUrl: `${OVHD_IMAGE_BASE_URL}/air_cond.png`, + identifiers: [ + 'air-cond', + 'air-cond-panel', + 'ac-panel', + 'air-cond-panel', + 'packs', + 'bleed', + 'bleed-air', + 'pack-flow-selector', + 'pack-switch', + 'pack-flow-switch', + 'eng-bleed-switch', + 'engine-bleed-switch', + 'ram-air-switch', + 'apu-bleed', + 'x-bleed-selector', + 'cross-bleed-selector', + 'hot-air-switch', + 'cabin-temp-selector', + ], }; export const elecPanel: Panel = { - name: 'ELEC Panel', - title: 'FlyByWire A32NX | Electrical System Panel', - docsUrl: `${OVHD_DOCS_BASE_URL}/elec/`, - flightDeckUrl: LOCATE_DOCS_BASE_URLS.a32nx.flightdeck, - imageUrl: `${OVHD_IMAGE_BASE_URL}/elec.png`, - identifiers: [ - 'elec', - 'elec-panel', - 'electrical-panel', - 'generators', - 'ac-bus', - 'dc-bus', - 'batteries', - 'external-power', - 'commercial-pwr-switch', - 'galy-cab-pwr-switch', - 'idg-switch', - 'eng-gen-switch', - 'engine-generator-switch', - 'apu-gen-switch', - 'bus-tie-switch', - 'ext-pwr-switch', - 'ac-ess-feed-switch', - 'battery-switch', - 'bat-switch', - ], + name: 'ELEC Panel', + title: 'FlyByWire A32NX | Electrical System Panel', + docsUrl: `${OVHD_DOCS_BASE_URL}/elec/`, + flightDeckUrl: LOCATE_DOCS_BASE_URLS.a32nx.flightdeck, + imageUrl: `${OVHD_IMAGE_BASE_URL}/elec.png`, + identifiers: [ + 'elec', + 'elec-panel', + 'electrical-panel', + 'generators', + 'ac-bus', + 'dc-bus', + 'batteries', + 'external-power', + 'commercial-pwr-switch', + 'galy-cab-pwr-switch', + 'idg-switch', + 'eng-gen-switch', + 'engine-generator-switch', + 'apu-gen-switch', + 'bus-tie-switch', + 'ext-pwr-switch', + 'ac-ess-feed-switch', + 'battery-switch', + 'bat-switch', + ], }; export const fuelPanel: Panel = { - name: 'FUEL Panel', - title: 'FlyByWire A32NX | Fuel Control Panel', - docsUrl: `${OVHD_DOCS_BASE_URL}/fuel/`, - flightDeckUrl: LOCATE_DOCS_BASE_URLS.a32nx.flightdeck, - imageUrl: `${OVHD_IMAGE_BASE_URL}/fuel.png`, - identifiers: ['fuel', 'fuel-panel', 'fuel-pumps', 'x-feed', 'cross-feed', 'wing-tanks', 'center-tanks'], + name: 'FUEL Panel', + title: 'FlyByWire A32NX | Fuel Control Panel', + docsUrl: `${OVHD_DOCS_BASE_URL}/fuel/`, + flightDeckUrl: LOCATE_DOCS_BASE_URLS.a32nx.flightdeck, + imageUrl: `${OVHD_IMAGE_BASE_URL}/fuel.png`, + identifiers: ['fuel', 'fuel-panel', 'fuel-pumps', 'x-feed', 'cross-feed', 'wing-tanks', 'center-tanks'], }; export const hydPanel: Panel = { - name: 'HYD Panel', - title: 'FlyByWire A32NX | Hydraulics Control Panel', - docsUrl: `${OVHD_DOCS_BASE_URL}/hyd/`, - flightDeckUrl: LOCATE_DOCS_BASE_URLS.a32nx.flightdeck, - imageUrl: `${OVHD_IMAGE_BASE_URL}/hyd.png`, - identifiers: [ - 'hyd', - 'hydraulics-panel', - 'green-system', - 'blue-system', - 'yellow-system', - 'rat', - 'ptu', - 'eng-hyd-pump-switch', - 'engine-hydraulics-pump-switch', - 'elec-hyd-pump', - 'rat-man-on-switch', - ], + name: 'HYD Panel', + title: 'FlyByWire A32NX | Hydraulics Control Panel', + docsUrl: `${OVHD_DOCS_BASE_URL}/hyd/`, + flightDeckUrl: LOCATE_DOCS_BASE_URLS.a32nx.flightdeck, + imageUrl: `${OVHD_IMAGE_BASE_URL}/hyd.png`, + identifiers: [ + 'hyd', + 'hydraulics-panel', + 'green-system', + 'blue-system', + 'yellow-system', + 'rat', + 'ptu', + 'eng-hyd-pump-switch', + 'engine-hydraulics-pump-switch', + 'elec-hyd-pump', + 'rat-man-on-switch', + ], }; export const firePanel: Panel = { - name: 'FIRE Panel', - title: 'FlyByWire A32NX | Fire Control Panel', - docsUrl: `${OVHD_DOCS_BASE_URL}/fire/`, - flightDeckUrl: LOCATE_DOCS_BASE_URLS.a32nx.flightdeck, - imageUrl: `${OVHD_IMAGE_BASE_URL}/fire.png`, - identifiers: ['engine-fire-panel', 'fire', 'smoke', 'fire-agent', 'disch'], + name: 'FIRE Panel', + title: 'FlyByWire A32NX | Fire Control Panel', + docsUrl: `${OVHD_DOCS_BASE_URL}/fire/`, + flightDeckUrl: LOCATE_DOCS_BASE_URLS.a32nx.flightdeck, + imageUrl: `${OVHD_IMAGE_BASE_URL}/fire.png`, + identifiers: ['engine-fire-panel', 'fire', 'smoke', 'fire-agent', 'disch'], }; export const engManStartPanel: Panel = { - name: 'ENG MAN START Panel', - title: 'FlyByWire A32NX | Engine Manual Start Panel', - docsUrl: `${OVHD_DOCS_BASE_URL}/eng-man/`, - flightDeckUrl: LOCATE_DOCS_BASE_URLS.a32nx.flightdeck, - imageUrl: `${OVHD_IMAGE_BASE_URL}/eng_n1.png`, - identifiers: ['eng-n1', 'manual-engine-start', 'eng-man-start-switch'], + name: 'ENG MAN START Panel', + title: 'FlyByWire A32NX | Engine Manual Start Panel', + docsUrl: `${OVHD_DOCS_BASE_URL}/eng-man/`, + flightDeckUrl: LOCATE_DOCS_BASE_URLS.a32nx.flightdeck, + imageUrl: `${OVHD_IMAGE_BASE_URL}/eng_n1.png`, + identifiers: ['eng-n1', 'manual-engine-start', 'eng-man-start-switch'], }; export const ventilationPanel: Panel = { - name: 'Ventilation Panel', - title: 'FlyByWire A32NX | Ventilation Panel', - docsUrl: `${OVHD_DOCS_BASE_URL}/vent/`, - flightDeckUrl: LOCATE_DOCS_BASE_URLS.a32nx.flightdeck, - imageUrl: `${OVHD_IMAGE_BASE_URL}/ventilation.png`, - identifiers: ['vent', 'ventilation-panel', 'cabin-fans', 'blower-switch', 'extract-ventilation-switch'], + name: 'Ventilation Panel', + title: 'FlyByWire A32NX | Ventilation Panel', + docsUrl: `${OVHD_DOCS_BASE_URL}/vent/`, + flightDeckUrl: LOCATE_DOCS_BASE_URLS.a32nx.flightdeck, + imageUrl: `${OVHD_IMAGE_BASE_URL}/ventilation.png`, + identifiers: ['vent', 'ventilation-panel', 'cabin-fans', 'blower-switch', 'extract-ventilation-switch'], }; export const cargoSmokePanel: Panel = { - name: 'CARGO SMOKE Panel', - title: 'FlyByWire A32NX | Cargo Smoke Panel', - docsUrl: `${OVHD_DOCS_BASE_URL}/cargo-smoke/`, - flightDeckUrl: LOCATE_DOCS_BASE_URLS.a32nx.flightdeck, - imageUrl: `${OVHD_IMAGE_BASE_URL}/cargo_smoke.png`, - identifiers: ['cargo-fire', 'cargo-smoke-panel'], + name: 'CARGO SMOKE Panel', + title: 'FlyByWire A32NX | Cargo Smoke Panel', + docsUrl: `${OVHD_DOCS_BASE_URL}/cargo-smoke/`, + flightDeckUrl: LOCATE_DOCS_BASE_URLS.a32nx.flightdeck, + imageUrl: `${OVHD_IMAGE_BASE_URL}/cargo_smoke.png`, + identifiers: ['cargo-fire', 'cargo-smoke-panel'], }; export const cargoVentPanel: Panel = { - name: 'CARGO VENT Panel', - title: 'FlyByWire A32NX | Cargo Vent Panel', - docsUrl: `${OVHD_DOCS_BASE_URL}/cargo-vent/`, - flightDeckUrl: LOCATE_DOCS_BASE_URLS.a32nx.flightdeck, - imageUrl: `${OVHD_IMAGE_BASE_URL}/cargo_vent.png`, - identifiers: ['cargo-vent-panel', 'cargo-ventilation', 'aft-isol-valve-switch'], + name: 'CARGO VENT Panel', + title: 'FlyByWire A32NX | Cargo Vent Panel', + docsUrl: `${OVHD_DOCS_BASE_URL}/cargo-vent/`, + flightDeckUrl: LOCATE_DOCS_BASE_URLS.a32nx.flightdeck, + imageUrl: `${OVHD_IMAGE_BASE_URL}/cargo_vent.png`, + identifiers: ['cargo-vent-panel', 'cargo-ventilation', 'aft-isol-valve-switch'], }; export const thirdACP: Panel = { - name: '3rd ACP', - title: 'FlyByWire A32NX | 3rd Audio Control Panel', - docsUrl: `${OVHD_DOCS_BASE_URL}/3rd-acp/`, - flightDeckUrl: LOCATE_DOCS_BASE_URLS.a32nx.flightdeck, - imageUrl: `${OVHD_IMAGE_BASE_URL}/acp_3.png`, - identifiers: ['acp3', '3rd-acp', '3rd-audio-control-panel'], + name: '3rd ACP', + title: 'FlyByWire A32NX | 3rd Audio Control Panel', + docsUrl: `${OVHD_DOCS_BASE_URL}/3rd-acp/`, + flightDeckUrl: LOCATE_DOCS_BASE_URLS.a32nx.flightdeck, + imageUrl: `${OVHD_IMAGE_BASE_URL}/acp_3.png`, + identifiers: ['acp3', '3rd-acp', '3rd-audio-control-panel'], }; export const readingLightsJumpSeats: Panel = { - name: 'Jump Seats Reading Light Panel', - title: 'FlyByWire A32NX | Reading Lights Jump Seats', - docsUrl: `${AFT_OVHD_DOCS_BASE_URL}/reading-light/`, - flightDeckUrl: LOCATE_DOCS_BASE_URLS.a32nx.flightdeck, - imageUrl: `${AFT_OVHD_IMAGE_BASE_URL}/jump_seat_reading_lt.png`, - identifiers: ['reading-lights-jump-seat', 'jump-seat-reading-lights'], + name: 'Jump Seats Reading Light Panel', + title: 'FlyByWire A32NX | Reading Lights Jump Seats', + docsUrl: `${AFT_OVHD_DOCS_BASE_URL}/reading-light/`, + flightDeckUrl: LOCATE_DOCS_BASE_URLS.a32nx.flightdeck, + imageUrl: `${AFT_OVHD_IMAGE_BASE_URL}/jump_seat_reading_lt.png`, + identifiers: ['reading-lights-jump-seat', 'jump-seat-reading-lights'], }; export const cockpitDoorIndicatorPanel: Panel = { - name: 'CKPT DOOR CONT Panel', - title: 'FlyByWire A32NX | Cockpit Door Panel', - docsUrl: `${AFT_OVHD_DOCS_BASE_URL}/cockpit-door/#description`, - flightDeckUrl: LOCATE_DOCS_BASE_URLS.a32nx.flightdeck, - imageUrl: `${AFT_OVHD_IMAGE_BASE_URL}/ckpt_door_cont.png`, - identifiers: ['cockpit-door-cont', 'cockpit-door-indicator-panel'], + name: 'CKPT DOOR CONT Panel', + title: 'FlyByWire A32NX | Cockpit Door Panel', + docsUrl: `${AFT_OVHD_DOCS_BASE_URL}/cockpit-door/#description`, + flightDeckUrl: LOCATE_DOCS_BASE_URLS.a32nx.flightdeck, + imageUrl: `${AFT_OVHD_IMAGE_BASE_URL}/ckpt_door_cont.png`, + identifiers: ['cockpit-door-cont', 'cockpit-door-indicator-panel'], }; export const eltPanel: Panel = { - name: 'ELT Panel', - title: 'FlyByWire A32NX | ELT Panel', - docsUrl: `${AFT_OVHD_DOCS_BASE_URL}/elt/`, - flightDeckUrl: LOCATE_DOCS_BASE_URLS.a32nx.flightdeck, - imageUrl: `${AFT_OVHD_IMAGE_BASE_URL}/elt.png`, - identifiers: ['elt', 'elt-panel', 'emergency-locator-transmitter'], + name: 'ELT Panel', + title: 'FlyByWire A32NX | ELT Panel', + docsUrl: `${AFT_OVHD_DOCS_BASE_URL}/elt/`, + flightDeckUrl: LOCATE_DOCS_BASE_URLS.a32nx.flightdeck, + imageUrl: `${AFT_OVHD_IMAGE_BASE_URL}/elt.png`, + identifiers: ['elt', 'elt-panel', 'emergency-locator-transmitter'], }; export const pedestalLightPanel: Panel = { - name: 'Pedestal Light Panel', - title: 'FlyByWire A32NX | Pedestal Light and Audio 3 Switch', - docsUrl: `${AFT_OVHD_DOCS_BASE_URL}/pedestal-light/`, - flightDeckUrl: LOCATE_DOCS_BASE_URLS.a32nx.flightdeck, - imageUrl: `${AFT_OVHD_IMAGE_BASE_URL}/pedestal_light.png`, - identifiers: ['pedestal-light-panel', 'acp3-switching-selector', 'audio-control-panel-3-switching-selector'], + name: 'Pedestal Light Panel', + title: 'FlyByWire A32NX | Pedestal Light and Audio 3 Switch', + docsUrl: `${AFT_OVHD_DOCS_BASE_URL}/pedestal-light/`, + flightDeckUrl: LOCATE_DOCS_BASE_URLS.a32nx.flightdeck, + imageUrl: `${AFT_OVHD_IMAGE_BASE_URL}/pedestal_light.png`, + identifiers: ['pedestal-light-panel', 'acp3-switching-selector', 'audio-control-panel-3-switching-selector'], }; export const emerCbPanel: Panel = { - name: 'EMER CB Panel', - title: 'FlyByWire A32NX | Emergency Circuit Breaker Panel', - docsUrl: `${AFT_OVHD_DOCS_BASE_URL}/circuit/`, - flightDeckUrl: LOCATE_DOCS_BASE_URLS.a32nx.flightdeck, - imageUrl: `${AFT_OVHD_IMAGE_BASE_URL}/emer_cb.png`, - identifiers: ['emer-cb', 'emergency-circuit-breaker-panel'], + name: 'EMER CB Panel', + title: 'FlyByWire A32NX | Emergency Circuit Breaker Panel', + docsUrl: `${AFT_OVHD_DOCS_BASE_URL}/circuit/`, + flightDeckUrl: LOCATE_DOCS_BASE_URLS.a32nx.flightdeck, + imageUrl: `${AFT_OVHD_IMAGE_BASE_URL}/emer_cb.png`, + identifiers: ['emer-cb', 'emergency-circuit-breaker-panel'], }; export const fmsLoadPanel: Panel = { - name: 'FMS LOAD Panel', - title: 'FlyByWire A32NX | FMS Load Panel', - docsUrl: `${AFT_OVHD_DOCS_BASE_URL}/fms-load/`, - flightDeckUrl: LOCATE_DOCS_BASE_URLS.a32nx.flightdeck, - imageUrl: `${AFT_OVHD_IMAGE_BASE_URL}/fms_load.png`, - identifiers: ['fms-load-panel'], + name: 'FMS LOAD Panel', + title: 'FlyByWire A32NX | FMS Load Panel', + docsUrl: `${AFT_OVHD_DOCS_BASE_URL}/fms-load/`, + flightDeckUrl: LOCATE_DOCS_BASE_URLS.a32nx.flightdeck, + imageUrl: `${AFT_OVHD_IMAGE_BASE_URL}/fms_load.png`, + identifiers: ['fms-load-panel'], }; export const maintenancePanel: Panel = { - name: 'Maintenance Panel', - title: 'FlyByWire A32NX | Maintenance Panel', - docsUrl: `${AFT_OVHD_DOCS_BASE_URL}/maintenance/`, - flightDeckUrl: LOCATE_DOCS_BASE_URLS.a32nx.flightdeck, - imageUrl: `${AFT_OVHD_IMAGE_BASE_URL}/maintenance.png`, - identifiers: [ - 'maintenance', - 'maintenance-panel', - 'fadec-ground-power-switch', - 'blue-pump-override-switch', - 'hyd-leak-measurement-valves-switch', - 'oxygen-tmr-reset-switch', - 'svge-int-ovrd-switch', - 'avionics-comp-lt-switch', - ], + name: 'Maintenance Panel', + title: 'FlyByWire A32NX | Maintenance Panel', + docsUrl: `${AFT_OVHD_DOCS_BASE_URL}/maintenance/`, + flightDeckUrl: LOCATE_DOCS_BASE_URLS.a32nx.flightdeck, + imageUrl: `${AFT_OVHD_IMAGE_BASE_URL}/maintenance.png`, + identifiers: [ + 'maintenance', + 'maintenance-panel', + 'fadec-ground-power-switch', + 'blue-pump-override-switch', + 'hyd-leak-measurement-valves-switch', + 'oxygen-tmr-reset-switch', + 'svge-int-ovrd-switch', + 'avionics-comp-lt-switch', + ], }; diff --git a/src/commands/utils/locate/panels/a32nx/pedestal.ts b/src/commands/utils/locate/panels/a32nx/pedestal.ts index 81f3f862..de74478f 100644 --- a/src/commands/utils/locate/panels/a32nx/pedestal.ts +++ b/src/commands/utils/locate/panels/a32nx/pedestal.ts @@ -5,205 +5,199 @@ const PEDESTAL_DOCS_BASE_URL = LOCATE_DOCS_BASE_URLS.a32nx.pedestal; const PEDESTAL_IMAGE_BASE_URL = LOCATE_IMAGE_BASE_URLS.a32nx.pedestal; export const console: Panel = { - name: 'Console', - title: 'FlyByWire A32NX | Console', - docsUrl: `${PEDESTAL_DOCS_BASE_URL}/console`, - flightDeckUrl: LOCATE_DOCS_BASE_URLS.a32nx.flightdeck, - imageUrl: `${PEDESTAL_IMAGE_BASE_URL}/console.png`, - identifiers: [ - 'console', - 'sidestick', - 'side-stick', - 'ap-disc-button', - 'autopilot-disconnect-button', - 'tiller', - 'pedal-disconnect-button', - ], + name: 'Console', + title: 'FlyByWire A32NX | Console', + docsUrl: `${PEDESTAL_DOCS_BASE_URL}/console`, + flightDeckUrl: LOCATE_DOCS_BASE_URLS.a32nx.flightdeck, + imageUrl: `${PEDESTAL_IMAGE_BASE_URL}/console.png`, + identifiers: [ + 'console', + 'sidestick', + 'side-stick', + 'ap-disc-button', + 'autopilot-disconnect-button', + 'tiller', + 'pedal-disconnect-button', + ], }; export const mcdu: Panel = { - name: 'MCDU', - title: 'FlyByWire A32NX | Multipurpose Control & Display Unit (MCDU)', - docsUrl: `${PEDESTAL_DOCS_BASE_URL}/mcdu`, - flightDeckUrl: LOCATE_DOCS_BASE_URLS.a32nx.flightdeck, - imageUrl: `${PEDESTAL_IMAGE_BASE_URL}/mcdu.png`, - identifiers: ['fms', 'cdu', 'mcdu', 'fmgc'], + name: 'MCDU', + title: 'FlyByWire A32NX | Multipurpose Control & Display Unit (MCDU)', + docsUrl: `${PEDESTAL_DOCS_BASE_URL}/mcdu`, + flightDeckUrl: LOCATE_DOCS_BASE_URLS.a32nx.flightdeck, + imageUrl: `${PEDESTAL_IMAGE_BASE_URL}/mcdu.png`, + identifiers: ['fms', 'cdu', 'mcdu', 'fmgc'], }; export const rmpAcpPanel: Panel = { - name: 'RMP/ACP Panel', - title: 'FlyByWire A32NX | Radio Management and Audio Control Panel', - docsUrl: `${PEDESTAL_DOCS_BASE_URL}/rmp`, - flightDeckUrl: LOCATE_DOCS_BASE_URLS.a32nx.flightdeck, - imageUrl: `${PEDESTAL_IMAGE_BASE_URL}/rmp_acp.png`, - identifiers: ['rmp', 'radio-management-panel', 'acp', 'audio-control-panel', 'atc-panel'], + name: 'RMP/ACP Panel', + title: 'FlyByWire A32NX | Radio Management and Audio Control Panel', + docsUrl: `${PEDESTAL_DOCS_BASE_URL}/rmp`, + flightDeckUrl: LOCATE_DOCS_BASE_URLS.a32nx.flightdeck, + imageUrl: `${PEDESTAL_IMAGE_BASE_URL}/rmp_acp.png`, + identifiers: ['rmp', 'radio-management-panel', 'acp', 'audio-control-panel', 'atc-panel'], }; export const captPedestalLightingPanel: Panel = { - name: 'Pedestal Lighting Panel', - title: 'FlyByWire A32NX | Pedestal Lighting Panel (Captain Side)', - docsUrl: `${PEDESTAL_DOCS_BASE_URL}/lighting-capt`, - flightDeckUrl: LOCATE_DOCS_BASE_URLS.a32nx.flightdeck, - imageUrl: `${PEDESTAL_IMAGE_BASE_URL}/capt_pedestal_lt.png`, - identifiers: ['captain-pedestal-lighting-panel'], + name: 'Pedestal Lighting Panel', + title: 'FlyByWire A32NX | Pedestal Lighting Panel (Captain Side)', + docsUrl: `${PEDESTAL_DOCS_BASE_URL}/lighting-capt`, + flightDeckUrl: LOCATE_DOCS_BASE_URLS.a32nx.flightdeck, + imageUrl: `${PEDESTAL_IMAGE_BASE_URL}/capt_pedestal_lt.png`, + identifiers: ['captain-pedestal-lighting-panel'], }; export const wxPanel: Panel = { - name: 'WX Radar', - title: 'Weather Radar Panel', - docsUrl: `${PEDESTAL_DOCS_BASE_URL}/radar`, - flightDeckUrl: LOCATE_DOCS_BASE_URLS.a32nx.flightdeck, - imageUrl: `${PEDESTAL_IMAGE_BASE_URL}/wx_radar.png`, - identifiers: ['wx', 'weather-radar', 'wx-radar', 'pws', 'predictive-windshear-systems'], + name: 'WX Radar', + title: 'Weather Radar Panel', + docsUrl: `${PEDESTAL_DOCS_BASE_URL}/radar`, + flightDeckUrl: LOCATE_DOCS_BASE_URLS.a32nx.flightdeck, + imageUrl: `${PEDESTAL_IMAGE_BASE_URL}/wx_radar.png`, + identifiers: ['wx', 'weather-radar', 'wx-radar', 'pws', 'predictive-windshear-systems'], }; export const speedBrake: Panel = { - name: 'Speed Brake', - title: 'FlyByWire A32NX | Speed Brake', - docsUrl: `${PEDESTAL_DOCS_BASE_URL}/speedbrake`, - flightDeckUrl: LOCATE_DOCS_BASE_URLS.a32nx.flightdeck, - imageUrl: `${PEDESTAL_IMAGE_BASE_URL}/spd_brk.png`, - identifiers: ['speed-brake', 'spd-brk', 'spoilers', 'gnd-sprls'], + name: 'Speed Brake', + title: 'FlyByWire A32NX | Speed Brake', + docsUrl: `${PEDESTAL_DOCS_BASE_URL}/speedbrake`, + flightDeckUrl: LOCATE_DOCS_BASE_URLS.a32nx.flightdeck, + imageUrl: `${PEDESTAL_IMAGE_BASE_URL}/spd_brk.png`, + identifiers: ['speed-brake', 'spd-brk', 'spoilers', 'gnd-sprls'], }; export const cockpitDoorPanel: Panel = { - name: 'Cockpit Door Panel', - title: 'FlyByWire A32NX | Cockpit Door Panel', - docsUrl: `${PEDESTAL_DOCS_BASE_URL}/cockpit-door`, - flightDeckUrl: LOCATE_DOCS_BASE_URLS.a32nx.flightdeck, - imageUrl: `${PEDESTAL_IMAGE_BASE_URL}/cockpit_door.png`, - identifiers: ['cockpit-door', 'cockpit-door-panel', 'cockpit-door-switch', 'cockpit-door-video-button'], + name: 'Cockpit Door Panel', + title: 'FlyByWire A32NX | Cockpit Door Panel', + docsUrl: `${PEDESTAL_DOCS_BASE_URL}/cockpit-door`, + flightDeckUrl: LOCATE_DOCS_BASE_URLS.a32nx.flightdeck, + imageUrl: `${PEDESTAL_IMAGE_BASE_URL}/cockpit_door.png`, + identifiers: ['cockpit-door', 'cockpit-door-panel', 'cockpit-door-switch', 'cockpit-door-video-button'], }; export const switchingPanel: Panel = { - name: 'Switching Panel', - title: 'FlyByWire A32NX | Switching Panel', - docsUrl: `${PEDESTAL_DOCS_BASE_URL}/switching`, - flightDeckUrl: LOCATE_DOCS_BASE_URLS.a32nx.flightdeck, - imageUrl: `${PEDESTAL_IMAGE_BASE_URL}/switching.png`, - identifiers: [ - 'switching', - 'switching-panel', - 'att-hdg-selector', - 'air-data-selector', - 'eis-dmc-selector', - 'ecam-nd-xfr-selector', - ], + name: 'Switching Panel', + title: 'FlyByWire A32NX | Switching Panel', + docsUrl: `${PEDESTAL_DOCS_BASE_URL}/switching`, + flightDeckUrl: LOCATE_DOCS_BASE_URLS.a32nx.flightdeck, + imageUrl: `${PEDESTAL_IMAGE_BASE_URL}/switching.png`, + identifiers: [ + 'switching', + 'switching-panel', + 'att-hdg-selector', + 'air-data-selector', + 'eis-dmc-selector', + 'ecam-nd-xfr-selector', + ], }; export const ecamControlPanel: Panel = { - name: 'ECAM Control Panel', - title: 'FlyByWire A32NX | ECAM Control Panel', - docsUrl: `${PEDESTAL_DOCS_BASE_URL}/ecam-control`, - flightDeckUrl: LOCATE_DOCS_BASE_URLS.a32nx.flightdeck, - imageUrl: `${PEDESTAL_IMAGE_BASE_URL}/ecam_ctl.png`, - identifiers: [ - 'ecam-control', - 'upper-ecam-display-brightness', - 'lower-ecam-display-brightness', - 'ecam-to-config', - 'to-config', - 'emer-canc', - 'ecam-clr', - 'ecam-rcl', - ], + name: 'ECAM Control Panel', + title: 'FlyByWire A32NX | ECAM Control Panel', + docsUrl: `${PEDESTAL_DOCS_BASE_URL}/ecam-control`, + flightDeckUrl: LOCATE_DOCS_BASE_URLS.a32nx.flightdeck, + imageUrl: `${PEDESTAL_IMAGE_BASE_URL}/ecam_ctl.png`, + identifiers: [ + 'ecam-control', + 'upper-ecam-display-brightness', + 'lower-ecam-display-brightness', + 'ecam-to-config', + 'to-config', + 'emer-canc', + 'ecam-clr', + 'ecam-rcl', + ], }; export const thrLvrPitchTrim: Panel = { - name: 'THR LVR/Pitch Trim Column', - title: 'FlyByWire A32NX | Thrust Lever and Pitch Trim Column', - docsUrl: `${PEDESTAL_DOCS_BASE_URL}/thrust-pitch-trim`, - flightDeckUrl: LOCATE_DOCS_BASE_URLS.a32nx.flightdeck, - imageUrl: `${PEDESTAL_IMAGE_BASE_URL}/thr_lvrs_pitch_trim.png`, - identifiers: [ - 'thr-lvr', - 'thrust-levers', - 'athr-disc-button', - 'autothrust-disconnect-button', - 'pitch-trim-wheels', - 'idle-detent', - 'cb-detent', - 'clb-detent', - 'flx-mct-detent', - 'toga-detent', - 'reversers', - ], + name: 'THR LVR/Pitch Trim Column', + title: 'FlyByWire A32NX | Thrust Lever and Pitch Trim Column', + docsUrl: `${PEDESTAL_DOCS_BASE_URL}/thrust-pitch-trim`, + flightDeckUrl: LOCATE_DOCS_BASE_URLS.a32nx.flightdeck, + imageUrl: `${PEDESTAL_IMAGE_BASE_URL}/thr_lvrs_pitch_trim.png`, + identifiers: [ + 'thr-lvr', + 'thrust-levers', + 'athr-disc-button', + 'autothrust-disconnect-button', + 'pitch-trim-wheels', + 'idle-detent', + 'cb-detent', + 'clb-detent', + 'flx-mct-detent', + 'toga-detent', + 'reversers', + ], }; export const engPanel: Panel = { - name: 'ENG Panel', - title: 'FlyByWire A32NX | Engine Panel', - docsUrl: `${PEDESTAL_DOCS_BASE_URL}/engine`, - flightDeckUrl: LOCATE_DOCS_BASE_URLS.a32nx.flightdeck, - imageUrl: `${PEDESTAL_IMAGE_BASE_URL}/eng.png`, - identifiers: [ - 'engine-panel', - 'engine-master', - 'engine-master-switches', - 'eng-mode-selector', - 'engine-mode-selector', - ], + name: 'ENG Panel', + title: 'FlyByWire A32NX | Engine Panel', + docsUrl: `${PEDESTAL_DOCS_BASE_URL}/engine`, + flightDeckUrl: LOCATE_DOCS_BASE_URLS.a32nx.flightdeck, + imageUrl: `${PEDESTAL_IMAGE_BASE_URL}/eng.png`, + identifiers: ['engine-panel', 'engine-master', 'engine-master-switches', 'eng-mode-selector', 'engine-mode-selector'], }; export const rudderTrim: Panel = { - name: 'Rudder Trim Panel', - title: 'FlyByWire A32NX | Rudder Trim Panel', - docsUrl: `${PEDESTAL_DOCS_BASE_URL}/rudder-trim`, - flightDeckUrl: LOCATE_DOCS_BASE_URLS.a32nx.flightdeck, - imageUrl: `${PEDESTAL_IMAGE_BASE_URL}/rudder_trim.png`, - identifiers: ['rudder-trim'], + name: 'Rudder Trim Panel', + title: 'FlyByWire A32NX | Rudder Trim Panel', + docsUrl: `${PEDESTAL_DOCS_BASE_URL}/rudder-trim`, + flightDeckUrl: LOCATE_DOCS_BASE_URLS.a32nx.flightdeck, + imageUrl: `${PEDESTAL_IMAGE_BASE_URL}/rudder_trim.png`, + identifiers: ['rudder-trim'], }; export const parkBrkPanel: Panel = { - name: 'Parking Brake Panel', - title: 'FlyByWire A32NX | Parking Brake Panel', - docsUrl: `${PEDESTAL_DOCS_BASE_URL}/parking-brake`, - flightDeckUrl: LOCATE_DOCS_BASE_URLS.a32nx.flightdeck, - imageUrl: `${PEDESTAL_IMAGE_BASE_URL}/park_brk.png`, - identifiers: ['parking-brake', 'park-brk'], + name: 'Parking Brake Panel', + title: 'FlyByWire A32NX | Parking Brake Panel', + docsUrl: `${PEDESTAL_DOCS_BASE_URL}/parking-brake`, + flightDeckUrl: LOCATE_DOCS_BASE_URLS.a32nx.flightdeck, + imageUrl: `${PEDESTAL_IMAGE_BASE_URL}/park_brk.png`, + identifiers: ['parking-brake', 'park-brk'], }; export const gravityGearExtensionPanel: Panel = { - name: 'Gravity Gear Extension Panel', - title: 'FlyByWire A32NX | Emergency Gravity Gear Extension Panel', - docsUrl: `${PEDESTAL_DOCS_BASE_URL}/gravity-gear-ext`, - flightDeckUrl: LOCATE_DOCS_BASE_URLS.a32nx.flightdeck, - imageUrl: `${PEDESTAL_IMAGE_BASE_URL}/gravity_gear_extn.png`, - identifiers: ['gravity-gear-extension'], + name: 'Gravity Gear Extension Panel', + title: 'FlyByWire A32NX | Emergency Gravity Gear Extension Panel', + docsUrl: `${PEDESTAL_DOCS_BASE_URL}/gravity-gear-ext`, + flightDeckUrl: LOCATE_DOCS_BASE_URLS.a32nx.flightdeck, + imageUrl: `${PEDESTAL_IMAGE_BASE_URL}/gravity_gear_extn.png`, + identifiers: ['gravity-gear-extension'], }; export const aidsDfdrPanel: Panel = { - name: 'AIDS/DFDR Panel', - title: 'FlyByWire A32NX | AIDS, DFDR Panel', - docsUrl: `${PEDESTAL_DOCS_BASE_URL}/lighting-aids-dfdr`, - flightDeckUrl: LOCATE_DOCS_BASE_URLS.a32nx.flightdeck, - imageUrl: `${PEDESTAL_IMAGE_BASE_URL}/aids_dfdr.png`, - identifiers: ['aids', 'dfdr', 'ped-flood-lt-knob', 'pedestal-flood-light-knob', 'aids-button', 'dfdr-button'], + name: 'AIDS/DFDR Panel', + title: 'FlyByWire A32NX | AIDS, DFDR Panel', + docsUrl: `${PEDESTAL_DOCS_BASE_URL}/lighting-aids-dfdr`, + flightDeckUrl: LOCATE_DOCS_BASE_URLS.a32nx.flightdeck, + imageUrl: `${PEDESTAL_IMAGE_BASE_URL}/aids_dfdr.png`, + identifiers: ['aids', 'dfdr', 'ped-flood-lt-knob', 'pedestal-flood-light-knob', 'aids-button', 'dfdr-button'], }; export const atcTcasPanel: Panel = { - name: 'ATC/TCAS Panel', - title: 'FlyByWire A32NX | ATC TCAS Panel', - docsUrl: `${PEDESTAL_DOCS_BASE_URL}/atc-tcas`, - flightDeckUrl: LOCATE_DOCS_BASE_URLS.a32nx.flightdeck, - imageUrl: `${PEDESTAL_IMAGE_BASE_URL}/atc_tcas.png`, - identifiers: ['xpdr', 'atc-tcas-panel', 'transponder', 'tcas', 'alt-rptg-switch'], + name: 'ATC/TCAS Panel', + title: 'FlyByWire A32NX | ATC TCAS Panel', + docsUrl: `${PEDESTAL_DOCS_BASE_URL}/atc-tcas`, + flightDeckUrl: LOCATE_DOCS_BASE_URLS.a32nx.flightdeck, + imageUrl: `${PEDESTAL_IMAGE_BASE_URL}/atc_tcas.png`, + identifiers: ['xpdr', 'atc-tcas-panel', 'transponder', 'tcas', 'alt-rptg-switch'], }; export const flaps: Panel = { - name: 'Flaps', - title: 'FlyByWire A32NX | Flaps', - docsUrl: `${PEDESTAL_DOCS_BASE_URL}/flaps`, - flightDeckUrl: LOCATE_DOCS_BASE_URLS.a32nx.flightdeck, - imageUrl: `${PEDESTAL_IMAGE_BASE_URL}/flaps.png`, - identifiers: ['flaps'], + name: 'Flaps', + title: 'FlyByWire A32NX | Flaps', + docsUrl: `${PEDESTAL_DOCS_BASE_URL}/flaps`, + flightDeckUrl: LOCATE_DOCS_BASE_URLS.a32nx.flightdeck, + imageUrl: `${PEDESTAL_IMAGE_BASE_URL}/flaps.png`, + identifiers: ['flaps'], }; export const printer: Panel = { - name: 'Printer', - title: 'FlyByWire A32NX | Printer', - docsUrl: `${PEDESTAL_DOCS_BASE_URL}/printer`, - flightDeckUrl: LOCATE_DOCS_BASE_URLS.a32nx.flightdeck, - imageUrl: `${PEDESTAL_IMAGE_BASE_URL}/printer.png`, - identifiers: ['printer'], + name: 'Printer', + title: 'FlyByWire A32NX | Printer', + docsUrl: `${PEDESTAL_DOCS_BASE_URL}/printer`, + flightDeckUrl: LOCATE_DOCS_BASE_URLS.a32nx.flightdeck, + imageUrl: `${PEDESTAL_IMAGE_BASE_URL}/printer.png`, + identifiers: ['printer'], }; diff --git a/src/commands/utils/locate/panels/a32nx/rear-cb-panel.ts b/src/commands/utils/locate/panels/a32nx/rear-cb-panel.ts index 5a801244..34e55773 100644 --- a/src/commands/utils/locate/panels/a32nx/rear-cb-panel.ts +++ b/src/commands/utils/locate/panels/a32nx/rear-cb-panel.ts @@ -2,10 +2,10 @@ import { LOCATE_DOCS_BASE_URLS, LOCATE_IMAGE_BASE_URLS } from '../../base-urls'; import { Panel } from '../panel'; export const rearBackCbPanel: Panel = { - name: 'Rear CB Panel', - title: 'FlyByWire A32NX | Rear Back Circuit Breaker Panel', - docsUrl: `${LOCATE_DOCS_BASE_URLS.a32nx.aftOverhead}/circuit/#rear-right-back-panel`, - flightDeckUrl: LOCATE_DOCS_BASE_URLS.a32nx.flightdeck, - imageUrl: `${LOCATE_IMAGE_BASE_URLS.a32nx.rearCb}/rear_right_back.jpg`, - identifiers: ['rear-back-circuit-breaker-panel', 'secondary-circuit-breaker-panel'], + name: 'Rear CB Panel', + title: 'FlyByWire A32NX | Rear Back Circuit Breaker Panel', + docsUrl: `${LOCATE_DOCS_BASE_URLS.a32nx.aftOverhead}/circuit/#rear-right-back-panel`, + flightDeckUrl: LOCATE_DOCS_BASE_URLS.a32nx.flightdeck, + imageUrl: `${LOCATE_IMAGE_BASE_URLS.a32nx.rearCb}/rear_right_back.jpg`, + identifiers: ['rear-back-circuit-breaker-panel', 'secondary-circuit-breaker-panel'], }; diff --git a/src/commands/utils/locate/panels/panel.ts b/src/commands/utils/locate/panels/panel.ts index 4fea53da..1a85801a 100644 --- a/src/commands/utils/locate/panels/panel.ts +++ b/src/commands/utils/locate/panels/panel.ts @@ -1,31 +1,31 @@ export interface Panel { - /** - * The name of the Panel. This should be usable in sentences. - */ - name: string; + /** + * The name of the Panel. This should be usable in sentences. + */ + name: string; - /** - * The title of the Panel. -> Used as the embed title. - */ - title: string; + /** + * The title of the Panel. -> Used as the embed title. + */ + title: string; - /** - * The URL to the relevant documentation. - */ - docsUrl: string; + /** + * The URL to the relevant documentation. + */ + docsUrl: string; - /** - * The URL to documentation of the flight deck this panel belongs to. - */ - flightDeckUrl: string; + /** + * The URL to documentation of the flight deck this panel belongs to. + */ + flightDeckUrl: string; - /** - * The URL to the image that shows the location of this panel. - */ - imageUrl: string; + /** + * The URL to the image that shows the location of this panel. + */ + imageUrl: string; - /** - * The search queries that lead to this panel. - */ - identifiers: string[]; + /** + * The search queries that lead to this panel. + */ + identifiers: string[]; } diff --git a/src/commands/utils/memberCount.ts b/src/commands/utils/memberCount.ts index 46423ea7..5bf4fa7b 100644 --- a/src/commands/utils/memberCount.ts +++ b/src/commands/utils/memberCount.ts @@ -2,16 +2,16 @@ import { ApplicationCommandType } from 'discord.js'; import { slashCommand, slashCommandStructure, makeEmbed } from '../../lib'; const data = slashCommandStructure({ - name: 'member-count', - description: 'Lists the current member count for the server.', - type: ApplicationCommandType.ChatInput, + name: 'member-count', + description: 'Lists the current member count for the server.', + type: ApplicationCommandType.ChatInput, }); export default slashCommand(data, async ({ interaction }) => { - const memberCountEmbed = makeEmbed({ - title: 'Member Count', - description: `There are currently **${interaction.guild?.memberCount}** members in the server.`, - }); + const memberCountEmbed = makeEmbed({ + title: 'Member Count', + description: `There are currently **${interaction.guild?.memberCount}** members in the server.`, + }); - return interaction.reply({ embeds: [memberCountEmbed] }); + return interaction.reply({ embeds: [memberCountEmbed] }); }); diff --git a/src/commands/utils/metar.ts b/src/commands/utils/metar.ts index 4a5ae8b3..c9f5e03f 100644 --- a/src/commands/utils/metar.ts +++ b/src/commands/utils/metar.ts @@ -3,87 +3,88 @@ import fetch from 'node-fetch'; import { constantsConfig, slashCommand, slashCommandStructure, makeEmbed, makeLines, Logger } from '../../lib'; const data = slashCommandStructure({ - name: 'metar', - description: 'Provides the METAR report of the requested airport', - type: ApplicationCommandType.ChatInput, - options: [ - { - name: 'icao', - description: 'Provide an airport ICAO code.', - type: ApplicationCommandOptionType.String, - max_length: 4, - min_length: 4, - required: true, - }, - ], + name: 'metar', + description: 'Provides the METAR report of the requested airport', + type: ApplicationCommandType.ChatInput, + options: [ + { + name: 'icao', + description: 'Provide an airport ICAO code.', + type: ApplicationCommandOptionType.String, + max_length: 4, + min_length: 4, + required: true, + }, + ], }); export default slashCommand(data, async ({ interaction }) => { - await interaction.deferReply(); + await interaction.deferReply(); - const icao = interaction.options.getString('icao')!; + const icao = interaction.options.getString('icao')!; - const metarToken = process.env.METAR_TOKEN; - - if (!metarToken) { - const noTokenEmbed = makeEmbed({ - title: 'Error | METAR', - description: 'Metar token not found.', - color: Colors.Red, - }); - return interaction.editReply({ embeds: [noTokenEmbed] }); - } + const metarToken = process.env.METAR_TOKEN; - try { - const metarReport: any = await fetch(`https://avwx.rest/api/metar/${icao}`, { - method: 'GET', - headers: { Authorization: metarToken }, - }).then((res) => res.json()); + if (!metarToken) { + const noTokenEmbed = makeEmbed({ + title: 'Error | METAR', + description: 'Metar token not found.', + color: Colors.Red, + }); + return interaction.editReply({ embeds: [noTokenEmbed] }); + } - if (metarReport.error) { - const invalidEmbed = makeEmbed({ - title: `Metar Error | ${icao.toUpperCase()}`, - description: metarReport.error, - color: Colors.Red, - }); - return interaction.editReply({ embeds: [invalidEmbed] }); - } - const metarEmbed = makeEmbed({ - title: `METAR Report | ${metarReport.station}`, - description: makeLines([ - '**Raw Report**', - metarReport.raw, - '', - '**Basic Report:**', - `**Time Observed:** ${metarReport.time.dt}`, - `**Station:** ${metarReport.station}`, - `**Wind:** ${metarReport.wind_direction.repr}${metarReport.wind_direction.repr === 'VRB' ? '' : constantsConfig.units.DEGREES} at ${metarReport.wind_speed.repr} ${metarReport.units.wind_speed}`, - `**Visibility:** ${metarReport.visibility.repr} ${Number.isNaN(+metarReport.visibility.repr) ? '' : metarReport.units.visibility}`, - `**Temperature:** ${metarReport.temperature.repr} ${constantsConfig.units.CELSIUS}`, - `**Dew Point:** ${metarReport.dewpoint.repr} ${constantsConfig.units.CELSIUS}`, - `**Altimeter:** ${metarReport.altimeter.value.toString()} ${metarReport.units.altimeter}`, - `**Flight Rules:** ${metarReport.flight_rules}`, - ]), - fields: [ - { - name: 'Unsure of how to read the raw report?', - value: 'Please refer to our guide [here.](https://docs.flybywiresim.com/pilots-corner/airliner-flying-guide/weather/)', - inline: false, - }, - ], - footer: { - text: 'This METAR report may not accurately reflect the weather in the simulator. However, it will always be similar to the current conditions present in the sim.', - }, - }); + try { + const metarReport: any = await fetch(`https://avwx.rest/api/metar/${icao}`, { + method: 'GET', + headers: { Authorization: metarToken }, + }).then((res) => res.json()); - return interaction.editReply({ embeds: [metarEmbed] }); - } catch (e) { - Logger.error('metar:', e); - const fetchErrorEmbed = makeEmbed({ - title: 'Metar Error | Fetch Error', - description: 'There was an error fetching the METAR report. Please try again later.', - color: Colors.Red, - }); - return interaction.editReply({ embeds: [fetchErrorEmbed] }); + if (metarReport.error) { + const invalidEmbed = makeEmbed({ + title: `Metar Error | ${icao.toUpperCase()}`, + description: metarReport.error, + color: Colors.Red, + }); + return interaction.editReply({ embeds: [invalidEmbed] }); } + const metarEmbed = makeEmbed({ + title: `METAR Report | ${metarReport.station}`, + description: makeLines([ + '**Raw Report**', + metarReport.raw, + '', + '**Basic Report:**', + `**Time Observed:** ${metarReport.time.dt}`, + `**Station:** ${metarReport.station}`, + `**Wind:** ${metarReport.wind_direction.repr}${metarReport.wind_direction.repr === 'VRB' ? '' : constantsConfig.units.DEGREES} at ${metarReport.wind_speed.repr} ${metarReport.units.wind_speed}`, + `**Visibility:** ${metarReport.visibility.repr} ${Number.isNaN(+metarReport.visibility.repr) ? '' : metarReport.units.visibility}`, + `**Temperature:** ${metarReport.temperature.repr} ${constantsConfig.units.CELSIUS}`, + `**Dew Point:** ${metarReport.dewpoint.repr} ${constantsConfig.units.CELSIUS}`, + `**Altimeter:** ${metarReport.altimeter.value.toString()} ${metarReport.units.altimeter}`, + `**Flight Rules:** ${metarReport.flight_rules}`, + ]), + fields: [ + { + name: 'Unsure of how to read the raw report?', + value: + 'Please refer to our guide [here.](https://docs.flybywiresim.com/pilots-corner/airliner-flying-guide/weather/)', + inline: false, + }, + ], + footer: { + text: 'This METAR report may not accurately reflect the weather in the simulator. However, it will always be similar to the current conditions present in the sim.', + }, + }); + + return interaction.editReply({ embeds: [metarEmbed] }); + } catch (e) { + Logger.error('metar:', e); + const fetchErrorEmbed = makeEmbed({ + title: 'Metar Error | Fetch Error', + description: 'There was an error fetching the METAR report. Please try again later.', + color: Colors.Red, + }); + return interaction.editReply({ embeds: [fetchErrorEmbed] }); + } }); diff --git a/src/commands/utils/ping.ts b/src/commands/utils/ping.ts index 93c8f6a5..e5af6fda 100644 --- a/src/commands/utils/ping.ts +++ b/src/commands/utils/ping.ts @@ -2,24 +2,24 @@ import { ApplicationCommandOptionType, ApplicationCommandType } from 'discord.js import { slashCommand, slashCommandStructure, makeEmbed } from '../../lib'; const data = slashCommandStructure({ - name: 'ping', - description: 'Ping the bot for a response.', - type: ApplicationCommandType.ChatInput, - options: [ - { - name: 'message', - description: 'Provide some text to send back.', - type: ApplicationCommandOptionType.String, - max_length: 100, - required: false, - }, - ], + name: 'ping', + description: 'Ping the bot for a response.', + type: ApplicationCommandType.ChatInput, + options: [ + { + name: 'message', + description: 'Provide some text to send back.', + type: ApplicationCommandOptionType.String, + max_length: 100, + required: false, + }, + ], }); export default slashCommand(data, async ({ interaction }) => { - const msg = interaction.options.getString('message') ?? 'Pong 🏓'; + const msg = interaction.options.getString('message') ?? 'Pong 🏓'; - const pongEmbed = makeEmbed({ description: msg }); + const pongEmbed = makeEmbed({ description: msg }); - return interaction.reply({ embeds: [pongEmbed] }); + return interaction.reply({ embeds: [pongEmbed] }); }); diff --git a/src/commands/utils/reportedIssues.ts b/src/commands/utils/reportedIssues.ts index 0390431f..4ac03e04 100644 --- a/src/commands/utils/reportedIssues.ts +++ b/src/commands/utils/reportedIssues.ts @@ -3,125 +3,125 @@ import { JSDOM } from 'jsdom'; import { Logger, makeEmbed, slashCommand, slashCommandStructure } from '../../lib'; const data = slashCommandStructure({ - name: 'reported-issues', - description: 'Provides a link to the reported issues page within docs.', - type: ApplicationCommandType.ChatInput, - options: [ - { - name: 'query', - description: 'Provide a query to search for.', - type: ApplicationCommandOptionType.String, - max_length: 100, - required: true, - }, - ], + name: 'reported-issues', + description: 'Provides a link to the reported issues page within docs.', + type: ApplicationCommandType.ChatInput, + options: [ + { + name: 'query', + description: 'Provide a query to search for.', + type: ApplicationCommandOptionType.String, + max_length: 100, + required: true, + }, + ], }); const FBW_DOCS_REPORTED_ISSUES_URL = 'https://docs.flybywiresim.com/fbw-a32nx/support/reported-issues/'; const FBW_DOCS_AUTOPILOT_ISSUES_URL = - 'https://docs.flybywiresim.com/fbw-a32nx/feature-guides/autopilot-fbw/#typical-issues-and-how-to-solve-them'; + 'https://docs.flybywiresim.com/fbw-a32nx/feature-guides/autopilot-fbw/#typical-issues-and-how-to-solve-them'; const FBW_DOCS_SIMBRIDGE_ISSUES_URL = 'https://docs.flybywiresim.com/simbridge/troubleshooting/'; const genericReportedIssuesEmbed = makeEmbed({ - title: 'FlyByWire A32NX | Reported Issues', - description: `I couldn't find a match foy your query. Please see [this link](${FBW_DOCS_REPORTED_ISSUES_URL}) for a current list of reported issues.`, + title: 'FlyByWire A32NX | Reported Issues', + description: `I couldn't find a match foy your query. Please see [this link](${FBW_DOCS_REPORTED_ISSUES_URL}) for a current list of reported issues.`, }); const issueInSubsectionEmbed = (fields: EmbedField[]) => - makeEmbed({ - title: 'FlyByWire A32NX | Reported Issues', - description: - "Your issue is in our reported issues list. Please try the possible solutions in the following link(s) and report back if they didn't help. Include all the steps you tried.", - fields, - }); + makeEmbed({ + title: 'FlyByWire A32NX | Reported Issues', + description: + "Your issue is in our reported issues list. Please try the possible solutions in the following link(s) and report back if they didn't help. Include all the steps you tried.", + fields, + }); const subsectionLinkEmbedField = (id: string, title: string): EmbedField[] => [ - { - inline: false, - name: `${title}`, - value: `[Link to reported issues section](${FBW_DOCS_REPORTED_ISSUES_URL}#${id})`, - }, + { + inline: false, + name: `${title}`, + value: `[Link to reported issues section](${FBW_DOCS_REPORTED_ISSUES_URL}#${id})`, + }, ]; const autopilotEmbed = makeEmbed({ - title: 'FlyByWire A32NX | Reported Issues', - description: `Please see [this link](${FBW_DOCS_AUTOPILOT_ISSUES_URL}) for typical issues with the custom autopilot and how to solve them.`, + title: 'FlyByWire A32NX | Reported Issues', + description: `Please see [this link](${FBW_DOCS_AUTOPILOT_ISSUES_URL}) for typical issues with the custom autopilot and how to solve them.`, }); const simbridgeEmbed = makeEmbed({ - title: 'FlyByWire A32NX | Reported Issues', - description: `Please see [this link](${FBW_DOCS_SIMBRIDGE_ISSUES_URL}) for typical issues with simbridge and how to solve them.`, + title: 'FlyByWire A32NX | Reported Issues', + description: `Please see [this link](${FBW_DOCS_SIMBRIDGE_ISSUES_URL}) for typical issues with simbridge and how to solve them.`, }); const generalTroubleshootingEmbed = makeEmbed({ - title: 'FlyByWire A32NX | Reported Issues', - description: - "Please try the general troubleshooting steps from our reported issues page and report back if they didn't help. Include all the steps you tried.", - fields: [ - { - inline: false, - name: 'General Troubleshooting Steps', - value: `[Link to reported issues section](${FBW_DOCS_REPORTED_ISSUES_URL}#general-troubleshooting-steps)`, - }, - ], + title: 'FlyByWire A32NX | Reported Issues', + description: + "Please try the general troubleshooting steps from our reported issues page and report back if they didn't help. Include all the steps you tried.", + fields: [ + { + inline: false, + name: 'General Troubleshooting Steps', + value: `[Link to reported issues section](${FBW_DOCS_REPORTED_ISSUES_URL}#general-troubleshooting-steps)`, + }, + ], }); const tooManyResultsEmbed = makeEmbed({ - title: 'FlyByWire A32NX | Error', - description: 'The search term returned too many results', - color: Colors.Red, + title: 'FlyByWire A32NX | Error', + description: 'The search term returned too many results', + color: Colors.Red, }); export default slashCommand(data, async ({ interaction }) => { - const query = interaction.options.getString('query')!; - - const lowercaseQuery = query.toLowerCase(); - - const words = lowercaseQuery.split(/\s+/); - - if (words.length === 1) { - if (lowercaseQuery === 'autopilot') { - return interaction.reply({ embeds: [autopilotEmbed] }); - } - if (lowercaseQuery === 'simbridge') { - return interaction.reply({ embeds: [simbridgeEmbed] }); - } - if (lowercaseQuery === 'troubleshooting') { - return interaction.reply({ embeds: [generalTroubleshootingEmbed] }); - } + const query = interaction.options.getString('query')!; + + const lowercaseQuery = query.toLowerCase(); + + const words = lowercaseQuery.split(/\s+/); + + if (words.length === 1) { + if (lowercaseQuery === 'autopilot') { + return interaction.reply({ embeds: [autopilotEmbed] }); } + if (lowercaseQuery === 'simbridge') { + return interaction.reply({ embeds: [simbridgeEmbed] }); + } + if (lowercaseQuery === 'troubleshooting') { + return interaction.reply({ embeds: [generalTroubleshootingEmbed] }); + } + } + + try { + const reportedIssues: any = []; + const dom = await JSDOM.fromURL(`${FBW_DOCS_REPORTED_ISSUES_URL}`); + const { document } = dom.window; + const h3Elements = document.querySelectorAll('h3'); + h3Elements.forEach((element) => { + const { id } = element; + if (words.every((searchWord) => id.includes(searchWord))) { + reportedIssues.push({ id, title: element.textContent }); + } + }); - try { - const reportedIssues: any = []; - const dom = await JSDOM.fromURL(`${FBW_DOCS_REPORTED_ISSUES_URL}`); - const { document } = dom.window; - const h3Elements = document.querySelectorAll('h3'); - h3Elements.forEach((element) => { - const { id } = element; - if (words.every((searchWord) => id.includes(searchWord))) { - reportedIssues.push({ id, title: element.textContent }); - } - }); - - if (reportedIssues.length === 0 || reportedIssues.length > 4) { - if (reportedIssues.length > 4) { - return interaction.reply({ embeds: [tooManyResultsEmbed] }); - } - return interaction.reply({ embeds: [genericReportedIssuesEmbed] }); - } - - const fields = reportedIssues - .map((sectionElement: any) => subsectionLinkEmbedField(sectionElement.id, sectionElement.title)) - .flat(); - return interaction.reply({ embeds: [issueInSubsectionEmbed(fields)] }); - } catch (error: any) { - Logger.error(error); - Logger.error(error.stack); - const errorEmbed = makeEmbed({ - title: 'Error | Reported Issues', - description: error.message, - color: Colors.Red, - }); - return interaction.reply({ embeds: [errorEmbed] }); + if (reportedIssues.length === 0 || reportedIssues.length > 4) { + if (reportedIssues.length > 4) { + return interaction.reply({ embeds: [tooManyResultsEmbed] }); + } + return interaction.reply({ embeds: [genericReportedIssuesEmbed] }); } + + const fields = reportedIssues + .map((sectionElement: any) => subsectionLinkEmbedField(sectionElement.id, sectionElement.title)) + .flat(); + return interaction.reply({ embeds: [issueInSubsectionEmbed(fields)] }); + } catch (error: any) { + Logger.error(error); + Logger.error(error.stack); + const errorEmbed = makeEmbed({ + title: 'Error | Reported Issues', + description: error.message, + color: Colors.Red, + }); + return interaction.reply({ embeds: [errorEmbed] }); + } }); diff --git a/src/commands/utils/roleInfo.ts b/src/commands/utils/roleInfo.ts index 86c87e2a..06eb201e 100644 --- a/src/commands/utils/roleInfo.ts +++ b/src/commands/utils/roleInfo.ts @@ -2,31 +2,31 @@ import { ApplicationCommandOptionType, ApplicationCommandType } from 'discord.js import { slashCommand, slashCommandStructure, makeEmbed } from '../../lib'; const data = slashCommandStructure({ - name: 'role-info', - description: "Lists the given role's amount of members.", - type: ApplicationCommandType.ChatInput, - options: [ - { - name: 'role', - description: 'Provide the role to get info about.', - type: ApplicationCommandOptionType.Role, - required: true, - }, - ], + name: 'role-info', + description: "Lists the given role's amount of members.", + type: ApplicationCommandType.ChatInput, + options: [ + { + name: 'role', + description: 'Provide the role to get info about.', + type: ApplicationCommandOptionType.Role, + required: true, + }, + ], }); export default slashCommand(data, async ({ interaction }) => { - const role = interaction.options.getRole('role'); + const role = interaction.options.getRole('role'); - if (!role) return interaction.reply({ content: 'Invalid role!', ephemeral: true }); + if (!role) return interaction.reply({ content: 'Invalid role!', ephemeral: true }); - const roleMembers = role.members.map((member) => member.user.tag); - const roleMemberCount = roleMembers.length; + const roleMembers = role.members.map((member) => member.user.tag); + const roleMemberCount = roleMembers.length; - const roleInfoEmbed = makeEmbed({ - title: `Role Info | ${role.name}`, - description: `Members: ${roleMemberCount}`, - }); + const roleInfoEmbed = makeEmbed({ + title: `Role Info | ${role.name}`, + description: `Members: ${roleMemberCount}`, + }); - return interaction.reply({ embeds: [roleInfoEmbed] }); + return interaction.reply({ embeds: [roleInfoEmbed] }); }); diff --git a/src/commands/utils/searchFaq.ts b/src/commands/utils/searchFaq.ts index 29ebe50b..dd20b719 100644 --- a/src/commands/utils/searchFaq.ts +++ b/src/commands/utils/searchFaq.ts @@ -2,63 +2,63 @@ import { ApplicationCommandOptionType, ApplicationCommandType } from 'discord.js import { constantsConfig, slashCommand, slashCommandStructure, makeEmbed, FAQ, Logger } from '../../lib'; const data = slashCommandStructure({ - name: 'faq-search', - description: 'Searches the FAQs.', - type: ApplicationCommandType.ChatInput, - options: [ - { - name: 'search_term', - description: 'The faq title to search for.', - type: ApplicationCommandOptionType.String, - max_length: 100, - required: true, - }, - ], + name: 'faq-search', + description: 'Searches the FAQs.', + type: ApplicationCommandType.ChatInput, + options: [ + { + name: 'search_term', + description: 'The faq title to search for.', + type: ApplicationCommandOptionType.String, + max_length: 100, + required: true, + }, + ], }); const noFaqsFoundEmbed = (searchTerm: string) => - makeEmbed({ - title: `No FAQs found - ${searchTerm}`, - description: 'No FAQs found matching your search term. Please try again or see the links below.', - fields: [ - { - name: '**FAQ Channel**', - value: `<#${constantsConfig.channels.FAQ}>`, - }, - { - name: '**Docs FAQ**', - value: 'https://docs.flybywiresim.com/fbw-a32nx/faq/', - }, - ], - }); + makeEmbed({ + title: `No FAQs found - ${searchTerm}`, + description: 'No FAQs found matching your search term. Please try again or see the links below.', + fields: [ + { + name: '**FAQ Channel**', + value: `<#${constantsConfig.channels.FAQ}>`, + }, + { + name: '**Docs FAQ**', + value: 'https://docs.flybywiresim.com/fbw-a32nx/faq/', + }, + ], + }); export default slashCommand(data, async ({ interaction }) => { - const searchTerm = interaction.options.getString('search_term') ?? ''; + const searchTerm = interaction.options.getString('search_term') ?? ''; - await interaction.deferReply(); + await interaction.deferReply(); - try { - // Fetch FAQs from the database based on the search term - const faq = await FAQ.findOne({ faqTitle: { $regex: new RegExp(searchTerm, 'i') } }); + try { + // Fetch FAQs from the database based on the search term + const faq = await FAQ.findOne({ faqTitle: { $regex: new RegExp(searchTerm, 'i') } }); - if (!faq) { - await interaction.followUp({ embeds: [noFaqsFoundEmbed(searchTerm)] }); - } else { - const faqEmbed = makeEmbed({ - title: 'Frequently Asked Question', - description: `Search results for **${searchTerm}**`, - fields: [ - { - name: `**${faq.faqTitle}**`, - value: `${faq.faqAnswer}`, - }, - ], - }); + if (!faq) { + await interaction.followUp({ embeds: [noFaqsFoundEmbed(searchTerm)] }); + } else { + const faqEmbed = makeEmbed({ + title: 'Frequently Asked Question', + description: `Search results for **${searchTerm}**`, + fields: [ + { + name: `**${faq.faqTitle}**`, + value: `${faq.faqAnswer}`, + }, + ], + }); - await interaction.followUp({ embeds: [faqEmbed] }); - } - } catch (error) { - Logger.error('Error fetching FAQ:', error); - await interaction.followUp({ content: 'An error occurred while fetching the FAQ.', ephemeral: true }); + await interaction.followUp({ embeds: [faqEmbed] }); } + } catch (error) { + Logger.error('Error fetching FAQ:', error); + await interaction.followUp({ content: 'An error occurred while fetching the FAQ.', ephemeral: true }); + } }); diff --git a/src/commands/utils/simbriefData.ts b/src/commands/utils/simbriefData.ts index 50e456ce..af0a074a 100644 --- a/src/commands/utils/simbriefData.ts +++ b/src/commands/utils/simbriefData.ts @@ -3,97 +3,97 @@ import moment from 'moment'; import { slashCommand, makeEmbed, makeLines, slashCommandStructure } from '../../lib'; const data = slashCommandStructure({ - name: 'simbrief-data', - description: 'Gets the simbrief data for the given flight number/pilotID.', - type: ApplicationCommandType.ChatInput, - options: [ + name: 'simbrief-data', + description: 'Gets the simbrief data for the given flight number/pilotID.', + type: ApplicationCommandType.ChatInput, + options: [ + { + name: 'retrieve', + description: 'Shows data for your last filed flight plan.', + type: ApplicationCommandOptionType.Subcommand, + options: [ { - name: 'retrieve', - description: 'Shows data for your last filed flight plan.', - type: ApplicationCommandOptionType.Subcommand, - options: [ - { - name: 'pilot_id', - description: 'Please provide your pilot ID.', - type: ApplicationCommandOptionType.String, - max_length: 100, - required: true, - }, - ], + name: 'pilot_id', + description: 'Please provide your pilot ID.', + type: ApplicationCommandOptionType.String, + max_length: 100, + required: true, }, - { - name: 'support-request', - description: 'Shows information on how to provide SimBrief data.', - type: ApplicationCommandOptionType.Subcommand, - }, - ], + ], + }, + { + name: 'support-request', + description: 'Shows information on how to provide SimBrief data.', + type: ApplicationCommandOptionType.Subcommand, + }, + ], }); const FBW_AIRFRAME_ID = '337364_1631550522735'; const simbriefdatarequestEmbed = makeEmbed({ - title: 'FlyByWire Support | SimBrief Data Request', - description: makeLines([ - 'To evaluate your problem we kindly ask you to enter the following bot command into a new message.', - '```/simbrief_data retrieve```', - 'Enter your `pilotId` with your simbrief pilotId or userName (as set in the EFB settings). The Bot will read your last generated flight plan and display some details about it including the route.', - '', - '**Privacy notice**: If you share your pilotId or username it is possible to read your pilot name from the API the bot uses. This pilot name is by default your real name, but you can change it in the flight edit screen or your user profile in SimBrief. No data is stored by FlyByWire when using the command.', - ]), + title: 'FlyByWire Support | SimBrief Data Request', + description: makeLines([ + 'To evaluate your problem we kindly ask you to enter the following bot command into a new message.', + '```/simbrief_data retrieve```', + 'Enter your `pilotId` with your simbrief pilotId or userName (as set in the EFB settings). The Bot will read your last generated flight plan and display some details about it including the route.', + '', + '**Privacy notice**: If you share your pilotId or username it is possible to read your pilot name from the API the bot uses. This pilot name is by default your real name, but you can change it in the flight edit screen or your user profile in SimBrief. No data is stored by FlyByWire when using the command.', + ]), }); const errorEmbed = (errorMessage: any) => - makeEmbed({ - title: 'SimBrief Error', - description: makeLines(['SimBrief data could not be read.', errorMessage]), - color: Colors.Red, - }); + makeEmbed({ + title: 'SimBrief Error', + description: makeLines(['SimBrief data could not be read.', errorMessage]), + color: Colors.Red, + }); const simbriefIdMismatchEmbed = (enteredId: any, flightplanId: any) => - makeEmbed({ - title: 'SimBrief Data', - description: makeLines([ - `Entered pilotId ${enteredId} and returned pilotId ${flightplanId} don't match. The pilotId might be used as username by someone else.`, - ]), - }); + makeEmbed({ + title: 'SimBrief Data', + description: makeLines([ + `Entered pilotId ${enteredId} and returned pilotId ${flightplanId} don't match. The pilotId might be used as username by someone else.`, + ]), + }); const simbriefEmbed = (flightplan: any) => - makeEmbed({ - title: 'SimBrief Data', - description: makeLines([ - `**Generated at**: ${moment(flightplan.params.time_generated * 1000).format('DD.MM.YYYY, HH:mm:ss')}`, - `**AirFrame**: ${flightplan.aircraft.name} ${flightplan.aircraft.internal_id} ${flightplan.aircraft.internal_id === FBW_AIRFRAME_ID ? '(provided by FBW)' : ''}`, - `**AIRAC Cycle**: ${flightplan.params.airac}`, - `**Origin**: ${flightplan.origin.icao_code}`, - `**Destination**: ${flightplan.destination.icao_code}`, - `**Route**: ${flightplan.general.route}`, - ]), - }); + makeEmbed({ + title: 'SimBrief Data', + description: makeLines([ + `**Generated at**: ${moment(flightplan.params.time_generated * 1000).format('DD.MM.YYYY, HH:mm:ss')}`, + `**AirFrame**: ${flightplan.aircraft.name} ${flightplan.aircraft.internal_id} ${flightplan.aircraft.internal_id === FBW_AIRFRAME_ID ? '(provided by FBW)' : ''}`, + `**AIRAC Cycle**: ${flightplan.params.airac}`, + `**Origin**: ${flightplan.origin.icao_code}`, + `**Destination**: ${flightplan.destination.icao_code}`, + `**Route**: ${flightplan.general.route}`, + ]), + }); export default slashCommand(data, async ({ interaction }) => { - if (interaction.options.getSubcommand() === 'support-request') { - return interaction.reply({ embeds: [simbriefdatarequestEmbed] }); - } + if (interaction.options.getSubcommand() === 'support-request') { + return interaction.reply({ embeds: [simbriefdatarequestEmbed] }); + } - if (interaction.options.getSubcommand() === 'retrieve') { - const simbriefId = interaction.options.getString('pilot_id'); - if (!simbriefId) return interaction.reply({ content: 'Invalid pilot ID!', ephemeral: true }); + if (interaction.options.getSubcommand() === 'retrieve') { + const simbriefId = interaction.options.getString('pilot_id'); + if (!simbriefId) return interaction.reply({ content: 'Invalid pilot ID!', ephemeral: true }); - const flightplan = await fetch( - `https://www.simbrief.com/api/xml.fetcher.php?json=1&userid=${simbriefId}&username=${simbriefId}`, - ).then((res) => res.json()); + const flightplan = await fetch( + `https://www.simbrief.com/api/xml.fetcher.php?json=1&userid=${simbriefId}&username=${simbriefId}`, + ).then((res) => res.json()); - if (flightplan.fetch.status !== 'Success') { - interaction.reply({ embeds: [errorEmbed(flightplan.fetch.status)], ephemeral: true }); - return Promise.resolve(); - } - - if (!simbriefId.match(/\D/) && simbriefId !== flightplan.params.user_id) { - interaction.reply({ embeds: [simbriefIdMismatchEmbed(simbriefId, flightplan.params.user_id)] }); - } - interaction.reply({ embeds: [simbriefEmbed(flightplan)] }); + if (flightplan.fetch.status !== 'Success') { + interaction.reply({ embeds: [errorEmbed(flightplan.fetch.status)], ephemeral: true }); + return Promise.resolve(); + } - return Promise.resolve(); + if (!simbriefId.match(/\D/) && simbriefId !== flightplan.params.user_id) { + interaction.reply({ embeds: [simbriefIdMismatchEmbed(simbriefId, flightplan.params.user_id)] }); } + interaction.reply({ embeds: [simbriefEmbed(flightplan)] }); + return Promise.resolve(); + } + return Promise.resolve(); }); diff --git a/src/commands/utils/station.ts b/src/commands/utils/station.ts index 70fa684d..44fb247d 100644 --- a/src/commands/utils/station.ts +++ b/src/commands/utils/station.ts @@ -3,96 +3,96 @@ import fetch from 'node-fetch'; import { slashCommand, slashCommandStructure, makeEmbed, Logger, makeLines } from '../../lib'; const data = slashCommandStructure({ - name: 'station', - description: 'Provides station information.', - type: ApplicationCommandType.ChatInput, - options: [ - { - name: 'icao', - description: 'Provide an airport ICAO code.', - type: ApplicationCommandOptionType.String, - max_length: 4, - min_length: 4, - required: true, - }, - ], + name: 'station', + description: 'Provides station information.', + type: ApplicationCommandType.ChatInput, + options: [ + { + name: 'icao', + description: 'Provide an airport ICAO code.', + type: ApplicationCommandOptionType.String, + max_length: 4, + min_length: 4, + required: true, + }, + ], }); const noQueryEmbed = makeEmbed({ - title: 'Station Error | Missing Query', - description: 'You must provide an airport ICAO code.', - color: Colors.Red, + title: 'Station Error | Missing Query', + description: 'You must provide an airport ICAO code.', + color: Colors.Red, }); export default slashCommand(data, async ({ interaction }) => { - await interaction.deferReply(); + await interaction.deferReply(); - const stationToken = process.env.STATION_TOKEN; + const stationToken = process.env.STATION_TOKEN; - if (!stationToken) { - const noTokenEmbed = makeEmbed({ - title: 'Error | Station', - description: 'Station token not found.', - color: Colors.Red, - }); - return interaction.editReply({ embeds: [noTokenEmbed] }); - } + if (!stationToken) { + const noTokenEmbed = makeEmbed({ + title: 'Error | Station', + description: 'Station token not found.', + color: Colors.Red, + }); + return interaction.editReply({ embeds: [noTokenEmbed] }); + } - const icao = interaction.options.getString('icao'); + const icao = interaction.options.getString('icao'); - if (!icao) return interaction.editReply({ embeds: [noQueryEmbed] }); + if (!icao) return interaction.editReply({ embeds: [noQueryEmbed] }); - try { - const stationReport: any = await fetch(`https://avwx.rest/api/station/${icao}`, { - method: 'GET', - headers: { Authorization: stationToken }, - }).then((res) => res.json()); + try { + const stationReport: any = await fetch(`https://avwx.rest/api/station/${icao}`, { + method: 'GET', + headers: { Authorization: stationToken }, + }).then((res) => res.json()); - if (stationReport.error) { - const invalidEmbed = makeEmbed({ - title: `Station Error | ${icao.toUpperCase()}`, - description: stationReport.error, - color: Colors.Red, - }); - return interaction.editReply({ embeds: [invalidEmbed] }); - } + if (stationReport.error) { + const invalidEmbed = makeEmbed({ + title: `Station Error | ${icao.toUpperCase()}`, + description: stationReport.error, + color: Colors.Red, + }); + return interaction.editReply({ embeds: [invalidEmbed] }); + } - const runwayIdents = stationReport.runways.map( - (runways: any) => - `**${runways.ident1}/${runways.ident2}:** ` + - `${runways.length_ft} ft x ${runways.width_ft} ft / ` + - `${Math.round(runways.length_ft * 0.3048)} m x ${Math.round(runways.width_ft * 0.3048)} m`, - ); + const runwayIdents = stationReport.runways.map( + (runways: any) => + `**${runways.ident1}/${runways.ident2}:** ` + + `${runways.length_ft} ft x ${runways.width_ft} ft / ` + + `${Math.round(runways.length_ft * 0.3048)} m x ${Math.round(runways.width_ft * 0.3048)} m`, + ); - const stationEmbed = makeEmbed({ - title: `Station Info | ${stationReport.icao}`, - description: makeLines([ - '**Station Information:**', - `**Name:** ${stationReport.name}`, - `**Country:** ${stationReport.country}`, - `**City:** ${stationReport.city}`, - `**Latitude:** ${stationReport.latitude}°`, - `**Longitude:** ${stationReport.longitude}°`, - `**Elevation:** ${stationReport.elevation_m} m/${stationReport.elevation_ft} ft`, - '', - '**Runways (Ident1/Ident2: Length x Width):**', - `${runwayIdents.toString().replace(/,/g, '\n')}`, - '', - `**Type:** ${stationReport.type.replace(/_/g, ' ')}`, - `**Website:** ${stationReport.website}`, - `**Wiki:** ${stationReport.wiki}`, - ]), - footer: { text: 'Due to limitations of the API, not all links may be up to date at all times.' }, - }); + const stationEmbed = makeEmbed({ + title: `Station Info | ${stationReport.icao}`, + description: makeLines([ + '**Station Information:**', + `**Name:** ${stationReport.name}`, + `**Country:** ${stationReport.country}`, + `**City:** ${stationReport.city}`, + `**Latitude:** ${stationReport.latitude}°`, + `**Longitude:** ${stationReport.longitude}°`, + `**Elevation:** ${stationReport.elevation_m} m/${stationReport.elevation_ft} ft`, + '', + '**Runways (Ident1/Ident2: Length x Width):**', + `${runwayIdents.toString().replace(/,/g, '\n')}`, + '', + `**Type:** ${stationReport.type.replace(/_/g, ' ')}`, + `**Website:** ${stationReport.website}`, + `**Wiki:** ${stationReport.wiki}`, + ]), + footer: { text: 'Due to limitations of the API, not all links may be up to date at all times.' }, + }); - return interaction.editReply({ embeds: [stationEmbed] }); - } catch (error) { - Logger.error('station:', error); - const fetchErrorEmbed = makeEmbed({ - title: 'Station Error | Fetch Error', - description: 'There was an error fetching the station report. Please try again later.', - color: Colors.Red, - }); - return interaction.editReply({ embeds: [fetchErrorEmbed] }); - } + return interaction.editReply({ embeds: [stationEmbed] }); + } catch (error) { + Logger.error('station:', error); + const fetchErrorEmbed = makeEmbed({ + title: 'Station Error | Fetch Error', + description: 'There was an error fetching the station report. Please try again later.', + color: Colors.Red, + }); + return interaction.editReply({ embeds: [fetchErrorEmbed] }); + } }); diff --git a/src/commands/utils/taf.ts b/src/commands/utils/taf.ts index 78792ad3..799cc3a1 100644 --- a/src/commands/utils/taf.ts +++ b/src/commands/utils/taf.ts @@ -3,104 +3,105 @@ import fetch from 'node-fetch'; import { constantsConfig, slashCommand, slashCommandStructure, makeEmbed, makeLines, Logger } from '../../lib'; const data = slashCommandStructure({ - name: 'taf', - description: 'Provides the TAF report of the requested airport.', - type: ApplicationCommandType.ChatInput, - options: [ - { - name: 'icao', - description: 'Provide an airport ICAO code.', - type: ApplicationCommandOptionType.String, - max_length: 4, - min_length: 4, - required: true, - }, - ], + name: 'taf', + description: 'Provides the TAF report of the requested airport.', + type: ApplicationCommandType.ChatInput, + options: [ + { + name: 'icao', + description: 'Provide an airport ICAO code.', + type: ApplicationCommandOptionType.String, + max_length: 4, + min_length: 4, + required: true, + }, + ], }); const noQueryEmbed = makeEmbed({ - title: 'TAF Error | Missing Query', - description: 'You must provide an airport ICAO code.', - color: Colors.Red, + title: 'TAF Error | Missing Query', + description: 'You must provide an airport ICAO code.', + color: Colors.Red, }); export default slashCommand(data, async ({ interaction }) => { - await interaction.deferReply(); + await interaction.deferReply(); - const tafToken = process.env.TAF_TOKEN; + const tafToken = process.env.TAF_TOKEN; - if (!tafToken) { - const noTokenEmbed = makeEmbed({ - title: 'Error | Station', - description: 'Station token not found.', - color: Colors.Red, - }); - return interaction.editReply({ embeds: [noTokenEmbed] }); - } + if (!tafToken) { + const noTokenEmbed = makeEmbed({ + title: 'Error | Station', + description: 'Station token not found.', + color: Colors.Red, + }); + return interaction.editReply({ embeds: [noTokenEmbed] }); + } - const icao = interaction.options.getString('icao'); + const icao = interaction.options.getString('icao'); - if (!icao) { - return interaction.editReply({ embeds: [noQueryEmbed] }); - } + if (!icao) { + return interaction.editReply({ embeds: [noQueryEmbed] }); + } - try { - const tafReport: any = await fetch(`https://avwx.rest/api/taf/${icao}`, { - method: 'GET', - headers: { Authorization: tafToken }, - }).then((res) => res.json()); + try { + const tafReport: any = await fetch(`https://avwx.rest/api/taf/${icao}`, { + method: 'GET', + headers: { Authorization: tafToken }, + }).then((res) => res.json()); - if (tafReport.error) { - const invalidEmbed = makeEmbed({ - title: `TAF Error | ${icao.toUpperCase()}`, - description: tafReport.error, - color: Colors.Red, - }); - return interaction.editReply({ embeds: [invalidEmbed] }); - } - const getClouds = (clouds: any) => { - const retClouds = []; - for (const cloud of clouds) { - retClouds.push(cloud.repr); - } - return retClouds.join(', '); - }; - const tafEmbed = makeEmbed({ - title: `TAF Report | ${tafReport.station}`, - description: makeLines([ - '**Raw Report**', - tafReport.raw, + if (tafReport.error) { + const invalidEmbed = makeEmbed({ + title: `TAF Error | ${icao.toUpperCase()}`, + description: tafReport.error, + color: Colors.Red, + }); + return interaction.editReply({ embeds: [invalidEmbed] }); + } + const getClouds = (clouds: any) => { + const retClouds = []; + for (const cloud of clouds) { + retClouds.push(cloud.repr); + } + return retClouds.join(', '); + }; + const tafEmbed = makeEmbed({ + title: `TAF Report | ${tafReport.station}`, + description: makeLines([ + '**Raw Report**', + tafReport.raw, - '', - '**Basic Report:**', - `**Time Forecasted:** ${tafReport.time.dt}`, - `**Forecast Start Time:** ${tafReport.start_time.dt}`, - `**Forecast End Time:** ${tafReport.end_time.dt}`, - `**Visibility:** ${tafReport.forecast[0].visibility.repr} ${Number.isNaN(+tafReport.forecast[0].visibility.repr) ? '' : tafReport.units.visibility}`, - `**Wind:** ${tafReport.forecast[0].wind_direction.repr}${tafReport.forecast[0].wind_direction.repr === 'VRB' ? '' : constantsConfig.units.DEGREES} at ${tafReport.forecast[0].wind_speed.repr} ${tafReport.units.wind_speed}`, - `**Clouds:** ${getClouds(tafReport.forecast[0].clouds)}`, - `**Flight Rules:** ${tafReport.forecast[0].flight_rules}`, - ]), - fields: [ - { - name: 'Unsure of how to read the raw report?', - value: 'Please refer to our guide [here.](https://docs.flybywiresim.com/pilots-corner/airliner-flying-guide/weather/#taf-example-decoded)', - inline: false, - }, - ], - footer: { - text: 'This TAF report is only a forecast, and may not accurately reflect weather in the simulator.', - }, - }); + '', + '**Basic Report:**', + `**Time Forecasted:** ${tafReport.time.dt}`, + `**Forecast Start Time:** ${tafReport.start_time.dt}`, + `**Forecast End Time:** ${tafReport.end_time.dt}`, + `**Visibility:** ${tafReport.forecast[0].visibility.repr} ${Number.isNaN(+tafReport.forecast[0].visibility.repr) ? '' : tafReport.units.visibility}`, + `**Wind:** ${tafReport.forecast[0].wind_direction.repr}${tafReport.forecast[0].wind_direction.repr === 'VRB' ? '' : constantsConfig.units.DEGREES} at ${tafReport.forecast[0].wind_speed.repr} ${tafReport.units.wind_speed}`, + `**Clouds:** ${getClouds(tafReport.forecast[0].clouds)}`, + `**Flight Rules:** ${tafReport.forecast[0].flight_rules}`, + ]), + fields: [ + { + name: 'Unsure of how to read the raw report?', + value: + 'Please refer to our guide [here.](https://docs.flybywiresim.com/pilots-corner/airliner-flying-guide/weather/#taf-example-decoded)', + inline: false, + }, + ], + footer: { + text: 'This TAF report is only a forecast, and may not accurately reflect weather in the simulator.', + }, + }); - return interaction.editReply({ embeds: [tafEmbed] }); - } catch (error) { - Logger.error('taf:', error); - const fetchErrorEmbed = makeEmbed({ - title: 'TAF Error | Fetch Error', - description: 'There was an error fetching the TAF report. Please try again later.', - color: Colors.Red, - }); - return interaction.editReply({ embeds: [fetchErrorEmbed] }); - } + return interaction.editReply({ embeds: [tafEmbed] }); + } catch (error) { + Logger.error('taf:', error); + const fetchErrorEmbed = makeEmbed({ + title: 'TAF Error | Fetch Error', + description: 'There was an error fetching the TAF report. Please try again later.', + color: Colors.Red, + }); + return interaction.editReply({ embeds: [fetchErrorEmbed] }); + } }); diff --git a/src/commands/utils/vatsim/functions/vatsimControllers.ts b/src/commands/utils/vatsim/functions/vatsimControllers.ts index 32dcf34a..83a65b52 100644 --- a/src/commands/utils/vatsim/functions/vatsimControllers.ts +++ b/src/commands/utils/vatsim/functions/vatsimControllers.ts @@ -4,111 +4,111 @@ import { makeEmbed } from '../../../../lib'; /* eslint-disable camelcase */ const listEmbed = (type: string, fields: EmbedField[], totalCount: number, shownCount: number, callsign: string) => - makeEmbed({ - title: `VATSIM Data - ${callsign} - ${totalCount} ${type} online`, - description: `A list of ${shownCount} online ${type} matching ${callsign}.`, - fields, - }); + makeEmbed({ + title: `VATSIM Data - ${callsign} - ${totalCount} ${type} online`, + description: `A list of ${shownCount} online ${type} matching ${callsign}.`, + fields, + }); const controllersListEmbedFields = ( - callsign: string, - frequency: string, - logon: string, - rating: string, - atis: string, - atisCode: string, + callsign: string, + frequency: string, + logon: string, + rating: string, + atis: string, + atisCode: string, ): EmbedField[] => { - const fields = [ - { - name: 'Callsign', - value: `${callsign}`, - inline: false, - }, - { - name: 'Frequency', - value: `${frequency}`, - inline: true, - }, - { - name: 'Logon Date & Time', - value: `${logon}`, - inline: true, - }, - { - name: 'Rating', - value: `${rating}`, - inline: true, - }, - ]; - if (atis !== null) { - let atisTitle = 'Info'; - if (atisCode) { - atisTitle = `ATIS - Code: ${atisCode}`; - } else if (atisCode !== undefined) { - atisTitle = 'ATIS'; - } - fields.push({ - name: atisTitle, - value: atis, - inline: false, - }); + const fields = [ + { + name: 'Callsign', + value: `${callsign}`, + inline: false, + }, + { + name: 'Frequency', + value: `${frequency}`, + inline: true, + }, + { + name: 'Logon Date & Time', + value: `${logon}`, + inline: true, + }, + { + name: 'Rating', + value: `${rating}`, + inline: true, + }, + ]; + if (atis !== null) { + let atisTitle = 'Info'; + if (atisCode) { + atisTitle = `ATIS - Code: ${atisCode}`; + } else if (atisCode !== undefined) { + atisTitle = 'ATIS'; } + fields.push({ + name: atisTitle, + value: atis, + inline: false, + }); + } - return fields; + return fields; }; const handleLocaleDateTimeString = (date: Date) => - date.toLocaleDateString('en-US', { - hour: 'numeric', - minute: 'numeric', - weekday: 'short', - month: 'short', - day: 'numeric', - }); + date.toLocaleDateString('en-US', { + hour: 'numeric', + minute: 'numeric', + weekday: 'short', + month: 'short', + day: 'numeric', + }); export async function handleVatsimControllers( - interaction: ChatInputCommandInteraction<'cached'>, - vatsimData: any, - callsignSearch: any, + interaction: ChatInputCommandInteraction<'cached'>, + vatsimData: any, + callsignSearch: any, ) { - const vatsimAllControllers = vatsimData.controllers - ? vatsimData.controllers.filter((controller: { facility: number }) => controller.facility > 0) - : null; + const vatsimAllControllers = vatsimData.controllers + ? vatsimData.controllers.filter((controller: { facility: number }) => controller.facility > 0) + : null; - const vatsimControllerRatings = vatsimData.ratings ? vatsimData.ratings : null; - const vatsimControllers = vatsimAllControllers - ? vatsimAllControllers.filter((controller: { callsign: string | string[] }) => - controller.callsign.includes(callsignSearch), - ) - : null; - const vatsimAtis = vatsimData.atis - ? vatsimData.atis.filter((atis: { callsign: string | string[] }) => atis.callsign.includes(callsignSearch)) - : null; + const vatsimControllerRatings = vatsimData.ratings ? vatsimData.ratings : null; + const vatsimControllers = vatsimAllControllers + ? vatsimAllControllers.filter((controller: { callsign: string | string[] }) => + controller.callsign.includes(callsignSearch), + ) + : null; + const vatsimAtis = vatsimData.atis + ? vatsimData.atis.filter((atis: { callsign: string | string[] }) => atis.callsign.includes(callsignSearch)) + : null; - const { keys }: ObjectConstructor = Object; + const { keys }: ObjectConstructor = Object; - const fields: EmbedField[] = [ - ...vatsimControllers.sort((a: { facility: number }, b: { facility: number }) => b.facility - a.facility), - ...vatsimAtis, - ] - .map((vatsimController) => { - const { callsign, frequency, logon_time, atis_code, text_atis, rating } = vatsimController; - const logonTime = new Date(logon_time); - const logonTimeString = handleLocaleDateTimeString(logonTime); - const ratingDetail = vatsimControllerRatings.filter((ratingInfo: { id: any }) => ratingInfo.id === rating); - const { short, long } = ratingDetail[0]; - const ratingText = `${short} - ${long}`; - const atisText = text_atis ? text_atis.join('\n') : null; + const fields: EmbedField[] = [ + ...vatsimControllers.sort((a: { facility: number }, b: { facility: number }) => b.facility - a.facility), + ...vatsimAtis, + ] + .map((vatsimController) => { + const { callsign, frequency, logon_time, atis_code, text_atis, rating } = vatsimController; + const logonTime = new Date(logon_time); + const logonTimeString = handleLocaleDateTimeString(logonTime); + const ratingDetail = vatsimControllerRatings.filter((ratingInfo: { id: any }) => ratingInfo.id === rating); + const { short, long } = ratingDetail[0]; + const ratingText = `${short} - ${long}`; + const atisText = text_atis ? text_atis.join('\n') : null; - return controllersListEmbedFields(callsign, frequency, logonTimeString, ratingText, atisText, atis_code); - }) - .slice(0, 5) - .flat(); + return controllersListEmbedFields(callsign, frequency, logonTimeString, ratingText, atisText, atis_code); + }) + .slice(0, 5) + .flat(); - const totalCount = keys(vatsimControllers).length + keys(vatsimAtis).length; - const shownCount = totalCount < 5 ? totalCount : 5; + const totalCount = keys(vatsimControllers).length + keys(vatsimAtis).length; + const shownCount = totalCount < 5 ? totalCount : 5; - return interaction.reply({ - embeds: [listEmbed('Controllers & ATIS', fields, totalCount, shownCount, callsignSearch)], - }); + return interaction.reply({ + embeds: [listEmbed('Controllers & ATIS', fields, totalCount, shownCount, callsignSearch)], + }); } diff --git a/src/commands/utils/vatsim/functions/vatsimEvents.ts b/src/commands/utils/vatsim/functions/vatsimEvents.ts index 9206c400..66803fe9 100644 --- a/src/commands/utils/vatsim/functions/vatsimEvents.ts +++ b/src/commands/utils/vatsim/functions/vatsimEvents.ts @@ -4,85 +4,85 @@ import { Logger, makeEmbed } from '../../../../lib'; const BASE_VATSIM_URL = 'https://my.vatsim.net'; const handleLocaleTimeString = (date: Date) => - date.toLocaleTimeString('en-US', { - hour: 'numeric', - minute: 'numeric', - }); + date.toLocaleTimeString('en-US', { + hour: 'numeric', + minute: 'numeric', + }); const handleLocaleDateString = (date: Date) => - date.toLocaleDateString('en-US', { - weekday: 'short', - month: 'short', - day: 'numeric', - }); + date.toLocaleDateString('en-US', { + weekday: 'short', + month: 'short', + day: 'numeric', + }); export async function handleVatsimEvents(interaction: ChatInputCommandInteraction<'cached'>) { - await interaction.deferReply(); + await interaction.deferReply(); - try { - const eventsList = await fetch(`${BASE_VATSIM_URL}/api/v1/events/all`) - .then((res) => res.json()) - .then((res) => res.data) - .then((res) => res.filter((event: { type: string }) => event.type === 'Event')) - .then((res) => res.slice(0, 5)); + try { + const eventsList = await fetch(`${BASE_VATSIM_URL}/api/v1/events/all`) + .then((res) => res.json()) + .then((res) => res.data) + .then((res) => res.filter((event: { type: string }) => event.type === 'Event')) + .then((res) => res.slice(0, 5)); - const fields: EmbedField[] = eventsList - .map((event: any) => { - // eslint-disable-next-line camelcase - const { name, organisers, end_time, start_time, link } = event; - const { division } = organisers[0]; - const startDate = new Date(start_time); - const endDate = new Date(end_time); - const startTime = handleLocaleTimeString(startDate); - const endTime = handleLocaleTimeString(endDate); - const startDateString = handleLocaleDateString(startDate); - const endDateString = handleLocaleDateString(endDate); + const fields: EmbedField[] = eventsList + .map((event: any) => { + // eslint-disable-next-line camelcase + const { name, organisers, end_time, start_time, link } = event; + const { division } = organisers[0]; + const startDate = new Date(start_time); + const endDate = new Date(end_time); + const startTime = handleLocaleTimeString(startDate); + const endTime = handleLocaleTimeString(endDate); + const startDateString = handleLocaleDateString(startDate); + const endDateString = handleLocaleDateString(endDate); - return [ - { - name: 'Name', - value: name, - inline: false, - }, - { - name: 'Start Time/Date', - value: `${startTime}/${startDateString}`, - inline: true, - }, - { - name: 'End Time/Date', - value: `${endTime}/${endDateString}`, - inline: true, - }, - { - name: 'Division', - value: `${division}`, - inline: true, - }, - { - name: 'Link', - value: `${link}`, - inline: false, - }, - ]; - }) - .flat(); + return [ + { + name: 'Name', + value: name, + inline: false, + }, + { + name: 'Start Time/Date', + value: `${startTime}/${startDateString}`, + inline: true, + }, + { + name: 'End Time/Date', + value: `${endTime}/${endDateString}`, + inline: true, + }, + { + name: 'Division', + value: `${division}`, + inline: true, + }, + { + name: 'Link', + value: `${link}`, + inline: false, + }, + ]; + }) + .flat(); - const eventsEmbed = makeEmbed({ - title: 'VATSIM Events', - description: - 'A list of upcoming events on the VATSIM network. Find the full list [here.](https://my.vatsim.net/events)', - fields, - }); + const eventsEmbed = makeEmbed({ + title: 'VATSIM Events', + description: + 'A list of upcoming events on the VATSIM network. Find the full list [here.](https://my.vatsim.net/events)', + fields, + }); - return interaction.editReply({ embeds: [eventsEmbed] }); - } catch (error: any) { - Logger.error(error); - const errorEmbed = makeEmbed({ - title: 'Events Error', - description: error.message, - color: Colors.Red, - }); - return interaction.editReply({ embeds: [errorEmbed] }); - } + return interaction.editReply({ embeds: [eventsEmbed] }); + } catch (error: any) { + Logger.error(error); + const errorEmbed = makeEmbed({ + title: 'Events Error', + description: error.message, + color: Colors.Red, + }); + return interaction.editReply({ embeds: [errorEmbed] }); + } } diff --git a/src/commands/utils/vatsim/functions/vatsimObservers.ts b/src/commands/utils/vatsim/functions/vatsimObservers.ts index 900c9067..907b9b70 100644 --- a/src/commands/utils/vatsim/functions/vatsimObservers.ts +++ b/src/commands/utils/vatsim/functions/vatsimObservers.ts @@ -4,88 +4,86 @@ import { makeEmbed } from '../../../../lib'; /* eslint-disable camelcase */ const listEmbed = (type: string, fields: EmbedField[], totalCount: number, shownCount: number, callsign: string) => - makeEmbed({ - title: `VATSIM Data - ${callsign} - ${totalCount} ${type} online`, - description: `A list of ${shownCount} online ${type} matching ${callsign}.`, - fields, - }); + makeEmbed({ + title: `VATSIM Data - ${callsign} - ${totalCount} ${type} online`, + description: `A list of ${shownCount} online ${type} matching ${callsign}.`, + fields, + }); const observersListEmbedFields = (callsign: string, logon: string, rating: string, atis: string): EmbedField[] => { - const fields = [ - { - name: 'Callsign', - value: `${callsign}`, - inline: false, - }, - { - name: 'Logon Date & Time', - value: `${logon}`, - inline: true, - }, - { - name: 'Rating', - value: `${rating}`, - inline: true, - }, - ]; - if (atis !== null) { - const atisTitle = 'Info'; - fields.push({ - name: atisTitle, - value: atis, - inline: false, - }); - } + const fields = [ + { + name: 'Callsign', + value: `${callsign}`, + inline: false, + }, + { + name: 'Logon Date & Time', + value: `${logon}`, + inline: true, + }, + { + name: 'Rating', + value: `${rating}`, + inline: true, + }, + ]; + if (atis !== null) { + const atisTitle = 'Info'; + fields.push({ + name: atisTitle, + value: atis, + inline: false, + }); + } - return fields; + return fields; }; const handleLocaleDateTimeString = (date: Date) => - date.toLocaleDateString('en-US', { - hour: 'numeric', - minute: 'numeric', - weekday: 'short', - month: 'short', - day: 'numeric', - }); + date.toLocaleDateString('en-US', { + hour: 'numeric', + minute: 'numeric', + weekday: 'short', + month: 'short', + day: 'numeric', + }); export async function handleVatsimObservers( - interaction: ChatInputCommandInteraction<'cached'>, - vatsimData: any, - callsignSearch: any, + interaction: ChatInputCommandInteraction<'cached'>, + vatsimData: any, + callsignSearch: any, ) { - const vatsimAllObservers = vatsimData.controllers - ? vatsimData.controllers.filter((controller: { facility: number }) => controller.facility <= 0) - : null; + const vatsimAllObservers = vatsimData.controllers + ? vatsimData.controllers.filter((controller: { facility: number }) => controller.facility <= 0) + : null; - const vatsimControllerRatings = vatsimData.ratings ? vatsimData.ratings : null; - const vatsimObservers = vatsimAllObservers - ? vatsimAllObservers.filter((observer: { callsign: string | any[] }) => - observer.callsign.includes(callsignSearch), - ) - : null; + const vatsimControllerRatings = vatsimData.ratings ? vatsimData.ratings : null; + const vatsimObservers = vatsimAllObservers + ? vatsimAllObservers.filter((observer: { callsign: string | any[] }) => observer.callsign.includes(callsignSearch)) + : null; - const { keys }: ObjectConstructor = Object; + const { keys }: ObjectConstructor = Object; - const fields: EmbedField[] = [ - ...vatsimObservers.sort((a: { rating: number }, b: { rating: number }) => b.rating - a.rating), - ] - .map((vatsimObserver) => { - const { callsign, logon_time, text_atis, rating } = vatsimObserver; - const logonTime = new Date(logon_time); - const logonTimeString = handleLocaleDateTimeString(logonTime); - const ratingDetail = vatsimControllerRatings.filter((ratingInfo: { id: any }) => ratingInfo.id === rating); - const { short, long } = ratingDetail[0]; - const ratingText = `${short} - ${long}`; - const atisText = text_atis ? text_atis.join('\n') : null; + const fields: EmbedField[] = [ + ...vatsimObservers.sort((a: { rating: number }, b: { rating: number }) => b.rating - a.rating), + ] + .map((vatsimObserver) => { + const { callsign, logon_time, text_atis, rating } = vatsimObserver; + const logonTime = new Date(logon_time); + const logonTimeString = handleLocaleDateTimeString(logonTime); + const ratingDetail = vatsimControllerRatings.filter((ratingInfo: { id: any }) => ratingInfo.id === rating); + const { short, long } = ratingDetail[0]; + const ratingText = `${short} - ${long}`; + const atisText = text_atis ? text_atis.join('\n') : null; - return observersListEmbedFields(callsign, logonTimeString, ratingText, atisText); - }) - .slice(0, 5) - .flat(); + return observersListEmbedFields(callsign, logonTimeString, ratingText, atisText); + }) + .slice(0, 5) + .flat(); - const totalCount = keys(vatsimObservers).length; - const shownCount = totalCount < 5 ? totalCount : 5; + const totalCount = keys(vatsimObservers).length; + const shownCount = totalCount < 5 ? totalCount : 5; - return interaction.reply({ embeds: [listEmbed('Observers', fields, totalCount, shownCount, callsignSearch)] }); + return interaction.reply({ embeds: [listEmbed('Observers', fields, totalCount, shownCount, callsignSearch)] }); } diff --git a/src/commands/utils/vatsim/functions/vatsimPilots.ts b/src/commands/utils/vatsim/functions/vatsimPilots.ts index bb299da1..47ef8127 100644 --- a/src/commands/utils/vatsim/functions/vatsimPilots.ts +++ b/src/commands/utils/vatsim/functions/vatsimPilots.ts @@ -4,76 +4,72 @@ import { makeEmbed } from '../../../../lib'; /* eslint-disable camelcase */ const listEmbed = (type: string, fields: EmbedField[], totalCount: number, shownCount: number, callsign: string) => - makeEmbed({ - title: `VATSIM Data - ${callsign} - ${totalCount} ${type} online`, - description: `A list of ${shownCount} online ${type} matching ${callsign}.`, - fields, - }); + makeEmbed({ + title: `VATSIM Data - ${callsign} - ${totalCount} ${type} online`, + description: `A list of ${shownCount} online ${type} matching ${callsign}.`, + fields, + }); const pilotsListEmbedFields = (callsign: string, rating: string, flightPlan: any) => { - const fields = [ - { - name: 'Callsign', - value: callsign, - inline: false, - }, - { - name: 'Rating', - value: rating, - inline: true, - }, - ]; + const fields = [ + { + name: 'Callsign', + value: callsign, + inline: false, + }, + { + name: 'Rating', + value: rating, + inline: true, + }, + ]; - if (flightPlan !== null) { - const { aircraft_short, departure, arrival } = flightPlan; - fields.push( - { - name: 'Route', - value: `${departure} - ${arrival}`, - inline: true, - }, - { - name: 'Aircraft', - value: `${aircraft_short}`, - inline: true, - }, - ); - } + if (flightPlan !== null) { + const { aircraft_short, departure, arrival } = flightPlan; + fields.push( + { + name: 'Route', + value: `${departure} - ${arrival}`, + inline: true, + }, + { + name: 'Aircraft', + value: `${aircraft_short}`, + inline: true, + }, + ); + } - return fields; + return fields; }; export async function handleVatsimPilots( - interaction: ChatInputCommandInteraction<'cached'>, - vatsimData: any, - callsignSearch: any, + interaction: ChatInputCommandInteraction<'cached'>, + vatsimData: any, + callsignSearch: any, ) { - const vatsimPilotRatings = vatsimData.pilot_ratings ? vatsimData.pilot_ratings : null; - const vatsimPilots = vatsimData.pilots - ? vatsimData.pilots.filter((pilot: { callsign: (string | null)[] }) => pilot.callsign.includes(callsignSearch)) - : null; + const vatsimPilotRatings = vatsimData.pilot_ratings ? vatsimData.pilot_ratings : null; + const vatsimPilots = vatsimData.pilots + ? vatsimData.pilots.filter((pilot: { callsign: (string | null)[] }) => pilot.callsign.includes(callsignSearch)) + : null; - const { keys }: ObjectConstructor = Object; + const { keys }: ObjectConstructor = Object; - const fields: EmbedField[] = [ - ...vatsimPilots.sort( - (a: { pilot_rating: number }, b: { pilot_rating: number }) => b.pilot_rating - a.pilot_rating, - ), - ] - .map((vatsimPilot) => { - const { callsign, pilot_rating, flight_plan } = vatsimPilot; - const ratingDetail = vatsimPilotRatings.filter( - (ratingInfo: { id: number }) => ratingInfo.id === pilot_rating, - ); - const { short_name, long_name } = ratingDetail[0]; - const ratingText = `${short_name} - ${long_name}`; + const fields: EmbedField[] = [ + ...vatsimPilots.sort((a: { pilot_rating: number }, b: { pilot_rating: number }) => b.pilot_rating - a.pilot_rating), + ] + .map((vatsimPilot) => { + const { callsign, pilot_rating, flight_plan } = vatsimPilot; + const ratingDetail = vatsimPilotRatings.filter((ratingInfo: { id: number }) => ratingInfo.id === pilot_rating); + const { short_name, long_name } = ratingDetail[0]; + const ratingText = `${short_name} - ${long_name}`; - return pilotsListEmbedFields(callsign, ratingText, flight_plan); - }) - .slice(0, 5) - .flat(); + return pilotsListEmbedFields(callsign, ratingText, flight_plan); + }) + .slice(0, 5) + .flat(); - const totalCount = keys(vatsimPilots).length; - const shownCount = totalCount < 5 ? totalCount : 5; + const totalCount = keys(vatsimPilots).length; + const shownCount = totalCount < 5 ? totalCount : 5; - return interaction.reply({ embeds: [listEmbed('Pilots', fields, totalCount, shownCount, callsignSearch)] }); + return interaction.reply({ embeds: [listEmbed('Pilots', fields, totalCount, shownCount, callsignSearch)] }); } diff --git a/src/commands/utils/vatsim/functions/vatsimStats.ts b/src/commands/utils/vatsim/functions/vatsimStats.ts index 19b065fe..b5a02f2c 100644 --- a/src/commands/utils/vatsim/functions/vatsimStats.ts +++ b/src/commands/utils/vatsim/functions/vatsimStats.ts @@ -2,82 +2,80 @@ import { ChatInputCommandInteraction } from 'discord.js'; import { makeEmbed } from '../../../../lib'; const statsEmbed = (pilots: string, controllers: string, atis: string, observers: string, callsign: any) => - makeEmbed({ - title: callsign ? `VATSIM Data | Statistics for callsign ${callsign}` : 'VATSIM Data | Statistics', - description: callsign - ? `An overview of the current active Pilots, Controllers, ATIS and Observers matching ${callsign}.` - : 'An overview of the current active Pilots, Controllers, ATIS and Observers.', - fields: [ - { - name: 'Pilots', - value: pilots, - inline: true, - }, - { - name: 'Controllers', - value: controllers, - inline: true, - }, - { - name: 'ATIS', - value: atis, - inline: true, - }, - { - name: 'Observers', - value: observers, - inline: true, - }, - ], - }); + makeEmbed({ + title: callsign ? `VATSIM Data | Statistics for callsign ${callsign}` : 'VATSIM Data | Statistics', + description: callsign + ? `An overview of the current active Pilots, Controllers, ATIS and Observers matching ${callsign}.` + : 'An overview of the current active Pilots, Controllers, ATIS and Observers.', + fields: [ + { + name: 'Pilots', + value: pilots, + inline: true, + }, + { + name: 'Controllers', + value: controllers, + inline: true, + }, + { + name: 'ATIS', + value: atis, + inline: true, + }, + { + name: 'Observers', + value: observers, + inline: true, + }, + ], + }); export async function handleVatsimStats( - interaction: ChatInputCommandInteraction<'cached'>, - vatsimData: any, - callsignSearch: any, + interaction: ChatInputCommandInteraction<'cached'>, + vatsimData: any, + callsignSearch: any, ) { - const vatsimAllControllers = vatsimData.controllers - ? vatsimData.controllers.filter((controller: { facility: number }) => controller.facility > 0) - : null; - const vatsimAllObservers = vatsimData.controllers - ? vatsimData.controllers.filter((controller: { facility: number }) => controller.facility <= 0) - : null; - - if (!callsignSearch) { - const vatsimPilotCount = vatsimData.pilots ? vatsimData.pilots.length : 0; - const vatsimControllerCount = vatsimAllControllers ? vatsimAllControllers.length : 0; - const vatsimAtisCount = vatsimData.atis ? vatsimData.atis.length : 0; - const vatsimObserverCount = vatsimAllObservers ? vatsimAllObservers.length : 0; - - return interaction.reply({ - embeds: [statsEmbed(vatsimPilotCount, vatsimControllerCount, vatsimAtisCount, vatsimObserverCount, null)], - }); - } - const vatsimPilots = vatsimData.pilots - ? vatsimData.pilots.filter((pilot: { callsign: string | string[] }) => pilot.callsign.includes(callsignSearch)) - : null; - const vatsimControllers = vatsimAllControllers - ? vatsimAllControllers.filter((controller: { callsign: string | string[] }) => - controller.callsign.includes(callsignSearch), - ) - : null; - const vatsimAtis = vatsimData.atis - ? vatsimData.atis.filter((atis: { callsign: string | string[] }) => atis.callsign.includes(callsignSearch)) - : null; - const vatsimObservers = vatsimAllObservers - ? vatsimAllObservers.filter((observer: { callsign: string | string[] }) => - observer.callsign.includes(callsignSearch), - ) - : null; + const vatsimAllControllers = vatsimData.controllers + ? vatsimData.controllers.filter((controller: { facility: number }) => controller.facility > 0) + : null; + const vatsimAllObservers = vatsimData.controllers + ? vatsimData.controllers.filter((controller: { facility: number }) => controller.facility <= 0) + : null; - const vatsimPilotCount = vatsimPilots ? vatsimPilots.length : 0; - const vatsimControllerCount = vatsimControllers ? vatsimControllers.length : 0; - const vatsimAtisCount = vatsimAtis ? vatsimAtis.length : 0; - const vatsimObserverCount = vatsimObservers ? vatsimObservers.length : 0; + if (!callsignSearch) { + const vatsimPilotCount = vatsimData.pilots ? vatsimData.pilots.length : 0; + const vatsimControllerCount = vatsimAllControllers ? vatsimAllControllers.length : 0; + const vatsimAtisCount = vatsimData.atis ? vatsimData.atis.length : 0; + const vatsimObserverCount = vatsimAllObservers ? vatsimAllObservers.length : 0; return interaction.reply({ - embeds: [ - statsEmbed(vatsimPilotCount, vatsimControllerCount, vatsimAtisCount, vatsimObserverCount, callsignSearch), - ], + embeds: [statsEmbed(vatsimPilotCount, vatsimControllerCount, vatsimAtisCount, vatsimObserverCount, null)], }); + } + const vatsimPilots = vatsimData.pilots + ? vatsimData.pilots.filter((pilot: { callsign: string | string[] }) => pilot.callsign.includes(callsignSearch)) + : null; + const vatsimControllers = vatsimAllControllers + ? vatsimAllControllers.filter((controller: { callsign: string | string[] }) => + controller.callsign.includes(callsignSearch), + ) + : null; + const vatsimAtis = vatsimData.atis + ? vatsimData.atis.filter((atis: { callsign: string | string[] }) => atis.callsign.includes(callsignSearch)) + : null; + const vatsimObservers = vatsimAllObservers + ? vatsimAllObservers.filter((observer: { callsign: string | string[] }) => + observer.callsign.includes(callsignSearch), + ) + : null; + + const vatsimPilotCount = vatsimPilots ? vatsimPilots.length : 0; + const vatsimControllerCount = vatsimControllers ? vatsimControllers.length : 0; + const vatsimAtisCount = vatsimAtis ? vatsimAtis.length : 0; + const vatsimObserverCount = vatsimObservers ? vatsimObservers.length : 0; + + return interaction.reply({ + embeds: [statsEmbed(vatsimPilotCount, vatsimControllerCount, vatsimAtisCount, vatsimObserverCount, callsignSearch)], + }); } diff --git a/src/commands/utils/vatsim/vatsim.ts b/src/commands/utils/vatsim/vatsim.ts index 8c34ec55..8861090b 100644 --- a/src/commands/utils/vatsim/vatsim.ts +++ b/src/commands/utils/vatsim/vatsim.ts @@ -7,144 +7,144 @@ import { handleVatsimObservers } from './functions/vatsimObservers'; import { handleVatsimEvents } from './functions/vatsimEvents'; const data = slashCommandStructure({ - name: 'vatsim', - description: 'Displays information about Vatsim.', - type: ApplicationCommandType.ChatInput, - options: [ + name: 'vatsim', + description: 'Displays information about Vatsim.', + type: ApplicationCommandType.ChatInput, + options: [ + { + name: 'data', + description: 'Vatsim data.', + type: ApplicationCommandOptionType.SubcommandGroup, + options: [ { - name: 'data', - description: 'Vatsim data.', - type: ApplicationCommandOptionType.SubcommandGroup, - options: [ - { - name: 'stats', - description: 'Displays Vatsim stats.', - type: ApplicationCommandOptionType.Subcommand, - options: [ - { - name: 'callsign', - description: 'Please provide a callsign to retrieve specific data.', - type: ApplicationCommandOptionType.String, - required: false, - }, - ], - }, - { - name: 'controllers', - description: 'Displays Vatsim controllers and ATIS.', - type: ApplicationCommandOptionType.Subcommand, - options: [ - { - name: 'callsign', - description: 'Please provide a callsign.', - type: ApplicationCommandOptionType.String, - required: true, - }, - ], - }, - { - name: 'pilots', - description: 'Displays Vatsim pilots.', - type: ApplicationCommandOptionType.Subcommand, - options: [ - { - name: 'callsign', - description: 'Please provide a callsign.', - type: ApplicationCommandOptionType.String, - required: true, - }, - ], - }, - { - name: 'observers', - description: 'Displays Vatsim observers.', - type: ApplicationCommandOptionType.Subcommand, - options: [ - { - name: 'callsign', - description: 'Please provide a callsign.', - type: ApplicationCommandOptionType.String, - required: true, - }, - ], - }, - ], + name: 'stats', + description: 'Displays Vatsim stats.', + type: ApplicationCommandOptionType.Subcommand, + options: [ + { + name: 'callsign', + description: 'Please provide a callsign to retrieve specific data.', + type: ApplicationCommandOptionType.String, + required: false, + }, + ], }, { - name: 'events', - description: 'Displays Vatsim events.', - type: ApplicationCommandOptionType.Subcommand, + name: 'controllers', + description: 'Displays Vatsim controllers and ATIS.', + type: ApplicationCommandOptionType.Subcommand, + options: [ + { + name: 'callsign', + description: 'Please provide a callsign.', + type: ApplicationCommandOptionType.String, + required: true, + }, + ], }, - ], + { + name: 'pilots', + description: 'Displays Vatsim pilots.', + type: ApplicationCommandOptionType.Subcommand, + options: [ + { + name: 'callsign', + description: 'Please provide a callsign.', + type: ApplicationCommandOptionType.String, + required: true, + }, + ], + }, + { + name: 'observers', + description: 'Displays Vatsim observers.', + type: ApplicationCommandOptionType.Subcommand, + options: [ + { + name: 'callsign', + description: 'Please provide a callsign.', + type: ApplicationCommandOptionType.String, + required: true, + }, + ], + }, + ], + }, + { + name: 'events', + description: 'Displays Vatsim events.', + type: ApplicationCommandOptionType.Subcommand, + }, + ], }); const fetchErrorEmbed = (error: any) => - makeEmbed({ - title: 'VATSIM Data - Fetching data failure', - description: `Could not fetch the VATSIM data from the VATSIM API service: ${error}`, - color: Colors.Red, - }); + makeEmbed({ + title: 'VATSIM Data - Fetching data failure', + description: `Could not fetch the VATSIM data from the VATSIM API service: ${error}`, + color: Colors.Red, + }); export default slashCommand(data, async ({ interaction }) => { - // Fetch VATSIM data + // Fetch VATSIM data - let vatsimData; - try { - vatsimData = await fetch('https://data.vatsim.net/v3/vatsim-data.json').then((response) => { - if (response.ok) { - return response.json(); - } - throw new Error(response.statusText); - }); - } catch (error) { - await interaction.reply({ embeds: [fetchErrorEmbed(error)], ephemeral: true }); - return; - } - - // Grap the callsign from the interaction + let vatsimData; + try { + vatsimData = await fetch('https://data.vatsim.net/v3/vatsim-data.json').then((response) => { + if (response.ok) { + return response.json(); + } + throw new Error(response.statusText); + }); + } catch (error) { + await interaction.reply({ embeds: [fetchErrorEmbed(error)], ephemeral: true }); + return; + } - let callsign = interaction.options.getString('callsign'); - let callsignSearch; + // Grap the callsign from the interaction - if (callsign) { - callsign = callsign.toUpperCase(); + let callsign = interaction.options.getString('callsign'); + let callsignSearch; - const regexCheck = /^["']?(?[\w-]+)?["']?\s*$/; - const regexMatches = callsign.match(regexCheck); + if (callsign) { + callsign = callsign.toUpperCase(); - if (!regexMatches || !regexMatches.groups || !regexMatches.groups.callsignSearch) { - // eslint-disable-next-line consistent-return - return interaction.reply({ - content: 'You need to provide a valid callsign or part of a callsign to search for', - ephemeral: true, - }); - } + const regexCheck = /^["']?(?[\w-]+)?["']?\s*$/; + const regexMatches = callsign.match(regexCheck); - callsignSearch = regexMatches.groups.callsignSearch; + if (!regexMatches || !regexMatches.groups || !regexMatches.groups.callsignSearch) { + // eslint-disable-next-line consistent-return + return interaction.reply({ + content: 'You need to provide a valid callsign or part of a callsign to search for', + ephemeral: true, + }); } - // Handle the subcommands + callsignSearch = regexMatches.groups.callsignSearch; + } - const subcommandName = interaction.options.getSubcommand(); + // Handle the subcommands - switch (subcommandName) { - case 'stats': - await handleVatsimStats(interaction, vatsimData, callsignSearch); - break; - case 'controllers': - await handleVatsimControllers(interaction, vatsimData, callsignSearch); - break; - case 'pilots': - await handleVatsimPilots(interaction, vatsimData, callsignSearch); - break; - case 'observers': - await handleVatsimObservers(interaction, vatsimData, callsignSearch); - break; - case 'events': - await handleVatsimEvents(interaction); - break; + const subcommandName = interaction.options.getSubcommand(); - default: - await interaction.reply({ content: 'Unknown subcommand', ephemeral: true }); - } + switch (subcommandName) { + case 'stats': + await handleVatsimStats(interaction, vatsimData, callsignSearch); + break; + case 'controllers': + await handleVatsimControllers(interaction, vatsimData, callsignSearch); + break; + case 'pilots': + await handleVatsimPilots(interaction, vatsimData, callsignSearch); + break; + case 'observers': + await handleVatsimObservers(interaction, vatsimData, callsignSearch); + break; + case 'events': + await handleVatsimEvents(interaction); + break; + + default: + await interaction.reply({ content: 'Unknown subcommand', ephemeral: true }); + } }); diff --git a/src/commands/utils/wolframAlpha.ts b/src/commands/utils/wolframAlpha.ts index 36b83e6a..c9d51cf8 100644 --- a/src/commands/utils/wolframAlpha.ts +++ b/src/commands/utils/wolframAlpha.ts @@ -2,116 +2,116 @@ import { ApplicationCommandOptionType, ApplicationCommandType, Colors } from 'di import { slashCommand, slashCommandStructure, makeEmbed, makeLines, Logger } from '../../lib'; const data = slashCommandStructure({ - name: 'wolframalpha', - description: 'Queries the Wolfram Alpha API.', - type: ApplicationCommandType.ChatInput, - options: [ - { - name: 'query', - description: 'Please provide a query. For example: `.wa How much is 1 + 1?`.', - type: ApplicationCommandOptionType.String, - required: true, - }, - ], + name: 'wolframalpha', + description: 'Queries the Wolfram Alpha API.', + type: ApplicationCommandType.ChatInput, + options: [ + { + name: 'query', + description: 'Please provide a query. For example: `.wa How much is 1 + 1?`.', + type: ApplicationCommandOptionType.String, + required: true, + }, + ], }); const noQueryEmbed = makeEmbed({ - title: 'Wolfram Alpha Error | Missing Query', - description: 'Please provide a query. For example: `.wa How much is 1 + 1?`', - color: Colors.Red, + title: 'Wolfram Alpha Error | Missing Query', + description: 'Please provide a query. For example: `.wa How much is 1 + 1?`', + color: Colors.Red, }); const WOLFRAMALPHA_API_URL = 'https://api.wolframalpha.com/v2/query?'; const WOLFRAMALPHA_QUERY_URL = 'https://www.wolframalpha.com/input/?'; export default slashCommand(data, async ({ interaction }) => { - await interaction.deferReply(); + await interaction.deferReply(); - const wolframAlphaToken = process.env.WOLFRAMALPHA_TOKEN; + const wolframAlphaToken = process.env.WOLFRAMALPHA_TOKEN; - if (!wolframAlphaToken) { - const noTokenEmbed = makeEmbed({ - title: 'Error | Wolfram Alpha', - description: 'Wolfram Alpha token not found.', - color: Colors.Red, - }); - return interaction.followUp({ embeds: [noTokenEmbed], ephemeral: true }); - } - - const query = interaction.options.getString('query'); + if (!wolframAlphaToken) { + const noTokenEmbed = makeEmbed({ + title: 'Error | Wolfram Alpha', + description: 'Wolfram Alpha token not found.', + color: Colors.Red, + }); + return interaction.followUp({ embeds: [noTokenEmbed], ephemeral: true }); + } - if (!query) return interaction.followUp({ embeds: [noQueryEmbed], ephemeral: true }); + const query = interaction.options.getString('query'); - const params = { - appid: wolframAlphaToken, - input: query, - format: 'plaintext', - output: 'JSON', - }; + if (!query) return interaction.followUp({ embeds: [noQueryEmbed], ephemeral: true }); - const searchParams = new URLSearchParams(params); + const params = { + appid: wolframAlphaToken, + input: query, + format: 'plaintext', + output: 'JSON', + }; - try { - const response = await fetch(`${WOLFRAMALPHA_API_URL}${searchParams.toString()}`).then((res) => res.json()); - - if (response.error) { - const errorEmbed = makeEmbed({ - title: 'Wolfram Alpha Error', - description: response.error, - color: Colors.Red, - }); - return interaction.followUp({ embeds: [errorEmbed], ephemeral: true }); - } + const searchParams = new URLSearchParams(params); - if (response.queryresult.success === true) { - const podTexts: string[] = []; - response.queryresult.pods.forEach((pod: any) => { - if (pod.id !== 'Input' && pod.primary === true) { - const results: string[] = []; - pod.subpods.forEach((subpod: any) => { - results.push(subpod.plaintext); - }); - if (results.length > 0) { - podTexts.push(`**${pod.title}:** \n${results.join('\n')}`); - } - } - }); - if (podTexts.length > 0) { - const result = podTexts.join('\n\n'); - const queryParams = new URLSearchParams({ i: query }); + try { + const response = await fetch(`${WOLFRAMALPHA_API_URL}${searchParams.toString()}`).then((res) => res.json()); - const waEmbed = makeEmbed({ - description: makeLines([ - `**Query:** ${query}`, - '', - result, - '', - `[Web Result](${WOLFRAMALPHA_QUERY_URL}${queryParams.toString()})`, - ]), - }); + if (response.error) { + const errorEmbed = makeEmbed({ + title: 'Wolfram Alpha Error', + description: response.error, + color: Colors.Red, + }); + return interaction.followUp({ embeds: [errorEmbed], ephemeral: true }); + } - return interaction.followUp({ embeds: [waEmbed] }); - } - const noResultsEmbed = makeEmbed({ - title: 'Wolfram Alpha Error | No Results', - description: makeLines(['No results were found for your query.']), - color: Colors.Red, - }); - return interaction.followUp({ embeds: [noResultsEmbed], ephemeral: true }); + if (response.queryresult.success === true) { + const podTexts: string[] = []; + response.queryresult.pods.forEach((pod: any) => { + if (pod.id !== 'Input' && pod.primary === true) { + const results: string[] = []; + pod.subpods.forEach((subpod: any) => { + results.push(subpod.plaintext); + }); + if (results.length > 0) { + podTexts.push(`**${pod.title}:** \n${results.join('\n')}`); + } } - const obscureQueryEmbed = makeEmbed({ - title: 'Wolfram Alpha Error | Could not understand query', - description: makeLines(['Wolfram Alpha could not understand your query.']), - color: Colors.Red, - }); - return interaction.followUp({ embeds: [obscureQueryEmbed], ephemeral: true }); - } catch (e) { - Logger.error('wolframalpha:', e); - const fetchErrorEmbed = makeEmbed({ - title: 'Wolfram Alpha | Fetch Error', - description: 'There was an error fetching your request. Please try again later.', - color: Colors.Red, + }); + if (podTexts.length > 0) { + const result = podTexts.join('\n\n'); + const queryParams = new URLSearchParams({ i: query }); + + const waEmbed = makeEmbed({ + description: makeLines([ + `**Query:** ${query}`, + '', + result, + '', + `[Web Result](${WOLFRAMALPHA_QUERY_URL}${queryParams.toString()})`, + ]), }); - return interaction.followUp({ embeds: [fetchErrorEmbed], ephemeral: true }); + + return interaction.followUp({ embeds: [waEmbed] }); + } + const noResultsEmbed = makeEmbed({ + title: 'Wolfram Alpha Error | No Results', + description: makeLines(['No results were found for your query.']), + color: Colors.Red, + }); + return interaction.followUp({ embeds: [noResultsEmbed], ephemeral: true }); } + const obscureQueryEmbed = makeEmbed({ + title: 'Wolfram Alpha Error | Could not understand query', + description: makeLines(['Wolfram Alpha could not understand your query.']), + color: Colors.Red, + }); + return interaction.followUp({ embeds: [obscureQueryEmbed], ephemeral: true }); + } catch (e) { + Logger.error('wolframalpha:', e); + const fetchErrorEmbed = makeEmbed({ + title: 'Wolfram Alpha | Fetch Error', + description: 'There was an error fetching your request. Please try again later.', + color: Colors.Red, + }); + return interaction.followUp({ embeds: [fetchErrorEmbed], ephemeral: true }); + } }); diff --git a/src/commands/utils/zulu.ts b/src/commands/utils/zulu.ts index 22557283..ed827c23 100644 --- a/src/commands/utils/zulu.ts +++ b/src/commands/utils/zulu.ts @@ -3,40 +3,40 @@ import moment from 'moment'; import { slashCommand, slashCommandStructure, makeEmbed, makeLines } from '../../lib'; const data = slashCommandStructure({ - name: 'zulu', - description: 'Get the current time at a given UTC-offset timezone.', - type: ApplicationCommandType.ChatInput, - options: [ - { - name: 'offset', - description: 'Please provide a timezone within UTC-12 and UTC+14.', - type: ApplicationCommandOptionType.String, - required: false, - }, - ], + name: 'zulu', + description: 'Get the current time at a given UTC-offset timezone.', + type: ApplicationCommandType.ChatInput, + options: [ + { + name: 'offset', + description: 'Please provide a timezone within UTC-12 and UTC+14.', + type: ApplicationCommandOptionType.String, + required: false, + }, + ], }); const dateFormat = 'HH:mm (LT)'; export default slashCommand(data, async ({ interaction }) => { - let utcOffset = interaction.options.getString('offset') ?? '0'; + let utcOffset = interaction.options.getString('offset') ?? '0'; - utcOffset = utcOffset.replace(/^[+-]+/, (match) => match[0]); - const numericOffset = parseInt(utcOffset); - const sign = utcOffset.startsWith('-') ? '-' : '+'; + utcOffset = utcOffset.replace(/^[+-]+/, (match) => match[0]); + const numericOffset = parseInt(utcOffset); + const sign = utcOffset.startsWith('-') ? '-' : '+'; - if (Number.isNaN(numericOffset) || numericOffset < -12 || numericOffset > 14) { - const invalidEmbed = makeEmbed({ - title: 'Zulu Error | Invalid Offset', - description: makeLines(['Please provide a timezone within UTC-12 and UTC+14.', 'For example: `/zulu -5`.']), - color: Colors.Red, - }); - return interaction.reply({ embeds: [invalidEmbed], ephemeral: true }); - } + if (Number.isNaN(numericOffset) || numericOffset < -12 || numericOffset > 14) { + const invalidEmbed = makeEmbed({ + title: 'Zulu Error | Invalid Offset', + description: makeLines(['Please provide a timezone within UTC-12 and UTC+14.', 'For example: `/zulu -5`.']), + color: Colors.Red, + }); + return interaction.reply({ embeds: [invalidEmbed], ephemeral: true }); + } - const formattedOffset = `${sign}${Math.abs(numericOffset)}`; + const formattedOffset = `${sign}${Math.abs(numericOffset)}`; - return interaction.reply({ - content: `It is ${moment().utc().add(utcOffset, 'hours').format(dateFormat)} in that timezone (UTC${formattedOffset}).`, - }); + return interaction.reply({ + content: `It is ${moment().utc().add(utcOffset, 'hours').format(dateFormat)} in that timezone (UTC${formattedOffset}).`, + }); }); diff --git a/src/events/autocompleteHandler.ts b/src/events/autocompleteHandler.ts index 8790d095..0ab4ee5d 100644 --- a/src/events/autocompleteHandler.ts +++ b/src/events/autocompleteHandler.ts @@ -4,38 +4,38 @@ import commandArray from '../commands'; const commandMap = new Map(); for (const cmd of commandArray) { - commandMap.set(cmd.meta.name, cmd); + commandMap.set(cmd.meta.name, cmd); } export default event(Events.InteractionCreate, async ({ log, client }, interaction) => { - if (!interaction.isAutocomplete()) { - return; - } - - if (!interaction.inCachedGuild()) { - return; - } + if (!interaction.isAutocomplete()) { + return; + } - try { - const { commandName } = interaction as { - commandName: any; - options: any; - }; + if (!interaction.inCachedGuild()) { + return; + } - const command = commandMap.get(commandName); + try { + const { commandName } = interaction as { + commandName: any; + options: any; + }; - if (!command) { - log(`Could not resolve the command with name "${commandName}"`); - return; - } + const command = commandMap.get(commandName); - if (!command.autocompleteCallback) { - log(`Command has no autocomplete, ignoring. Command: ${command.meta.name}`); - return; - } + if (!command) { + log(`Could not resolve the command with name "${commandName}"`); + return; + } - await command.autocompleteCallback({ client, log, interaction }); - } catch (error) { - log('[Autocomplete Error]', error); + if (!command.autocompleteCallback) { + log(`Command has no autocomplete, ignoring. Command: ${command.meta.name}`); + return; } + + await command.autocompleteCallback({ client, log, interaction }); + } catch (error) { + log('[Autocomplete Error]', error); + } }); diff --git a/src/events/buttonHandlers/buttonHandler.ts b/src/events/buttonHandlers/buttonHandler.ts index 65000dc9..9069cc2c 100644 --- a/src/events/buttonHandlers/buttonHandler.ts +++ b/src/events/buttonHandlers/buttonHandler.ts @@ -2,36 +2,36 @@ import { event, Events } from '../../lib'; import { handleRoleAssignment } from './functions/handleRoleAssignment'; export default event(Events.InteractionCreate, async ({ log }, interaction) => { - if (!interaction.isButton()) return; + if (!interaction.isButton()) return; - log('Button Handler: Button pressed'); + log('Button Handler: Button pressed'); - const { customId, component, user } = interaction; + const { customId, component, user } = interaction; - const buttonLabel = component?.label; + const buttonLabel = component?.label; - try { - const [prefix, ...params] = interaction.customId.split('_'); + try { + const [prefix, ...params] = interaction.customId.split('_'); - switch (prefix) { - case 'roleAssignment': - const [roleID] = params; - await handleRoleAssignment(interaction, roleID); - log(`Button Handler: Role assignment button pressed by ${user.tag} (${user.id}). roleID: ${roleID}`); - break; - default: - if (buttonLabel) { - log( - `Button Handler: Custom ID not matched. Skipping...\nCustom ID: ${customId}, Label: ${buttonLabel}, User: ${user.tag}, User ID: ${user.id}`, - ); - } else { - log( - `Button Handler: Custom ID not matched. Skipping...\nCustom ID: ${customId}, Label: null, User: ${user.tag}, User ID: ${user.id}`, - ); - } - return; + switch (prefix) { + case 'roleAssignment': + const [roleID] = params; + await handleRoleAssignment(interaction, roleID); + log(`Button Handler: Role assignment button pressed by ${user.tag} (${user.id}). roleID: ${roleID}`); + break; + default: + if (buttonLabel) { + log( + `Button Handler: Custom ID not matched. Skipping...\nCustom ID: ${customId}, Label: ${buttonLabel}, User: ${user.tag}, User ID: ${user.id}`, + ); + } else { + log( + `Button Handler: Custom ID not matched. Skipping...\nCustom ID: ${customId}, Label: null, User: ${user.tag}, User ID: ${user.id}`, + ); } - } catch (error) { - log('Button Handler: Error handling button press', error); + return; } + } catch (error) { + log('Button Handler: Error handling button press', error); + } }); diff --git a/src/events/buttonHandlers/functions/handleRoleAssignment.ts b/src/events/buttonHandlers/functions/handleRoleAssignment.ts index 7d91d2e7..c1feb3d2 100644 --- a/src/events/buttonHandlers/functions/handleRoleAssignment.ts +++ b/src/events/buttonHandlers/functions/handleRoleAssignment.ts @@ -2,43 +2,43 @@ import { ButtonInteraction, GuildMember } from 'discord.js'; import { constantsConfig, Logger } from '../../../lib'; export async function handleRoleAssignment(interaction: ButtonInteraction, roleID: string) { - await interaction.deferReply({ ephemeral: true }); + await interaction.deferReply({ ephemeral: true }); - try { - // Find the role object based on the customId - let role = null; - for (const group of constantsConfig.roleAssignmentIds) { - role = group.roles.find((r) => r.id === roleID); - if (role) break; // Stop searching if the role is found in any group - } + try { + // Find the role object based on the customId + let role = null; + for (const group of constantsConfig.roleAssignmentIds) { + role = group.roles.find((r) => r.id === roleID); + if (role) break; // Stop searching if the role is found in any group + } - if (!role) { - Logger.error('Role Assignment: Role not found'); - interaction.editReply({ content: "I couldn't find that role" }); - return; - } + if (!role) { + Logger.error('Role Assignment: Role not found'); + interaction.editReply({ content: "I couldn't find that role" }); + return; + } - if (!interaction.member) { - Logger.error('Role Assignment: Interaction member is null'); - return; - } + if (!interaction.member) { + Logger.error('Role Assignment: Interaction member is null'); + return; + } - const member = interaction.member as GuildMember; + const member = interaction.member as GuildMember; - const hasRole = member.roles.cache.has(role.id); + const hasRole = member.roles.cache.has(role.id); - if (hasRole) { - await member.roles.remove(role.id); - await interaction.editReply(`The role <@&${role.id}> has been removed.`); - } else { - await member.roles.add(role.id); - await interaction.editReply(`The role <@&${role.id}> has been added.`); - } - } catch (error) { - Logger.error(error); - await interaction.editReply({ - content: - 'Something went wrong, this role may no longer exist. Please try again. The error message has been logged.', - }); + if (hasRole) { + await member.roles.remove(role.id); + await interaction.editReply(`The role <@&${role.id}> has been removed.`); + } else { + await member.roles.add(role.id); + await interaction.editReply(`The role <@&${role.id}> has been added.`); } + } catch (error) { + Logger.error(error); + await interaction.editReply({ + content: + 'Something went wrong, this role may no longer exist. Please try again. The error message has been logged.', + }); + } } diff --git a/src/events/contextInteractionHandler.ts b/src/events/contextInteractionHandler.ts index 47728c45..94927443 100644 --- a/src/events/contextInteractionHandler.ts +++ b/src/events/contextInteractionHandler.ts @@ -4,40 +4,40 @@ import contextArray from '../commands/context'; const contextMap = new Map(contextArray.map((c) => [c.meta.name, c])); export default event(Events.InteractionCreate, async ({ log, client }, interaction) => { - if (!interaction.isContextMenuCommand()) { - return; + if (!interaction.isContextMenuCommand()) { + return; + } + + if (!interaction.inCachedGuild()) { + await interaction.reply(Reply('This bot can only be used in a server!', Color.Error)); + return; + } + + try { + const contextName = interaction.commandName; + const context = contextMap.get(contextName); + + if (!context) { + log(`Could not resolve the context with name "${contextName}"`); + return; } - if (!interaction.inCachedGuild()) { - await interaction.reply(Reply('This bot can only be used in a server!', Color.Error)); - return; - } - - try { - const contextName = interaction.commandName; - const context = contextMap.get(contextName); - - if (!context) { - log(`Could not resolve the context with name "${contextName}"`); - return; - } - - log(`[Context Command]: ${contextName} was executed by ${interaction.user.tag}`); + log(`[Context Command]: ${contextName} was executed by ${interaction.user.tag}`); - await context.callback({ client, log, interaction }); - } catch (error) { - const errorEmbed = makeEmbed({ - title: 'An error occurred while executing this context command.', - description: `${error}`, - color: Color.Error, - }); + await context.callback({ client, log, interaction }); + } catch (error) { + const errorEmbed = makeEmbed({ + title: 'An error occurred while executing this context command.', + description: `${error}`, + color: Color.Error, + }); - log('[Context Error]', error); + log('[Context Error]', error); - await interaction.followUp({ embeds: [errorEmbed] }); + await interaction.followUp({ embeds: [errorEmbed] }); - if (interaction.deferred || interaction.replied) { - log('Interaction was already replied to or deferred, ignoring'); - } + if (interaction.deferred || interaction.replied) { + log('Interaction was already replied to or deferred, ignoring'); } + } }); diff --git a/src/events/index.ts b/src/events/index.ts index 8de11afd..3110168f 100644 --- a/src/events/index.ts +++ b/src/events/index.ts @@ -11,13 +11,13 @@ import autocompleteHandler from './autocompleteHandler'; import buttonHandler from './buttonHandlers/buttonHandler'; export default [ - ready, - scamLogs, - detectBan, - slashCommandHandler, - contextInteractionHandler, - messageDelete, - messageUpdate, - autocompleteHandler, - buttonHandler, + ready, + scamLogs, + detectBan, + slashCommandHandler, + contextInteractionHandler, + messageDelete, + messageUpdate, + autocompleteHandler, + buttonHandler, ] as Event[]; diff --git a/src/events/logging/detectBan.ts b/src/events/logging/detectBan.ts index 29334d6f..3a4163f9 100644 --- a/src/events/logging/detectBan.ts +++ b/src/events/logging/detectBan.ts @@ -9,195 +9,195 @@ const MAX_RETRIES = 5; const SLEEP_TIMER = 0.5 * 1000; const noLogEmbed = (user: User, guildName: string) => - makeEmbed({ - color: Colors.Red, - author: { - name: `[BANNED] ${user.tag}`, - iconURL: user.displayAvatarURL(), - }, - description: makeLines([ - `${user.tag} was banned from ${guildName} but no audit log could be found.`, - '', - bold('NOTE - This was a non bot ban.'), - '', - `Please remember to send the user the reason they were banned and the ban appeal form - ${process.env.BAN_APPEAL_URL}`, - ]), - footer: { text: `User ID: ${user.id}` }, - }); + makeEmbed({ + color: Colors.Red, + author: { + name: `[BANNED] ${user.tag}`, + iconURL: user.displayAvatarURL(), + }, + description: makeLines([ + `${user.tag} was banned from ${guildName} but no audit log could be found.`, + '', + bold('NOTE - This was a non bot ban.'), + '', + `Please remember to send the user the reason they were banned and the ban appeal form - ${process.env.BAN_APPEAL_URL}`, + ]), + footer: { text: `User ID: ${user.id}` }, + }); const modLogEmbed = (user: User, executor: User, reason: string, formattedDate: string) => - makeEmbed({ - color: Colors.Red, - author: { - name: `[BANNED] ${user.tag}`, - iconURL: user.displayAvatarURL(), - }, - description: makeLines([ - bold('NOTE - This was a non bot ban.'), - '', - `Please remember to send the user the reason they were banned and the ban appeal form - ${process.env.BAN_APPEAL_URL}`, - ]), - fields: [ - { - name: 'User', - value: `${user}`, - }, - { - name: 'Moderator', - value: `${executor}`, - }, - { - name: 'Reason', - value: reason || 'No reason provided', - }, - { - name: 'Days of messages deleted', - value: 'Unavailable with a non bot ban', - }, - { - name: 'Date', - value: formattedDate, - }, - ], - footer: { text: `User ID: ${user.id}` }, - }); + makeEmbed({ + color: Colors.Red, + author: { + name: `[BANNED] ${user.tag}`, + iconURL: user.displayAvatarURL(), + }, + description: makeLines([ + bold('NOTE - This was a non bot ban.'), + '', + `Please remember to send the user the reason they were banned and the ban appeal form - ${process.env.BAN_APPEAL_URL}`, + ]), + fields: [ + { + name: 'User', + value: `${user}`, + }, + { + name: 'Moderator', + value: `${executor}`, + }, + { + name: 'Reason', + value: reason || 'No reason provided', + }, + { + name: 'Days of messages deleted', + value: 'Unavailable with a non bot ban', + }, + { + name: 'Date', + value: formattedDate, + }, + ], + footer: { text: `User ID: ${user.id}` }, + }); const userBannedIncompleteEmbed = (user: User, formattedDate: string) => - makeEmbed({ - color: Colors.Red, - author: { - name: `[BANNED] ${user.tag}`, - iconURL: user.displayAvatarURL(), - }, - description: makeLines([ - bold('NOTE - This was a non bot ban.'), - '', - `Please remember to send the user the reason they were banned and the ban appeal form - ${process.env.BAN_APPEAL_URL}`, - ]), - fields: [ - { - name: 'Member', - value: user.tag, - }, - { - name: 'Moderator', - value: 'Unavailable - Audit log incomplete', - }, - { - name: 'Reason', - value: 'Unavailable - Audit log incomplete', - }, - { - name: 'Days of messages deleted', - value: 'Unavailable with a non bot ban', - }, - { - name: 'Date', - value: formattedDate, - }, - ], - footer: { text: `User ID: ${user.id}` }, - }); + makeEmbed({ + color: Colors.Red, + author: { + name: `[BANNED] ${user.tag}`, + iconURL: user.displayAvatarURL(), + }, + description: makeLines([ + bold('NOTE - This was a non bot ban.'), + '', + `Please remember to send the user the reason they were banned and the ban appeal form - ${process.env.BAN_APPEAL_URL}`, + ]), + fields: [ + { + name: 'Member', + value: user.tag, + }, + { + name: 'Moderator', + value: 'Unavailable - Audit log incomplete', + }, + { + name: 'Reason', + value: 'Unavailable - Audit log incomplete', + }, + { + name: 'Days of messages deleted', + value: 'Unavailable with a non bot ban', + }, + { + name: 'Date', + value: formattedDate, + }, + ], + footer: { text: `User ID: ${user.id}` }, + }); const logFailed = makeEmbed({ - title: 'Non Bot Ban - Failed to log', - description: 'Failed to log the ban to the database, audit log could have been unavailable.', - color: Colors.Red, + title: 'Non Bot Ban - Failed to log', + description: 'Failed to log the ban to the database, audit log could have been unavailable.', + color: Colors.Red, }); export default event(Events.GuildBanAdd, async (_, msg) => { - Logger.debug('Starting Ban Handler'); - - const guildBanAdd = msg as GuildBan; - - if (guildBanAdd.guild === null) { - // DMs - return; + Logger.debug('Starting Ban Handler'); + + const guildBanAdd = msg as GuildBan; + + if (guildBanAdd.guild === null) { + // DMs + return; + } + + const modLogsChannel = (await guildBanAdd.guild.channels.resolve( + constantsConfig.channels.MOD_LOGS, + )) as TextChannel | null; + if (!modLogsChannel) { + // Exit as can't post + return; + } + + const currentDate = new Date(); + const formattedDate: string = moment(currentDate).utcOffset(0).format(); + + let executor; + let reason; + let target; + let retryCount = MAX_RETRIES; + do { + Logger.debug(`Ban Handler - Finding Audit Log entry retries left: ${retryCount}`); + if (retryCount < MAX_RETRIES) { + // eslint-disable-next-line no-await-in-loop + await new Promise((f) => setTimeout(f, SLEEP_TIMER)); } - - const modLogsChannel = (await guildBanAdd.guild.channels.resolve( - constantsConfig.channels.MOD_LOGS, - )) as TextChannel | null; - if (!modLogsChannel) { - // Exit as can't post - return; + // eslint-disable-next-line no-await-in-loop + const fetchedLogs = await guildBanAdd.guild.fetchAuditLogs({ + limit: 1, + type: AuditLogEvent.MemberBanAdd, + }); + const banLog = fetchedLogs.entries.first(); + if (banLog) { + ({ executor, reason, target } = banLog); } - const currentDate = new Date(); - const formattedDate: string = moment(currentDate).utcOffset(0).format(); - - let executor; - let reason; - let target; - let retryCount = MAX_RETRIES; - do { - Logger.debug(`Ban Handler - Finding Audit Log entry retries left: ${retryCount}`); - if (retryCount < MAX_RETRIES) { - // eslint-disable-next-line no-await-in-loop - await new Promise((f) => setTimeout(f, SLEEP_TIMER)); - } - // eslint-disable-next-line no-await-in-loop - const fetchedLogs = await guildBanAdd.guild.fetchAuditLogs({ - limit: 1, - type: AuditLogEvent.MemberBanAdd, - }); - const banLog = fetchedLogs.entries.first(); - if (banLog) { - ({ executor, reason, target } = banLog); - } - - retryCount--; - } while ((!target || target.id !== guildBanAdd.user.id) && retryCount > 0); - - if (!target) { - await modLogsChannel.send({ embeds: [noLogEmbed(guildBanAdd.user, guildBanAdd.guild.name)] }); - return; - } - if (target.id !== guildBanAdd.user.id) { - await modLogsChannel.send({ embeds: [userBannedIncompleteEmbed(guildBanAdd.user, formattedDate)] }); - return; + retryCount--; + } while ((!target || target.id !== guildBanAdd.user.id) && retryCount > 0); + + if (!target) { + await modLogsChannel.send({ embeds: [noLogEmbed(guildBanAdd.user, guildBanAdd.guild.name)] }); + return; + } + if (target.id !== guildBanAdd.user.id) { + await modLogsChannel.send({ embeds: [userBannedIncompleteEmbed(guildBanAdd.user, formattedDate)] }); + return; + } + if (executor && !constantsConfig.modLogExclude.includes(executor.id)) { + await modLogsChannel.send({ + content: executor.toString(), + embeds: [modLogEmbed(guildBanAdd.user, executor, reason as string, formattedDate)], + }); + + //Log to the DB + Logger.info('Starting Infraction process'); + + const newInfraction = { + infractionType: 'Ban', + moderatorID: executor ? executor.id : 'Unavailable', + reason: `This was a non bot ban: ${reason as string}`, + date: currentDate, + infractionID: new mongoose.Types.ObjectId(), + }; + + let userData = await Infraction.findOne({ userID: target.id }); + + Logger.info(userData); + + if (!userData) { + userData = new Infraction({ + userID: target.id, + infractions: [newInfraction], + }); + Logger.info(userData); + Logger.info('New user data created'); + } else { + userData.infractions.push(newInfraction); + Logger.info('User data updated'); } - if (executor && !constantsConfig.modLogExclude.includes(executor.id)) { - await modLogsChannel.send({ - content: executor.toString(), - embeds: [modLogEmbed(guildBanAdd.user, executor, reason as string, formattedDate)], - }); - - //Log to the DB - Logger.info('Starting Infraction process'); - - const newInfraction = { - infractionType: 'Ban', - moderatorID: executor ? executor.id : 'Unavailable', - reason: `This was a non bot ban: ${reason as string}`, - date: currentDate, - infractionID: new mongoose.Types.ObjectId(), - }; - - let userData = await Infraction.findOne({ userID: target.id }); - - Logger.info(userData); - - if (!userData) { - userData = new Infraction({ - userID: target.id, - infractions: [newInfraction], - }); - Logger.info(userData); - Logger.info('New user data created'); - } else { - userData.infractions.push(newInfraction); - Logger.info('User data updated'); - } - - try { - await userData.save(); - Logger.info('Infraction process complete'); - } catch (error) { - await modLogsChannel.send({ embeds: [logFailed] }); - Logger.error(error); - } + + try { + await userData.save(); + Logger.info('Infraction process complete'); + } catch (error) { + await modLogsChannel.send({ embeds: [logFailed] }); + Logger.error(error); } + } - Logger.debug('Ban Handler - Finished'); + Logger.debug('Ban Handler - Finished'); }); diff --git a/src/events/logging/messageDelete.ts b/src/events/logging/messageDelete.ts index 71b03f4a..fbe95f76 100644 --- a/src/events/logging/messageDelete.ts +++ b/src/events/logging/messageDelete.ts @@ -5,111 +5,111 @@ import { constantsConfig, event, Events, imageBaseUrl, Logger, makeEmbed } from const CONTENT_NOT_AVAIL = 'Unable to find content or embeds.'; export default event(Events.MessageDelete, async (_, msg) => { - try { - if (msg.guild === null || msg.author === null) { - // DMs - return; - } + try { + if (msg.guild === null || msg.author === null) { + // DMs + return; + } - if (msg.content === null || msg.content.trim() === '') { - // Old Message or empty content - return; - } + if (msg.content === null || msg.content.trim() === '') { + // Old Message or empty content + return; + } - const fetchedLogs = await msg.guild.fetchAuditLogs({ - limit: 1, - type: AuditLogEvent.MessageDelete, - }); - const deletionLog = fetchedLogs.entries.first(); - const currentDate = new Date(); - const formattedDate: string = moment(currentDate).utcOffset(0).format('DD, MM, YYYY, HH:mm:ss'); - const userLogsChannel = msg.guild.channels.resolve(constantsConfig.channels.USER_LOGS) as TextChannel | null; - const messageEmbeds = msg.embeds.length > 0 ? msg.embeds : []; - const messageComponents = []; - if (msg.content) { - messageComponents.push(msg.content); - } - if (msg.attachments) { - msg.attachments.forEach((attachment) => { - if (attachment.url || attachment.proxyURL) { - messageComponents.push(attachment.url ? attachment.url : attachment.proxyURL); - } - }); + const fetchedLogs = await msg.guild.fetchAuditLogs({ + limit: 1, + type: AuditLogEvent.MessageDelete, + }); + const deletionLog = fetchedLogs.entries.first(); + const currentDate = new Date(); + const formattedDate: string = moment(currentDate).utcOffset(0).format('DD, MM, YYYY, HH:mm:ss'); + const userLogsChannel = msg.guild.channels.resolve(constantsConfig.channels.USER_LOGS) as TextChannel | null; + const messageEmbeds = msg.embeds.length > 0 ? msg.embeds : []; + const messageComponents = []; + if (msg.content) { + messageComponents.push(msg.content); + } + if (msg.attachments) { + msg.attachments.forEach((attachment) => { + if (attachment.url || attachment.proxyURL) { + messageComponents.push(attachment.url ? attachment.url : attachment.proxyURL); } - for (const messageEmbed of messageEmbeds) { - const { image, fields } = messageEmbed; - if (image) { - messageComponents.push(`<${image.url}>`); - } - for (const field of fields) { - const { name, value } = field; - if (name && value) { - messageComponents.push(`${name}: ${value}`); - } - } + }); + } + for (const messageEmbed of messageEmbeds) { + const { image, fields } = messageEmbed; + if (image) { + messageComponents.push(`<${image.url}>`); + } + for (const field of fields) { + const { name, value } = field; + if (name && value) { + messageComponents.push(`${name}: ${value}`); } + } + } - const MAX_MESSAGE_LENGTH = 1024; + const MAX_MESSAGE_LENGTH = 1024; - let messageContent = messageComponents.join('\n'); + let messageContent = messageComponents.join('\n'); - let deletedMessageFieldTitle = 'Deleted Message'; + let deletedMessageFieldTitle = 'Deleted Message'; - if (messageContent.length > MAX_MESSAGE_LENGTH) { - messageContent = `${messageComponents.join('\n').slice(0, MAX_MESSAGE_LENGTH - 3)}...`; - deletedMessageFieldTitle = 'Deleted Message (truncated)'; - } + if (messageContent.length > MAX_MESSAGE_LENGTH) { + messageContent = `${messageComponents.join('\n').slice(0, MAX_MESSAGE_LENGTH - 3)}...`; + deletedMessageFieldTitle = 'Deleted Message (truncated)'; + } - const messageReference = msg.reference ? await msg.fetchReference() : null; - const messageDeleteEmbed = makeEmbed({ - color: Colors.Red, - thumbnail: { url: `${imageBaseUrl}/moderation/message_deleted.png` }, - author: { - name: msg.author.tag, - iconURL: msg.author.displayAvatarURL(), - }, - fields: [ - { - name: 'Date', - value: formattedDate, - inline: true, - }, - { - name: 'Author', - value: `${msg.author}`, - inline: true, - }, - { - name: 'Channel', - value: `${msg.channel}`, - inline: true, - }, - { - name: 'Reply to', - value: messageReference ? `${messageReference.url}` : 'None', - inline: true, - }, - { - name: 'Deleted by', - value: - deletionLog && deletionLog.target.id === msg.author.id - ? `${deletionLog.executor}` - : 'No audit log was found, message was either deleted by author, or a bot', - inline: false, - }, - { - name: deletedMessageFieldTitle, - value: messageContent ? `${messageContent}` : CONTENT_NOT_AVAIL, - inline: false, - }, - ], - footer: { text: `User ID: ${msg.author.id}` }, - }); + const messageReference = msg.reference ? await msg.fetchReference() : null; + const messageDeleteEmbed = makeEmbed({ + color: Colors.Red, + thumbnail: { url: `${imageBaseUrl}/moderation/message_deleted.png` }, + author: { + name: msg.author.tag, + iconURL: msg.author.displayAvatarURL(), + }, + fields: [ + { + name: 'Date', + value: formattedDate, + inline: true, + }, + { + name: 'Author', + value: `${msg.author}`, + inline: true, + }, + { + name: 'Channel', + value: `${msg.channel}`, + inline: true, + }, + { + name: 'Reply to', + value: messageReference ? `${messageReference.url}` : 'None', + inline: true, + }, + { + name: 'Deleted by', + value: + deletionLog && deletionLog.target.id === msg.author.id + ? `${deletionLog.executor}` + : 'No audit log was found, message was either deleted by author, or a bot', + inline: false, + }, + { + name: deletedMessageFieldTitle, + value: messageContent ? `${messageContent}` : CONTENT_NOT_AVAIL, + inline: false, + }, + ], + footer: { text: `User ID: ${msg.author.id}` }, + }); - if (userLogsChannel && !constantsConfig.userLogExclude.includes(msg.author!.id)) { - await userLogsChannel.send({ embeds: [messageDeleteEmbed] }); - } - } catch (error) { - Logger.error(error); + if (userLogsChannel && !constantsConfig.userLogExclude.includes(msg.author!.id)) { + await userLogsChannel.send({ embeds: [messageDeleteEmbed] }); } + } catch (error) { + Logger.error(error); + } }); diff --git a/src/events/logging/messageUpdate.ts b/src/events/logging/messageUpdate.ts index ff8d2d70..6a86e3c3 100644 --- a/src/events/logging/messageUpdate.ts +++ b/src/events/logging/messageUpdate.ts @@ -4,71 +4,69 @@ import { constantsConfig, event, Events, imageBaseUrl, Logger, makeEmbed } from const FEATURE_NOT_AVAIL = "(can't show embeds or images)"; export default event(Events.MessageUpdate, async (_, oldMessage, newMessage) => { - try { - if (oldMessage.guild === null || oldMessage.author === null || newMessage.author === null) { - // DMs - return; - } + try { + if (oldMessage.guild === null || oldMessage.author === null || newMessage.author === null) { + // DMs + return; + } - if (oldMessage.content === null) { - // Old Message - return; - } + if (oldMessage.content === null) { + // Old Message + return; + } - if (newMessage.content === null) { - // Message was deleted - return; - } + if (newMessage.content === null) { + // Message was deleted + return; + } - const userLogsChannel = oldMessage.guild.channels.resolve( - constantsConfig.channels.USER_LOGS, - ) as TextChannel | null; + const userLogsChannel = oldMessage.guild.channels.resolve(constantsConfig.channels.USER_LOGS) as TextChannel | null; - const MAX_MESSAGE_LENGTH = 1024; + const MAX_MESSAGE_LENGTH = 1024; - let oldMessageContent = oldMessage.content; - let newMessageContent = newMessage.content; + let oldMessageContent = oldMessage.content; + let newMessageContent = newMessage.content; - let originalMessageFieldTitle = 'Original Message'; - let editedMessageFieldTitle = 'Edited Message'; + let originalMessageFieldTitle = 'Original Message'; + let editedMessageFieldTitle = 'Edited Message'; - if (oldMessageContent.length > MAX_MESSAGE_LENGTH) { - oldMessageContent = `${oldMessageContent.slice(0, MAX_MESSAGE_LENGTH - 9)}...`; - originalMessageFieldTitle = 'Original Message (truncated)'; - } + if (oldMessageContent.length > MAX_MESSAGE_LENGTH) { + oldMessageContent = `${oldMessageContent.slice(0, MAX_MESSAGE_LENGTH - 9)}...`; + originalMessageFieldTitle = 'Original Message (truncated)'; + } - if (newMessageContent.length > MAX_MESSAGE_LENGTH) { - newMessageContent = `${newMessageContent.slice(0, MAX_MESSAGE_LENGTH - 9)}...`; - editedMessageFieldTitle = 'Edited Message (truncated)'; - } + if (newMessageContent.length > MAX_MESSAGE_LENGTH) { + newMessageContent = `${newMessageContent.slice(0, MAX_MESSAGE_LENGTH - 9)}...`; + editedMessageFieldTitle = 'Edited Message (truncated)'; + } - if (userLogsChannel && !constantsConfig.userLogExclude.includes(oldMessage.author!.id)) { - const messageUpdateEmbed = makeEmbed({ - color: Colors.Orange, - thumbnail: { url: `${imageBaseUrl}/moderation/message_edited.png` }, - author: { - name: oldMessage.author.tag, - iconURL: oldMessage.author.displayAvatarURL(), - }, - fields: [ - { name: 'Author', value: `${oldMessage.author}`, inline: true }, - { name: 'Channel', value: `${oldMessage.channel}`, inline: true }, - { - name: originalMessageFieldTitle, - value: oldMessageContent ? `\`\`\`${oldMessageContent}\`\`\`` : FEATURE_NOT_AVAIL, - inline: false, - }, - { - name: editedMessageFieldTitle, - value: newMessageContent ? `\`\`\`${newMessageContent}\`\`\`` : FEATURE_NOT_AVAIL, - inline: false, - }, - ], - footer: { text: `User ID: ${oldMessage.author.id}` }, - }); - await userLogsChannel.send({ embeds: [messageUpdateEmbed] }); - } - } catch (error) { - Logger.error(error); + if (userLogsChannel && !constantsConfig.userLogExclude.includes(oldMessage.author!.id)) { + const messageUpdateEmbed = makeEmbed({ + color: Colors.Orange, + thumbnail: { url: `${imageBaseUrl}/moderation/message_edited.png` }, + author: { + name: oldMessage.author.tag, + iconURL: oldMessage.author.displayAvatarURL(), + }, + fields: [ + { name: 'Author', value: `${oldMessage.author}`, inline: true }, + { name: 'Channel', value: `${oldMessage.channel}`, inline: true }, + { + name: originalMessageFieldTitle, + value: oldMessageContent ? `\`\`\`${oldMessageContent}\`\`\`` : FEATURE_NOT_AVAIL, + inline: false, + }, + { + name: editedMessageFieldTitle, + value: newMessageContent ? `\`\`\`${newMessageContent}\`\`\`` : FEATURE_NOT_AVAIL, + inline: false, + }, + ], + footer: { text: `User ID: ${oldMessage.author.id}` }, + }); + await userLogsChannel.send({ embeds: [messageUpdateEmbed] }); } + } catch (error) { + Logger.error(error); + } }); diff --git a/src/events/logging/scamLogs.ts b/src/events/logging/scamLogs.ts index 86199bbf..2ae9bd28 100644 --- a/src/events/logging/scamLogs.ts +++ b/src/events/logging/scamLogs.ts @@ -1,212 +1,209 @@ import { codeBlock, Colors, DMChannel, TextChannel } from 'discord.js'; import mongoose from 'mongoose'; import { - constantsConfig, - makeEmbed, - makeLines, - event, - Events, - getConn, - Infraction, - Logger, - imageBaseUrl, + constantsConfig, + makeEmbed, + makeLines, + event, + Events, + getConn, + Infraction, + Logger, + imageBaseUrl, } from '../../lib'; const excludedRoles = [ - constantsConfig.roles.ADMIN_TEAM, - constantsConfig.roles.MODERATION_TEAM, - constantsConfig.roles.DEVELOPMENT_TEAM, - constantsConfig.roles.MEDIA_TEAM, - constantsConfig.roles.COMMUNITY_SUPPORT, - constantsConfig.roles.FBW_EMERITUS, + constantsConfig.roles.ADMIN_TEAM, + constantsConfig.roles.MODERATION_TEAM, + constantsConfig.roles.DEVELOPMENT_TEAM, + constantsConfig.roles.MEDIA_TEAM, + constantsConfig.roles.COMMUNITY_SUPPORT, + constantsConfig.roles.FBW_EMERITUS, ]; const noConnEmbed = makeEmbed({ - title: 'Scam Logs - No Connection', - description: 'Could not connect to the database.', - color: Colors.Red, + title: 'Scam Logs - No Connection', + description: 'Could not connect to the database.', + color: Colors.Red, }); const logFailed = makeEmbed({ - title: 'Scam Logs - Failed to log', - description: 'Failed to log the Scam Log entry to the database.', - color: Colors.Red, + title: 'Scam Logs - Failed to log', + description: 'Failed to log the Scam Log entry to the database.', + color: Colors.Red, }); const deleteFailed = makeEmbed({ - title: 'Scam Logs - Failed to delete', - description: 'Failed to delete the message.', - color: Colors.Red, + title: 'Scam Logs - Failed to delete', + description: 'Failed to delete the message.', + color: Colors.Red, }); export default event(Events.MessageCreate, async ({ log }, msg) => { - if (msg.guild === null) { - // DM's - return; + if (msg.guild === null) { + // DM's + return; + } + + const scamReportLogs = msg.guild.channels.resolve(constantsConfig.channels.SCAM_REPORT_LOGS) as TextChannel | null; + if (scamReportLogs && msg.content.toLowerCase().includes('@everyone') && !msg.author.bot) { + const conn = getConn(); + if (!conn && scamReportLogs) { + await scamReportLogs.send({ embeds: [noConnEmbed] }); + return; } - const scamReportLogs = msg.guild.channels.resolve(constantsConfig.channels.SCAM_REPORT_LOGS) as TextChannel | null; - if (scamReportLogs && msg.content.toLowerCase().includes('@everyone') && !msg.author.bot) { - const conn = getConn(); - if (!conn && scamReportLogs) { - await scamReportLogs.send({ embeds: [noConnEmbed] }); - return; - } - - const MAX_MESSAGE_LENGTH = 1024; - - let messageContent = msg.content.toString(); - - let messageContentFieldTitle = 'Message Content:'; - - if (messageContent.length > MAX_MESSAGE_LENGTH) { - messageContent = `${msg.content.slice(0, MAX_MESSAGE_LENGTH - 11)}...`; - messageContentFieldTitle = 'Message Content (truncated):'; - } - - if (!(msg.channel instanceof DMChannel)) { - let hasRole = false; - try { - excludedRoles.forEach((roleList) => { - // @ts-ignore - if (msg.member.roles.cache.some((role) => role.id === roleList)) { - hasRole = true; - } - }); - } catch (e) { - log(e); - } - // Has role, message can stay, log sent - if (hasRole) { - const allowedEmbed = makeEmbed({ - title: 'Potential Scam Alert', - thumbnail: { url: `${imageBaseUrl}/moderation/approved.png` }, - description: 'An allowed role has used @everyone', - author: { - name: msg.author.tag, - iconURL: msg.author.displayAvatarURL(), - }, - fields: [ - { - name: 'User:', - value: `${msg.author}`, - }, - { - name: 'Channel:', - value: `${msg.channel}`, - }, - { - name: messageContentFieldTitle, - value: codeBlock(messageContent), - }, - ], - }); - - await scamReportLogs.send({ embeds: [allowedEmbed] }); - return; - } - // Doesn't have role, message deleted, log sent, user timed out - try { - await msg.delete(); - } catch (e) { - log(e); - await scamReportLogs.send({ embeds: [deleteFailed] }); - } - - const notAllowedEmbed = makeEmbed({ - title: 'Potential Scam Alert', - thumbnail: { url: `${imageBaseUrl}/moderation/scam.png` }, - author: { - name: msg.author.tag, - iconURL: msg.author.displayAvatarURL(), - }, - fields: [ - { - name: 'User:', - value: `${msg.author}`, - }, - { - name: 'Channel:', - value: `${msg.channel}`, - }, - { - name: messageContentFieldTitle, - value: codeBlock(messageContent), - }, - ], - }); - // Time out - try { - // @ts-ignore - await msg.member.timeout(60 * 60 * 24 * 7 * 1000, 'Scam log'); - } catch (e) { - log(e); - const errorEmbed = makeEmbed({ - title: 'Error timing out user', - description: makeLines([ - `An error occurred while timing out ${msg.author}`, - `${codeBlock(`Error : ${e}`)}`, - ]), - color: Colors.Red, - }); - await scamReportLogs.send({ embeds: [errorEmbed] }); - } - // Try and send a DM - try { - await msg.author.send( - 'We have detected use of @everyone in one of our text channels. This function is in place to prevent discord scams and has resulted in an automatic timeout and notification of our moderation team. If this was done in error, our moderation team will reverse the timeout, however please refrain from using the @everyone ping in future.', - ); - } catch (e) { - log(e); - - const noDMEmbed = makeEmbed({ - author: { - name: msg.author.tag, - iconURL: msg.author.displayAvatarURL(), - }, - description: `DM was not sent to ${msg.author.id}.`, - }); - - await scamReportLogs.send({ embeds: [noDMEmbed] }); - } - - await scamReportLogs.send({ embeds: [notAllowedEmbed] }); - - // Add infraction to database - - Logger.info('Starting Infraction process'); - - const newInfraction = { - infractionType: 'ScamLog', - moderatorID: msg.client.user.id, - reason: `Message content: ${msg.content.toString()}`, - date: new Date(), - infractionID: new mongoose.Types.ObjectId(), - }; - - let userData = await Infraction.findOne({ UserID: msg.author.id }); - - log(userData); - - if (!userData) { - userData = new Infraction({ - userID: msg.author.id, - infractions: [newInfraction], - }); - Logger.info(userData); - Logger.info('New user data created'); - } else { - userData.infractions.push(newInfraction); - Logger.info('User data updated'); - } - - try { - await userData.save(); - Logger.info('Infraction process complete'); - } catch (error) { - await scamReportLogs.send({ embeds: [logFailed] }); - Logger.error(error); - } - } + const MAX_MESSAGE_LENGTH = 1024; + + let messageContent = msg.content.toString(); + + let messageContentFieldTitle = 'Message Content:'; + + if (messageContent.length > MAX_MESSAGE_LENGTH) { + messageContent = `${msg.content.slice(0, MAX_MESSAGE_LENGTH - 11)}...`; + messageContentFieldTitle = 'Message Content (truncated):'; + } + + if (!(msg.channel instanceof DMChannel)) { + let hasRole = false; + try { + excludedRoles.forEach((roleList) => { + // @ts-ignore + if (msg.member.roles.cache.some((role) => role.id === roleList)) { + hasRole = true; + } + }); + } catch (e) { + log(e); + } + // Has role, message can stay, log sent + if (hasRole) { + const allowedEmbed = makeEmbed({ + title: 'Potential Scam Alert', + thumbnail: { url: `${imageBaseUrl}/moderation/approved.png` }, + description: 'An allowed role has used @everyone', + author: { + name: msg.author.tag, + iconURL: msg.author.displayAvatarURL(), + }, + fields: [ + { + name: 'User:', + value: `${msg.author}`, + }, + { + name: 'Channel:', + value: `${msg.channel}`, + }, + { + name: messageContentFieldTitle, + value: codeBlock(messageContent), + }, + ], + }); + + await scamReportLogs.send({ embeds: [allowedEmbed] }); + return; + } + // Doesn't have role, message deleted, log sent, user timed out + try { + await msg.delete(); + } catch (e) { + log(e); + await scamReportLogs.send({ embeds: [deleteFailed] }); + } + + const notAllowedEmbed = makeEmbed({ + title: 'Potential Scam Alert', + thumbnail: { url: `${imageBaseUrl}/moderation/scam.png` }, + author: { + name: msg.author.tag, + iconURL: msg.author.displayAvatarURL(), + }, + fields: [ + { + name: 'User:', + value: `${msg.author}`, + }, + { + name: 'Channel:', + value: `${msg.channel}`, + }, + { + name: messageContentFieldTitle, + value: codeBlock(messageContent), + }, + ], + }); + // Time out + try { + // @ts-ignore + await msg.member.timeout(60 * 60 * 24 * 7 * 1000, 'Scam log'); + } catch (e) { + log(e); + const errorEmbed = makeEmbed({ + title: 'Error timing out user', + description: makeLines([`An error occurred while timing out ${msg.author}`, `${codeBlock(`Error : ${e}`)}`]), + color: Colors.Red, + }); + await scamReportLogs.send({ embeds: [errorEmbed] }); + } + // Try and send a DM + try { + await msg.author.send( + 'We have detected use of @everyone in one of our text channels. This function is in place to prevent discord scams and has resulted in an automatic timeout and notification of our moderation team. If this was done in error, our moderation team will reverse the timeout, however please refrain from using the @everyone ping in future.', + ); + } catch (e) { + log(e); + + const noDMEmbed = makeEmbed({ + author: { + name: msg.author.tag, + iconURL: msg.author.displayAvatarURL(), + }, + description: `DM was not sent to ${msg.author.id}.`, + }); + + await scamReportLogs.send({ embeds: [noDMEmbed] }); + } + + await scamReportLogs.send({ embeds: [notAllowedEmbed] }); + + // Add infraction to database + + Logger.info('Starting Infraction process'); + + const newInfraction = { + infractionType: 'ScamLog', + moderatorID: msg.client.user.id, + reason: `Message content: ${msg.content.toString()}`, + date: new Date(), + infractionID: new mongoose.Types.ObjectId(), + }; + + let userData = await Infraction.findOne({ UserID: msg.author.id }); + + log(userData); + + if (!userData) { + userData = new Infraction({ + userID: msg.author.id, + infractions: [newInfraction], + }); + Logger.info(userData); + Logger.info('New user data created'); + } else { + userData.infractions.push(newInfraction); + Logger.info('User data updated'); + } + + try { + await userData.save(); + Logger.info('Infraction process complete'); + } catch (error) { + await scamReportLogs.send({ embeds: [logFailed] }); + Logger.error(error); + } } + } }); diff --git a/src/events/ready.ts b/src/events/ready.ts index 7b7a54fa..b99cba82 100644 --- a/src/events/ready.ts +++ b/src/events/ready.ts @@ -6,137 +6,137 @@ import commandArray from '../commands'; import contextArray from '../commands/context'; export default event(Events.ClientReady, async ({ log }, client) => { - log(`Logged in as ${client.user.username}!`); + log(`Logged in as ${client.user.username}!`); - // Set username, activity, status and avatar - if (process.env.NODE_ENV === 'production') { - log('Production environment detected, setting username, activity, status and avatar.'); + // Set username, activity, status and avatar + if (process.env.NODE_ENV === 'production') { + log('Production environment detected, setting username, activity, status and avatar.'); - try { - client.user?.setUsername('FlyByWire Simulations Utilities'); - client.user?.setActivity('the A380X', { type: ActivityType.Watching }); - client.user?.setStatus('online'); - client.user?.setAvatar(`${imageBaseUrl}/fbw_tail.png`); - } catch (error) { - log('Failed to set username, activity, status and avatar:', error); - } + try { + client.user?.setUsername('FlyByWire Simulations Utilities'); + client.user?.setActivity('the A380X', { type: ActivityType.Watching }); + client.user?.setStatus('online'); + client.user?.setAvatar(`${imageBaseUrl}/fbw_tail.png`); + } catch (error) { + log('Failed to set username, activity, status and avatar:', error); } + } - // Deploy commands and contexts - if (process.env.DEPLOY === 'true') { - log('DEPLOY variable set to true, deploying commands and contexts.'); - try { - await deployCommands(commandArray, contextArray).then(async (user) => { - const bot = `<@${user.id}>`; + // Deploy commands and contexts + if (process.env.DEPLOY === 'true') { + log('DEPLOY variable set to true, deploying commands and contexts.'); + try { + await deployCommands(commandArray, contextArray).then(async (user) => { + const bot = `<@${user.id}>`; - const response = - process.env.NODE_ENV === 'production' - ? `Deployed ${commandArray.length} commands and ${contextArray.length} contexts globally as ${bot}!` - : `Deployed ${commandArray.length} commands and ${contextArray.length} contexts to \`<@${constantsConfig.guildId}>\` as ${bot}!`; + const response = + process.env.NODE_ENV === 'production' + ? `Deployed ${commandArray.length} commands and ${contextArray.length} contexts globally as ${bot}!` + : `Deployed ${commandArray.length} commands and ${contextArray.length} contexts to \`<@${constantsConfig.guildId}>\` as ${bot}!`; - log(response); - }); - } catch (error) { - log('Failed to deploy commands:', error); - } + log(response); + }); + } catch (error) { + log('Failed to deploy commands:', error); } + } - // Connect to MongoDB and set up scheduler - let dbConnected = false; - let dbError: Error | undefined; - let schedulerConnected = false; - let schedulerError: Error | undefined; + // Connect to MongoDB and set up scheduler + let dbConnected = false; + let dbError: Error | undefined; + let schedulerConnected = false; + let schedulerError: Error | undefined; - if (process.env.MONGODB_URL) { - await connect(process.env.MONGODB_URL) - .then(() => { - dbConnected = true; - }) - .catch((error) => { - dbError = error; - Logger.error(error); - }); - await setupScheduler('fbwBotScheduler', process.env.MONGODB_URL) - .then(() => { - schedulerConnected = true; - }) - .catch((error) => { - schedulerError = error; - Logger.error(error); - }); - } + if (process.env.MONGODB_URL) { + await connect(process.env.MONGODB_URL) + .then(() => { + dbConnected = true; + }) + .catch((error) => { + dbError = error; + Logger.error(error); + }); + await setupScheduler('fbwBotScheduler', process.env.MONGODB_URL) + .then(() => { + schedulerConnected = true; + }) + .catch((error) => { + schedulerError = error; + Logger.error(error); + }); + } - // Set heartbeat handler - if (schedulerConnected && process.env.HEARTBEAT_URL && process.env.HEARTBEAT_INTERVAL) { - const scheduler = getScheduler(); - if (scheduler) { - const heartbeatJobList = await scheduler.jobs({ name: 'sendHeartbeat' }); - if (heartbeatJobList.length === 0) { - scheduler.every(`${process.env.HEARTBEAT_INTERVAL} seconds`, 'sendHeartbeat', { - interval: process.env.HEARTBEAT_INTERVAL, - }); - Logger.info(`Heartbeat job scheduled with interval ${process.env.HEARTBEAT_INTERVAL}`); - } else { - const heartbeatJob = heartbeatJobList[0]; - const { interval } = heartbeatJob.attrs.data as { interval: string }; - if (interval !== process.env.HEARTBEAT_INTERVAL) { - await scheduler.cancel({ name: 'sendHeartbeat' }); - scheduler.every(`${process.env.HEARTBEAT_INTERVAL} seconds`, 'sendHeartbeat', { - interval: process.env.HEARTBEAT_INTERVAL, - }); - Logger.info(`Heartbeat job rescheduled with new interval ${process.env.HEARTBEAT_INTERVAL}`); - } else { - Logger.info('Heartbeat job already scheduled'); - } - } + // Set heartbeat handler + if (schedulerConnected && process.env.HEARTBEAT_URL && process.env.HEARTBEAT_INTERVAL) { + const scheduler = getScheduler(); + if (scheduler) { + const heartbeatJobList = await scheduler.jobs({ name: 'sendHeartbeat' }); + if (heartbeatJobList.length === 0) { + scheduler.every(`${process.env.HEARTBEAT_INTERVAL} seconds`, 'sendHeartbeat', { + interval: process.env.HEARTBEAT_INTERVAL, + }); + Logger.info(`Heartbeat job scheduled with interval ${process.env.HEARTBEAT_INTERVAL}`); + } else { + const heartbeatJob = heartbeatJobList[0]; + const { interval } = heartbeatJob.attrs.data as { interval: string }; + if (interval !== process.env.HEARTBEAT_INTERVAL) { + await scheduler.cancel({ name: 'sendHeartbeat' }); + scheduler.every(`${process.env.HEARTBEAT_INTERVAL} seconds`, 'sendHeartbeat', { + interval: process.env.HEARTBEAT_INTERVAL, + }); + Logger.info(`Heartbeat job rescheduled with new interval ${process.env.HEARTBEAT_INTERVAL}`); + } else { + Logger.info('Heartbeat job already scheduled'); } + } } + } - // Set birthday handler - if (schedulerConnected && process.env.BIRTHDAY_INTERVAL) { - const scheduler = getScheduler(); - if (scheduler) { - const birthdayJobList = await scheduler.jobs({ name: 'postBirthdays' }); - if (birthdayJobList.length === 0) { - scheduler.every(`${process.env.BIRTHDAY_INTERVAL} seconds`, 'postBirthdays', { - interval: process.env.BIRTHDAY_INTERVAL, - }); - Logger.info(`Birthday job scheduled with interval ${process.env.BIRTHDAY_INTERVAL}`); - } else { - const birthdayJob = birthdayJobList[0]; - const { interval } = birthdayJob.attrs.data as { interval: string }; - if (interval !== process.env.BIRTHDAY_INTERVAL) { - await scheduler.cancel({ name: 'postBirthdays' }); - scheduler.every(`${process.env.BIRTHDAY_INTERVAL} seconds`, 'postBirthdays', { - interval: process.env.BIRTHDAY_INTERVAL, - }); - Logger.info(`Birthday job rescheduled with new interval ${process.env.BIRTHDAY_INTERVAL}`); - } else { - Logger.info('Birthday job already scheduled'); - } - } + // Set birthday handler + if (schedulerConnected && process.env.BIRTHDAY_INTERVAL) { + const scheduler = getScheduler(); + if (scheduler) { + const birthdayJobList = await scheduler.jobs({ name: 'postBirthdays' }); + if (birthdayJobList.length === 0) { + scheduler.every(`${process.env.BIRTHDAY_INTERVAL} seconds`, 'postBirthdays', { + interval: process.env.BIRTHDAY_INTERVAL, + }); + Logger.info(`Birthday job scheduled with interval ${process.env.BIRTHDAY_INTERVAL}`); + } else { + const birthdayJob = birthdayJobList[0]; + const { interval } = birthdayJob.attrs.data as { interval: string }; + if (interval !== process.env.BIRTHDAY_INTERVAL) { + await scheduler.cancel({ name: 'postBirthdays' }); + scheduler.every(`${process.env.BIRTHDAY_INTERVAL} seconds`, 'postBirthdays', { + interval: process.env.BIRTHDAY_INTERVAL, + }); + Logger.info(`Birthday job rescheduled with new interval ${process.env.BIRTHDAY_INTERVAL}`); + } else { + Logger.info('Birthday job already scheduled'); } + } } + } - // Send bot status message to bot-dev channel - const botDevChannel = client.channels.resolve(constantsConfig.channels.MOD_LOGS) as TextChannel; - if (botDevChannel) { - const currentDate = new Date(); - const formattedDate = moment(currentDate).utcOffset(0).format(); - - // Include the database connection and scheduler status in the mod logs message. - let logMessage = `<@&${constantsConfig.roles.BOT_DEVELOPER}>\n[${formattedDate}] - ${client.user?.username} has connected! - DB State: ${dbConnected ? 'Connected' : 'Disconnected'}`; - if (!dbConnected && dbError) { - logMessage += ` - DB Error: ${dbError.message}`; - } + // Send bot status message to bot-dev channel + const botDevChannel = client.channels.resolve(constantsConfig.channels.MOD_LOGS) as TextChannel; + if (botDevChannel) { + const currentDate = new Date(); + const formattedDate = moment(currentDate).utcOffset(0).format(); - logMessage += ` - Scheduler State: ${schedulerConnected ? 'Connected' : 'Disconnected'}`; - if (!schedulerConnected && schedulerError) { - logMessage += ` - Scheduler Error: ${schedulerError.message}`; - } + // Include the database connection and scheduler status in the mod logs message. + let logMessage = `<@&${constantsConfig.roles.BOT_DEVELOPER}>\n[${formattedDate}] - ${client.user?.username} has connected! - DB State: ${dbConnected ? 'Connected' : 'Disconnected'}`; + if (!dbConnected && dbError) { + logMessage += ` - DB Error: ${dbError.message}`; + } - await botDevChannel.send({ content: logMessage }); - } else { - log('Unable to find bot-dev channel. Cannot send bot status message.'); + logMessage += ` - Scheduler State: ${schedulerConnected ? 'Connected' : 'Disconnected'}`; + if (!schedulerConnected && schedulerError) { + logMessage += ` - Scheduler Error: ${schedulerError.message}`; } + + await botDevChannel.send({ content: logMessage }); + } else { + log('Unable to find bot-dev channel. Cannot send bot status message.'); + } }); diff --git a/src/events/slashCommandHandler.ts b/src/events/slashCommandHandler.ts index 84f2b2a1..cce29f0f 100644 --- a/src/events/slashCommandHandler.ts +++ b/src/events/slashCommandHandler.ts @@ -6,68 +6,68 @@ import commandArray from '../commands'; const commandMap = new Map(); for (const cmd of commandArray) { - commandMap.set(cmd.meta.name, cmd); + commandMap.set(cmd.meta.name, cmd); } export default event(Events.InteractionCreate, async ({ log, client }, interaction) => { - if (!interaction.isChatInputCommand()) { - return; + if (!interaction.isChatInputCommand()) { + return; + } + + if (!interaction.inCachedGuild()) { + await interaction.reply(Reply('This bot can only be used in a server!', Color.Error)); + return; + } + + try { + const { commandName, options } = interaction as { + commandName: any; + options: any; + }; + + const command = commandMap.get(commandName); + + if (!command) { + log(`Could not resolve the command with name "${commandName}"`); + return; } - if (!interaction.inCachedGuild()) { - await interaction.reply(Reply('This bot can only be used in a server!', Color.Error)); - return; - } - - try { - const { commandName, options } = interaction as { - commandName: any; - options: any; - }; - - const command = commandMap.get(commandName); - - if (!command) { - log(`Could not resolve the command with name "${commandName}"`); - return; - } - - let logMessage = `[Command]: ${commandName}`; - - if (options) { - if (options._group) { - logMessage += `, Subcommand Group: ${options._group}`; - } - if (options._subcommand) { - logMessage += `, Subcommand: ${options._subcommand}`; - } - if (options._hoistedOptions) { - for (const subcommandOption of options._hoistedOptions) { - if (subcommandOption.type === 1) { - logMessage += `, ${subcommandOption.name}`; - } - } - } + let logMessage = `[Command]: ${commandName}`; + + if (options) { + if (options._group) { + logMessage += `, Subcommand Group: ${options._group}`; + } + if (options._subcommand) { + logMessage += `, Subcommand: ${options._subcommand}`; + } + if (options._hoistedOptions) { + for (const subcommandOption of options._hoistedOptions) { + if (subcommandOption.type === 1) { + logMessage += `, ${subcommandOption.name}`; + } } + } + } - logMessage += ` was executed by ${interaction.user.tag}`; + logMessage += ` was executed by ${interaction.user.tag}`; - log(logMessage); + log(logMessage); - await command.callback({ client, log, interaction }); - } catch (error) { - const errorEmbed = makeEmbed({ - title: 'An error occurred while executing this command.', - description: `${error}`, - color: Color.Error, - }); + await command.callback({ client, log, interaction }); + } catch (error) { + const errorEmbed = makeEmbed({ + title: 'An error occurred while executing this command.', + description: `${error}`, + color: Color.Error, + }); - log('[Command Error]', error); + log('[Command Error]', error); - await interaction.followUp({ embeds: [errorEmbed] }); + await interaction.followUp({ embeds: [errorEmbed] }); - if (interaction.deferred || interaction.replied) { - log('Interaction was already replied to or deferred, ignoring'); - } + if (interaction.deferred || interaction.replied) { + log('Interaction was already replied to or deferred, ignoring'); } + } }); diff --git a/src/lib/autocomplete.ts b/src/lib/autocomplete.ts index 0ce99d84..f4d56015 100644 --- a/src/lib/autocomplete.ts +++ b/src/lib/autocomplete.ts @@ -3,9 +3,9 @@ import { LogMethods } from './index'; /// Props that will be passed through the autocomplete callback. export interface AutocompleteProps { - interaction: AutocompleteInteraction<'cached'>; - client: Client; - log: LogMethods; + interaction: AutocompleteInteraction<'cached'>; + client: Client; + log: LogMethods; } export type AutocompleteCallback = (props: AutocompleteProps) => Awaitable; diff --git a/src/lib/config.ts b/src/lib/config.ts index 8fb45900..51a7ba52 100644 --- a/src/lib/config.ts +++ b/src/lib/config.ts @@ -8,8 +8,8 @@ const imageBaseUrl = originalBaseUrl.endsWith('/') ? originalBaseUrl.slice(0, -1 export { imageBaseUrl }; interface roleAssignmentId { - group: string; - roles: { id: string; label: string }[]; + group: string; + roles: { id: string; label: string }[]; } // Config constants that are directly used in code should be mandatory, @@ -18,103 +18,103 @@ interface roleAssignmentId { // Constants that are only part of role groups or role assignment IDs are // not mandatory, as they can be dynamic. interface Config { - aircraftTypeList: { - [x: string]: string; - }; - channels: { - A32NX_SUPPORT: string; - FAQ: string; - FLIGHT_SCHOOL: string; - KNOWN_ISSUES: string; - MOD_ALERTS: string; - MOD_LOGS: string; - ROLES: string; - SCAM_REPORT_LOGS: string; - TEAM: string; - USER_LOGS: string; - VIDEOS: string; - [x: string]: string; - }; - colors: { - FBW_CYAN: string; - [x: string]: string; - }; - commandPermission: { - MANAGE_SERVER: string; - [x: string]: string; - }; - guildId: string; - modLogExclude: string[]; - roleAssignmentIds: roleAssignmentId[]; - roleGroups: { - [x: string]: string[]; - }; - roles: { - ADMIN_TEAM: string; - BOT_DEVELOPER: string; - COMMUNITY_SUPPORT: string; - DEVELOPMENT_TEAM: string; - FBW_EMERITUS: string; - MEDIA_TEAM: string; - MODERATION_TEAM: string; - [x: string]: string; - }; - threads: { - BIRTHDAY_THREAD: string; - COUNT_THREAD: string; - [x: string]: string; - }; - units: { - CELSIUS: string; - DEGREES: string; - [x: string]: string; - }; - userLogExclude: string[]; + aircraftTypeList: { + [x: string]: string; + }; + channels: { + A32NX_SUPPORT: string; + FAQ: string; + FLIGHT_SCHOOL: string; + KNOWN_ISSUES: string; + MOD_ALERTS: string; + MOD_LOGS: string; + ROLES: string; + SCAM_REPORT_LOGS: string; + TEAM: string; + USER_LOGS: string; + VIDEOS: string; + [x: string]: string; + }; + colors: { + FBW_CYAN: string; + [x: string]: string; + }; + commandPermission: { + MANAGE_SERVER: string; + [x: string]: string; + }; + guildId: string; + modLogExclude: string[]; + roleAssignmentIds: roleAssignmentId[]; + roleGroups: { + [x: string]: string[]; + }; + roles: { + ADMIN_TEAM: string; + BOT_DEVELOPER: string; + COMMUNITY_SUPPORT: string; + DEVELOPMENT_TEAM: string; + FBW_EMERITUS: string; + MEDIA_TEAM: string; + MODERATION_TEAM: string; + [x: string]: string; + }; + threads: { + BIRTHDAY_THREAD: string; + COUNT_THREAD: string; + [x: string]: string; + }; + units: { + CELSIUS: string; + DEGREES: string; + [x: string]: string; + }; + userLogExclude: string[]; } let parsedConfig: Config; try { - parsedConfig = botConfig as unknown as Config; - if (!parsedConfig.commandPermission.MANAGE_SERVER) { - // Making sure this is always set, even if an empty string is given - parsedConfig.commandPermission.MANAGE_SERVER = '32'; - } - const { roles, roleGroups, roleAssignmentIds } = parsedConfig; - // Parsing Role groups - const newRoleGroups: { [x: string]: string[] } = {}; - for (const group in roleGroups) { - if (Object.prototype.hasOwnProperty.call(roleGroups, group)) { - const groupRoles = roleGroups[group]; - const groupRoleIds = []; - for (let index = 0; index < groupRoles.length; index++) { - const groupRole = groupRoles[index]; - if (groupRole in roles) { - groupRoleIds.push(roles[groupRole]); - } - } - newRoleGroups[group] = groupRoleIds; + parsedConfig = botConfig as unknown as Config; + if (!parsedConfig.commandPermission.MANAGE_SERVER) { + // Making sure this is always set, even if an empty string is given + parsedConfig.commandPermission.MANAGE_SERVER = '32'; + } + const { roles, roleGroups, roleAssignmentIds } = parsedConfig; + // Parsing Role groups + const newRoleGroups: { [x: string]: string[] } = {}; + for (const group in roleGroups) { + if (Object.prototype.hasOwnProperty.call(roleGroups, group)) { + const groupRoles = roleGroups[group]; + const groupRoleIds = []; + for (let index = 0; index < groupRoles.length; index++) { + const groupRole = groupRoles[index]; + if (groupRole in roles) { + groupRoleIds.push(roles[groupRole]); } + } + newRoleGroups[group] = groupRoleIds; } - parsedConfig.roleGroups = newRoleGroups; - // Parsing Role assignment IDs - const newRoleAssignmentIds: roleAssignmentId[] = []; - for (let i = 0; i < roleAssignmentIds.length; i++) { - const roleAssignmentId = roleAssignmentIds[i]; - const { group, roles: roleAssignmentIdRoles } = roleAssignmentId; - const newRoleAssignmentIdRoles = []; - for (let j = 0; j < roleAssignmentIdRoles.length; j++) { - const roleAssignmentIdRole = roleAssignmentIdRoles[j]; - const { id, label } = roleAssignmentIdRole; - if (id in roles) { - newRoleAssignmentIdRoles.push({ id: roles[id], label }); - } - } - newRoleAssignmentIds.push({ group, roles: newRoleAssignmentIdRoles }); + } + parsedConfig.roleGroups = newRoleGroups; + // Parsing Role assignment IDs + const newRoleAssignmentIds: roleAssignmentId[] = []; + for (let i = 0; i < roleAssignmentIds.length; i++) { + const roleAssignmentId = roleAssignmentIds[i]; + const { group, roles: roleAssignmentIdRoles } = roleAssignmentId; + const newRoleAssignmentIdRoles = []; + for (let j = 0; j < roleAssignmentIdRoles.length; j++) { + const roleAssignmentIdRole = roleAssignmentIdRoles[j]; + const { id, label } = roleAssignmentIdRole; + if (id in roles) { + newRoleAssignmentIdRoles.push({ id: roles[id], label }); + } } - parsedConfig.roleAssignmentIds = newRoleAssignmentIds; + newRoleAssignmentIds.push({ group, roles: newRoleAssignmentIdRoles }); + } + parsedConfig.roleAssignmentIds = newRoleAssignmentIds; } catch (e) { - Logger.error(`Failed to load config: ${e}`); - exit(1); + Logger.error(`Failed to load config: ${e}`); + exit(1); } const constantsConfig = parsedConfig; diff --git a/src/lib/contextMenuCommand.ts b/src/lib/contextMenuCommand.ts index 6b1856bb..f3bf413b 100644 --- a/src/lib/contextMenuCommand.ts +++ b/src/lib/contextMenuCommand.ts @@ -1,16 +1,16 @@ import { - Awaitable, - Client, - ContextMenuCommandBuilder, - RESTPostAPIApplicationCommandsJSONBody, - ContextMenuCommandInteraction, + Awaitable, + Client, + ContextMenuCommandBuilder, + RESTPostAPIApplicationCommandsJSONBody, + ContextMenuCommandInteraction, } from 'discord.js'; import { LogMethods } from './index'; export interface ContextMenuCommandProps { - interaction: ContextMenuCommandInteraction<'cached'>; - client: Client; - log: LogMethods; + interaction: ContextMenuCommandInteraction<'cached'>; + client: Client; + log: LogMethods; } export type ContextMenuCommandCallback = (props: ContextMenuCommandProps) => Awaitable; @@ -18,17 +18,17 @@ export type ContextMenuCommandCallback = (props: ContextMenuCommandProps) => Awa export type ContextMenuCommandStructure = ContextMenuCommandBuilder | RESTPostAPIApplicationCommandsJSONBody; export interface ContextMenuCommand { - meta: ContextMenuCommandStructure; - callback: ContextMenuCommandCallback; + meta: ContextMenuCommandStructure; + callback: ContextMenuCommandCallback; } export function contextMenuCommandStructure(data: RESTPostAPIApplicationCommandsJSONBody): ContextMenuCommandStructure { - return data; + return data; } export function contextMenuCommand( - meta: ContextMenuCommandStructure, - callback: ContextMenuCommandCallback, + meta: ContextMenuCommandStructure, + callback: ContextMenuCommandCallback, ): ContextMenuCommand { - return { meta, callback }; + return { meta, callback }; } diff --git a/src/lib/db.ts b/src/lib/db.ts index 4f985bcd..ee8b35c5 100644 --- a/src/lib/db.ts +++ b/src/lib/db.ts @@ -4,35 +4,35 @@ import { Logger } from './index'; let connection: mongoose.Connection; export async function connect(url: string, callback = Logger.error) { - try { - await mongoose.connect(url); - connection = mongoose.connection; + try { + await mongoose.connect(url); + connection = mongoose.connection; - Logger.info('Connected to database'); - } catch (err) { - callback(err); - } + Logger.info('Connected to database'); + } catch (err) { + callback(err); + } - mongoose.connection.on('error', (err) => { - callback(err); - }); + mongoose.connection.on('error', (err) => { + callback(err); + }); } export function getConn(callback = Logger.error) { - if (!connection || connection.readyState !== mongoose.ConnectionStates.connected) { - callback(new Error('Not connected to database')); - } else { - return connection; - } + if (!connection || connection.readyState !== mongoose.ConnectionStates.connected) { + callback(new Error('Not connected to database')); + } else { + return connection; + } - return null; + return null; } export async function closeMongooseConnection() { - try { - await mongoose.disconnect(); - Logger.info('Mongoose connection closed.'); - } catch (error) { - Logger.error('Error closing Mongoose connection:', error); - } + try { + await mongoose.disconnect(); + Logger.info('Mongoose connection closed.'); + } catch (error) { + Logger.error('Error closing Mongoose connection:', error); + } } diff --git a/src/lib/durationInEnglish.ts b/src/lib/durationInEnglish.ts index fcade0af..ef29981a 100644 --- a/src/lib/durationInEnglish.ts +++ b/src/lib/durationInEnglish.ts @@ -1,17 +1,17 @@ export function durationInEnglish(milliseconds: any) { - const seconds = milliseconds / 1000; + const seconds = milliseconds / 1000; - if (seconds < 60) { - return `${Math.floor(seconds)} second${Math.floor(seconds) === 1 ? '' : 's'}`; - } - if (seconds < 3600) { - const minutes = seconds / 60; - return `${Math.floor(minutes)} minute${Math.floor(minutes) === 1 ? '' : 's'}`; - } - if (seconds < 86400) { - const hours = seconds / 3600; - return `${Math.floor(hours)} hour${Math.floor(hours) === 1 ? '' : 's'}`; - } - const days = seconds / 86400; - return `${Math.floor(days)} day${Math.floor(days) === 1 ? '' : 's'}`; + if (seconds < 60) { + return `${Math.floor(seconds)} second${Math.floor(seconds) === 1 ? '' : 's'}`; + } + if (seconds < 3600) { + const minutes = seconds / 60; + return `${Math.floor(minutes)} minute${Math.floor(minutes) === 1 ? '' : 's'}`; + } + if (seconds < 86400) { + const hours = seconds / 3600; + return `${Math.floor(hours)} hour${Math.floor(hours) === 1 ? '' : 's'}`; + } + const days = seconds / 86400; + return `${Math.floor(days)} day${Math.floor(days) === 1 ? '' : 's'}`; } diff --git a/src/lib/embed.ts b/src/lib/embed.ts index e1d17a9d..f158a18a 100644 --- a/src/lib/embed.ts +++ b/src/lib/embed.ts @@ -4,23 +4,23 @@ import { constantsConfig } from './index'; type ListTypes = 'bullet' | 'ordered'; export function makeEmbed(embed: EmbedData): EmbedBuilder { - return new EmbedBuilder({ - color: Number(constantsConfig.colors.FBW_CYAN), - ...embed, - }); + return new EmbedBuilder({ + color: Number(constantsConfig.colors.FBW_CYAN), + ...embed, + }); } export function makeLines(lines: string[]): string { - return lines.join('\n'); + return lines.join('\n'); } export const makeList = (lines: string[], type?: ListTypes): string => { - switch (type) { - case 'bullet': - return lines.map((line) => `• ${line}`).join('\n'); - case 'ordered': - return lines.map((line, index) => `${index + 1}. ${line}`).join('\n'); - default: - return lines.map((line) => `- ${line}`).join('\n'); - } + switch (type) { + case 'bullet': + return lines.map((line) => `• ${line}`).join('\n'); + case 'ordered': + return lines.map((line, index) => `${index + 1}. ${line}`).join('\n'); + default: + return lines.map((line) => `- ${line}`).join('\n'); + } }; diff --git a/src/lib/events.ts b/src/lib/events.ts index 2cb44ce4..f9143c2d 100644 --- a/src/lib/events.ts +++ b/src/lib/events.ts @@ -7,32 +7,32 @@ export type LogMethods = (...args: unknown[]) => void; export type EventKeys = keyof ClientEvents; export interface EventProps { - client: Client; - log: LogMethods; + client: Client; + log: LogMethods; } export type EventCallback = (props: EventProps, ...args: ClientEvents[T]) => Awaitable; export interface Event { - key: T; - callback: EventCallback; + key: T; + callback: EventCallback; } export function event(key: T, callback: EventCallback): Event { - return { key, callback }; + return { key, callback }; } export function registerEvents(client: Client, events: Event[]): void { - for (const { key, callback } of events) { - client.on(key, (...args) => { - // eslint-disable-next-line no-console - const log = console.log.bind(Logger, `[Event: ${key}]`); - - try { - callback({ client, log }, ...args); - } catch (e) { - log('[Uncaught Error]', e); - } - }); - } + for (const { key, callback } of events) { + client.on(key, (...args) => { + // eslint-disable-next-line no-console + const log = console.log.bind(Logger, `[Event: ${key}]`); + + try { + callback({ client, log }, ...args); + } catch (e) { + log('[Uncaught Error]', e); + } + }); + } } diff --git a/src/lib/genericEmbedPagination.ts b/src/lib/genericEmbedPagination.ts index e3422c6d..6758ad29 100644 --- a/src/lib/genericEmbedPagination.ts +++ b/src/lib/genericEmbedPagination.ts @@ -1,86 +1,86 @@ import { - ActionRowBuilder, - ButtonBuilder, - ButtonInteraction, - ButtonStyle, - CommandInteraction, - ComponentType, - EmbedBuilder, - Interaction, - InteractionResponse, - Message, + ActionRowBuilder, + ButtonBuilder, + ButtonInteraction, + ButtonStyle, + CommandInteraction, + ComponentType, + EmbedBuilder, + Interaction, + InteractionResponse, + Message, } from 'discord.js'; export async function createPaginatedEmbedHandler( - initialInteraction: CommandInteraction, - embeds: EmbedBuilder[], + initialInteraction: CommandInteraction, + embeds: EmbedBuilder[], ): Promise { - let currentPage = 0; + let currentPage = 0; - const nextButton = new ButtonBuilder() - .setCustomId('pagination_nextPage') - .setLabel('Next') - .setStyle(ButtonStyle.Primary); + const nextButton = new ButtonBuilder() + .setCustomId('pagination_nextPage') + .setLabel('Next') + .setStyle(ButtonStyle.Primary); - const prevButton = new ButtonBuilder() - .setCustomId('pagination_prevPage') - .setLabel('Previous') - .setStyle(ButtonStyle.Primary); + const prevButton = new ButtonBuilder() + .setCustomId('pagination_prevPage') + .setLabel('Previous') + .setStyle(ButtonStyle.Primary); - setButtonDisabledStates(); + setButtonDisabledStates(); - const buttonRow = new ActionRowBuilder().addComponents(prevButton, nextButton); + const buttonRow = new ActionRowBuilder().addComponents(prevButton, nextButton); - let message: Message | InteractionResponse; - if (initialInteraction.deferred || initialInteraction.replied) { - message = await initialInteraction.editReply({ embeds: [embeds[currentPage]], components: [buttonRow] }); - } else { - message = await initialInteraction.reply({ embeds: [embeds[currentPage]], components: [buttonRow] }); - } + let message: Message | InteractionResponse; + if (initialInteraction.deferred || initialInteraction.replied) { + message = await initialInteraction.editReply({ embeds: [embeds[currentPage]], components: [buttonRow] }); + } else { + message = await initialInteraction.reply({ embeds: [embeds[currentPage]], components: [buttonRow] }); + } - const filter = (buttonInteraction: Interaction) => initialInteraction.user.id === buttonInteraction.user.id; - const collector = message.createMessageComponentCollector({ - filter, - componentType: ComponentType.Button, - time: 120_000, - }); + const filter = (buttonInteraction: Interaction) => initialInteraction.user.id === buttonInteraction.user.id; + const collector = message.createMessageComponentCollector({ + filter, + componentType: ComponentType.Button, + time: 120_000, + }); - collector.on('collect', async (collectedInteraction: ButtonInteraction) => { - await collectedInteraction.deferUpdate(); + collector.on('collect', async (collectedInteraction: ButtonInteraction) => { + await collectedInteraction.deferUpdate(); - if (collectedInteraction.customId === 'pagination_nextPage') { - currentPage++; - } else if (collectedInteraction.customId === 'pagination_prevPage') { - currentPage--; - } + if (collectedInteraction.customId === 'pagination_nextPage') { + currentPage++; + } else if (collectedInteraction.customId === 'pagination_prevPage') { + currentPage--; + } - setButtonDisabledStates(); + setButtonDisabledStates(); - updateEmbed(); - }); + updateEmbed(); + }); - collector.on('end', async () => { - handleEmbedExpire(); - }); + collector.on('end', async () => { + handleEmbedExpire(); + }); - function updateEmbed() { - initialInteraction.editReply({ embeds: [embeds[currentPage]], components: [buttonRow] }); - } + function updateEmbed() { + initialInteraction.editReply({ embeds: [embeds[currentPage]], components: [buttonRow] }); + } - function handleEmbedExpire() { - const embed = embeds[currentPage]; - initialInteraction.editReply({ - embeds: [ - embed.setFooter({ - text: `${embed.data.footer ? `${embed.data.footer.text} - ` : ''}This embed has expired.`, - }), - ], - components: [], - }); - } + function handleEmbedExpire() { + const embed = embeds[currentPage]; + initialInteraction.editReply({ + embeds: [ + embed.setFooter({ + text: `${embed.data.footer ? `${embed.data.footer.text} - ` : ''}This embed has expired.`, + }), + ], + components: [], + }); + } - function setButtonDisabledStates() { - prevButton.setDisabled(currentPage <= 0); - nextButton.setDisabled(currentPage >= embeds.length - 1); - } + function setButtonDisabledStates() { + prevButton.setDisabled(currentPage <= 0); + nextButton.setDisabled(currentPage >= embeds.length - 1); + } } diff --git a/src/lib/infractionEmbedPagination.ts b/src/lib/infractionEmbedPagination.ts index 3c268884..59d974f1 100644 --- a/src/lib/infractionEmbedPagination.ts +++ b/src/lib/infractionEmbedPagination.ts @@ -1,125 +1,125 @@ import { - ActionRowBuilder, - ButtonBuilder, - ButtonStyle, - Interaction, - CommandInteraction, - ButtonInteraction, - EmbedBuilder, + ActionRowBuilder, + ButtonBuilder, + ButtonStyle, + Interaction, + CommandInteraction, + ButtonInteraction, + EmbedBuilder, } from 'discord.js'; export async function createPaginatedInfractionEmbedHandler( - initialInteraction: CommandInteraction, - user: string, - embeds: EmbedBuilder[], - infractionsLengths: { - warnsLength: string; - timeoutsLength: string; - scamLogsLength: string; - bansLength: string; - unbansLength: string; - notesLength: string; - }, + initialInteraction: CommandInteraction, + user: string, + embeds: EmbedBuilder[], + infractionsLengths: { + warnsLength: string; + timeoutsLength: string; + scamLogsLength: string; + bansLength: string; + unbansLength: string; + notesLength: string; + }, ): Promise { - let currentPage = 0; - - const aboutButton = new ButtonBuilder() - .setCustomId('infractions_about') - .setLabel('About') - .setStyle(ButtonStyle.Success); - - const warnButton = new ButtonBuilder() - .setCustomId('infractions_warns') - .setLabel(`Warns (${infractionsLengths.warnsLength})`) - .setStyle(ButtonStyle.Primary); - - const timeoutButton = new ButtonBuilder() - .setCustomId('infractions_timeouts') - .setLabel(`Timeouts (${infractionsLengths.timeoutsLength})`) - .setStyle(ButtonStyle.Primary); - - const scamLogButton = new ButtonBuilder() - .setCustomId('infractions_scamlog') - .setLabel(`Scam Logs (${infractionsLengths.scamLogsLength})`) - .setStyle(ButtonStyle.Primary); - - const banButton = new ButtonBuilder() - .setCustomId('infractions_bans') - .setLabel(`Bans (${infractionsLengths.bansLength})`) - .setStyle(ButtonStyle.Primary); - - const unbanButton = new ButtonBuilder() - .setCustomId('infractions_unbans') - .setLabel(`Unbans (${infractionsLengths.unbansLength})`) - .setStyle(ButtonStyle.Primary); - - const noteButton = new ButtonBuilder() - .setCustomId('infractions_notes') - .setLabel(`Notes (${infractionsLengths.notesLength})`) - .setStyle(ButtonStyle.Primary); - - const buttonRow1 = new ActionRowBuilder().addComponents(aboutButton, warnButton, timeoutButton); - const buttonRow2 = new ActionRowBuilder().addComponents( - scamLogButton, - banButton, - unbanButton, - noteButton, - ); - const message = await initialInteraction.followUp({ - embeds: [embeds[currentPage]], - components: [buttonRow1, buttonRow2], - }); - - const filter = (interaction: Interaction) => interaction.user.id === user; - const collector = message.createMessageComponentCollector({ filter, time: 120_000 }); - - collector.on('collect', async (collectedInteraction: ButtonInteraction) => { - await collectedInteraction.deferUpdate(); - - if (collectedInteraction.customId === 'infractions_about') { - currentPage = 0; - } else if (collectedInteraction.customId === 'infractions_warns') { - currentPage = 1; - } else if (collectedInteraction.customId === 'infractions_timeouts') { - currentPage = 2; - } else if (collectedInteraction.customId === 'infractions_scamlog') { - currentPage = 3; - } else if (collectedInteraction.customId === 'infractions_bans') { - currentPage = 4; - } else if (collectedInteraction.customId === 'infractions_unbans') { - currentPage = 5; - } else if (collectedInteraction.customId === 'infractions_notes') { - currentPage = 6; - } - - updateEmbed(); - }); - - collector.on('end', async () => { - handleEmbedExpire(); - }); - - function updateEmbed() { - aboutButton.setStyle(currentPage === 0 ? ButtonStyle.Success : ButtonStyle.Primary); - warnButton.setStyle(currentPage === 1 ? ButtonStyle.Success : ButtonStyle.Primary); - timeoutButton.setStyle(currentPage === 2 ? ButtonStyle.Success : ButtonStyle.Primary); - scamLogButton.setStyle(currentPage === 3 ? ButtonStyle.Success : ButtonStyle.Primary); - banButton.setStyle(currentPage === 4 ? ButtonStyle.Success : ButtonStyle.Primary); - unbanButton.setStyle(currentPage === 5 ? ButtonStyle.Success : ButtonStyle.Primary); - noteButton.setStyle(currentPage === 6 ? ButtonStyle.Success : ButtonStyle.Primary); - - initialInteraction.editReply({ embeds: [embeds[currentPage]], components: [buttonRow1, buttonRow2] }); + let currentPage = 0; + + const aboutButton = new ButtonBuilder() + .setCustomId('infractions_about') + .setLabel('About') + .setStyle(ButtonStyle.Success); + + const warnButton = new ButtonBuilder() + .setCustomId('infractions_warns') + .setLabel(`Warns (${infractionsLengths.warnsLength})`) + .setStyle(ButtonStyle.Primary); + + const timeoutButton = new ButtonBuilder() + .setCustomId('infractions_timeouts') + .setLabel(`Timeouts (${infractionsLengths.timeoutsLength})`) + .setStyle(ButtonStyle.Primary); + + const scamLogButton = new ButtonBuilder() + .setCustomId('infractions_scamlog') + .setLabel(`Scam Logs (${infractionsLengths.scamLogsLength})`) + .setStyle(ButtonStyle.Primary); + + const banButton = new ButtonBuilder() + .setCustomId('infractions_bans') + .setLabel(`Bans (${infractionsLengths.bansLength})`) + .setStyle(ButtonStyle.Primary); + + const unbanButton = new ButtonBuilder() + .setCustomId('infractions_unbans') + .setLabel(`Unbans (${infractionsLengths.unbansLength})`) + .setStyle(ButtonStyle.Primary); + + const noteButton = new ButtonBuilder() + .setCustomId('infractions_notes') + .setLabel(`Notes (${infractionsLengths.notesLength})`) + .setStyle(ButtonStyle.Primary); + + const buttonRow1 = new ActionRowBuilder().addComponents(aboutButton, warnButton, timeoutButton); + const buttonRow2 = new ActionRowBuilder().addComponents( + scamLogButton, + banButton, + unbanButton, + noteButton, + ); + const message = await initialInteraction.followUp({ + embeds: [embeds[currentPage]], + components: [buttonRow1, buttonRow2], + }); + + const filter = (interaction: Interaction) => interaction.user.id === user; + const collector = message.createMessageComponentCollector({ filter, time: 120_000 }); + + collector.on('collect', async (collectedInteraction: ButtonInteraction) => { + await collectedInteraction.deferUpdate(); + + if (collectedInteraction.customId === 'infractions_about') { + currentPage = 0; + } else if (collectedInteraction.customId === 'infractions_warns') { + currentPage = 1; + } else if (collectedInteraction.customId === 'infractions_timeouts') { + currentPage = 2; + } else if (collectedInteraction.customId === 'infractions_scamlog') { + currentPage = 3; + } else if (collectedInteraction.customId === 'infractions_bans') { + currentPage = 4; + } else if (collectedInteraction.customId === 'infractions_unbans') { + currentPage = 5; + } else if (collectedInteraction.customId === 'infractions_notes') { + currentPage = 6; } - function handleEmbedExpire() { - const embed = embeds[currentPage]; - initialInteraction.editReply({ - embeds: [ - embed.setFooter({ - text: `${embed.data.footer ? `${embed.data.footer.text} - ` : ''}This embed has expired.`, - }), - ], - components: [], - }); - } + updateEmbed(); + }); + + collector.on('end', async () => { + handleEmbedExpire(); + }); + + function updateEmbed() { + aboutButton.setStyle(currentPage === 0 ? ButtonStyle.Success : ButtonStyle.Primary); + warnButton.setStyle(currentPage === 1 ? ButtonStyle.Success : ButtonStyle.Primary); + timeoutButton.setStyle(currentPage === 2 ? ButtonStyle.Success : ButtonStyle.Primary); + scamLogButton.setStyle(currentPage === 3 ? ButtonStyle.Success : ButtonStyle.Primary); + banButton.setStyle(currentPage === 4 ? ButtonStyle.Success : ButtonStyle.Primary); + unbanButton.setStyle(currentPage === 5 ? ButtonStyle.Success : ButtonStyle.Primary); + noteButton.setStyle(currentPage === 6 ? ButtonStyle.Success : ButtonStyle.Primary); + + initialInteraction.editReply({ embeds: [embeds[currentPage]], components: [buttonRow1, buttonRow2] }); + } + + function handleEmbedExpire() { + const embed = embeds[currentPage]; + initialInteraction.editReply({ + embeds: [ + embed.setFooter({ + text: `${embed.data.footer ? `${embed.data.footer.text} - ` : ''}This embed has expired.`, + }), + ], + components: [], + }); + } } diff --git a/src/lib/logger.ts b/src/lib/logger.ts index c8237154..2c238a5d 100644 --- a/src/lib/logger.ts +++ b/src/lib/logger.ts @@ -1,23 +1,23 @@ import winston from 'winston'; const level = () => { - if (process.env.DEBUG_MODE === 'true') { - return 'debug'; - } + if (process.env.DEBUG_MODE === 'true') { + return 'debug'; + } - const env = process.env.NODE_ENV || 'development'; - const isDevelopment = env === 'development'; - return isDevelopment ? 'debug' : 'info'; + const env = process.env.NODE_ENV || 'development'; + const isDevelopment = env === 'development'; + return isDevelopment ? 'debug' : 'info'; }; const format = () => { - const env = process.env.NODE_ENV || 'development'; - const isDevelopment = env === 'development'; - return isDevelopment ? winston.format.simple() : winston.format.json(); + const env = process.env.NODE_ENV || 'development'; + const isDevelopment = env === 'development'; + return isDevelopment ? winston.format.simple() : winston.format.json(); }; export const Logger = winston.createLogger({ - level: level(), - format: format(), - transports: [new winston.transports.Console()], + level: level(), + format: format(), + transports: [new winston.transports.Console()], }); diff --git a/src/lib/replies.ts b/src/lib/replies.ts index e25d588f..7ff9efde 100644 --- a/src/lib/replies.ts +++ b/src/lib/replies.ts @@ -4,24 +4,24 @@ import { InteractionReplyOptions, InteractionEditReplyOptions } from 'discord.js'; export enum Color { - Error = 0xf54242, - Success = 0x42f551, - Info = 0x4296f5, + Error = 0xf54242, + Success = 0x42f551, + Info = 0x4296f5, } export const EditReply = (msg: string, color: Color = Color.Info): InteractionEditReplyOptions => ({ - content: undefined, - embeds: [ - { - description: msg, - color, - }, - ], - components: [], - files: [], + content: undefined, + embeds: [ + { + description: msg, + color, + }, + ], + components: [], + files: [], }); export const Reply = (msg: string, color: Color = Color.Info): InteractionReplyOptions => ({ - ephemeral: true, - ...(EditReply(msg, color) as InteractionReplyOptions), + ephemeral: true, + ...(EditReply(msg, color) as InteractionReplyOptions), }); diff --git a/src/lib/scheduler.ts b/src/lib/scheduler.ts index 95c674fc..571987cc 100644 --- a/src/lib/scheduler.ts +++ b/src/lib/scheduler.ts @@ -4,34 +4,34 @@ import { Logger, autoDisableSlowMode, sendHeartbeat, postBirthdays } from './ind let scheduler: Agenda; export async function setupScheduler(name: string, url: string, callback = Logger.error) { - try { - scheduler = new Agenda({ - name, - processEvery: '30 seconds', - defaultLockLifetime: 30000, // In milliseconds, this makes sure that if the bot restarts with locked jobs, they get released quickly and tried again. - db: { - address: url, - collection: `${name}Jobs`, - }, - }); - await scheduler.start(); - scheduler.define('autoDisableSlowMode', autoDisableSlowMode); - scheduler.define('sendHeartbeat', sendHeartbeat); - scheduler.define('postBirthdays', postBirthdays); - Logger.info('Scheduler set up'); - } catch (err) { - callback(err); - } - - scheduler.on('error', (err) => { - callback(err); + try { + scheduler = new Agenda({ + name, + processEvery: '30 seconds', + defaultLockLifetime: 30000, // In milliseconds, this makes sure that if the bot restarts with locked jobs, they get released quickly and tried again. + db: { + address: url, + collection: `${name}Jobs`, + }, }); + await scheduler.start(); + scheduler.define('autoDisableSlowMode', autoDisableSlowMode); + scheduler.define('sendHeartbeat', sendHeartbeat); + scheduler.define('postBirthdays', postBirthdays); + Logger.info('Scheduler set up'); + } catch (err) { + callback(err); + } + + scheduler.on('error', (err) => { + callback(err); + }); } export function getScheduler(callback = Logger.error) { - if (!scheduler) { - callback(new Error('No scheduler available. Check database connection.')); - return null; - } - return scheduler; + if (!scheduler) { + callback(new Error('No scheduler available. Check database connection.')); + return null; + } + return scheduler; } diff --git a/src/lib/schedulerJobs/autoDisableSlowMode.ts b/src/lib/schedulerJobs/autoDisableSlowMode.ts index 272b83a9..5a20124c 100644 --- a/src/lib/schedulerJobs/autoDisableSlowMode.ts +++ b/src/lib/schedulerJobs/autoDisableSlowMode.ts @@ -4,95 +4,95 @@ import { client } from '../../client'; import { constantsConfig, makeEmbed, Logger, getScheduler } from '../index'; const failedEmbed = (action: string, channel: string) => - makeEmbed({ - title: `Slow Message - ${action} failed`, - description: `Failed to ${action} the slow mode for channel <#${channel}>.`, - color: Colors.Red, - }); + makeEmbed({ + title: `Slow Message - ${action} failed`, + description: `Failed to ${action} the slow mode for channel <#${channel}>.`, + color: Colors.Red, + }); const modLogEmbed = (action: string, fields: any, color: number) => - makeEmbed({ - title: `Slow Mode - ${action}`, - fields, - color, - }); + makeEmbed({ + title: `Slow Mode - ${action}`, + fields, + color, + }); export async function autoDisableSlowMode(job: Job) { - const scheduler = getScheduler(); - if (!scheduler) { - Logger.error('Failed to get scheduler instance'); - return; - } - // Needed because of https://github.com/agenda/agenda/issues/401 - // eslint-disable-next-line no-underscore-dangle - const matchingJobs = await scheduler.jobs({ _id: job.attrs._id }); - if (matchingJobs.length !== 1) { - Logger.debug('Job has been deleted already, skipping execution.'); - return; + const scheduler = getScheduler(); + if (!scheduler) { + Logger.error('Failed to get scheduler instance'); + return; + } + // Needed because of https://github.com/agenda/agenda/issues/401 + // eslint-disable-next-line no-underscore-dangle + const matchingJobs = await scheduler.jobs({ _id: job.attrs._id }); + if (matchingJobs.length !== 1) { + Logger.debug('Job has been deleted already, skipping execution.'); + return; + } + const { channelId } = job.attrs.data as { channelId: string }; + const modLogsChannel = client.channels.resolve(constantsConfig.channels.MOD_LOGS) as TextChannel | null; + const slowmodeChannel = client.channels.resolve(channelId); + if ( + !slowmodeChannel || + [ChannelType.GuildText, ChannelType.GuildForum, ChannelType.PublicThread, ChannelType.PrivateThread].indexOf( + slowmodeChannel.type, + ) === -1 + ) { + Logger.error('Slow mode - Auto disable - Unable to disable for non-existing channel'); + if (modLogsChannel) { + await modLogsChannel.send({ embeds: [failedEmbed('Auto disable', channelId)] }); } - const { channelId } = job.attrs.data as { channelId: string }; - const modLogsChannel = client.channels.resolve(constantsConfig.channels.MOD_LOGS) as TextChannel | null; - const slowmodeChannel = client.channels.resolve(channelId); + return; + } + try { if ( - !slowmodeChannel || - [ChannelType.GuildText, ChannelType.GuildForum, ChannelType.PublicThread, ChannelType.PrivateThread].indexOf( - slowmodeChannel.type, - ) === -1 + slowmodeChannel.type === ChannelType.GuildForum || + slowmodeChannel.type === ChannelType.GuildText || + slowmodeChannel.type === ChannelType.PrivateThread || + slowmodeChannel.type === ChannelType.PublicThread ) { - Logger.error('Slow mode - Auto disable - Unable to disable for non-existing channel'); - if (modLogsChannel) { - await modLogsChannel.send({ embeds: [failedEmbed('Auto disable', channelId)] }); - } - return; - } - try { - if ( - slowmodeChannel.type === ChannelType.GuildForum || - slowmodeChannel.type === ChannelType.GuildText || - slowmodeChannel.type === ChannelType.PrivateThread || - slowmodeChannel.type === ChannelType.PublicThread - ) { - await slowmodeChannel.setRateLimitPerUser(0, 'Slow mode disabled through bot'); - } - await job.remove(); - } catch (err) { - Logger.error(`Failed to auto disable slow mode for channel <#${channelId}>: ${err}`); - return; + await slowmodeChannel.setRateLimitPerUser(0, 'Slow mode disabled through bot'); } + await job.remove(); + } catch (err) { + Logger.error(`Failed to auto disable slow mode for channel <#${channelId}>: ${err}`); + return; + } - try { - // @ts-ignore - await modLogsChannel.send({ - embeds: [ - modLogEmbed( - 'Auto Disable', - [ - { - inline: true, - name: 'Channel', - value: `<#${channelId}>`, - }, - { - inline: true, - name: 'Slow mode limit', - value: 'Disabled', - }, - { - inline: true, - name: 'Auto disable timeout', - value: 'None', - }, - { - inline: true, - name: 'Moderator', - value: 'FBW Bot', - }, - ], - Colors.Green, - ), - ], - }); - } catch (err) { - Logger.warn(`Failed to send Mod Log for auto disable of slow mode for channel <#${channelId}>: ${err}`); - } + try { + // @ts-ignore + await modLogsChannel.send({ + embeds: [ + modLogEmbed( + 'Auto Disable', + [ + { + inline: true, + name: 'Channel', + value: `<#${channelId}>`, + }, + { + inline: true, + name: 'Slow mode limit', + value: 'Disabled', + }, + { + inline: true, + name: 'Auto disable timeout', + value: 'None', + }, + { + inline: true, + name: 'Moderator', + value: 'FBW Bot', + }, + ], + Colors.Green, + ), + ], + }); + } catch (err) { + Logger.warn(`Failed to send Mod Log for auto disable of slow mode for channel <#${channelId}>: ${err}`); + } } diff --git a/src/lib/schedulerJobs/postBirthdays.ts b/src/lib/schedulerJobs/postBirthdays.ts index bde84ffb..963e3267 100644 --- a/src/lib/schedulerJobs/postBirthdays.ts +++ b/src/lib/schedulerJobs/postBirthdays.ts @@ -4,129 +4,129 @@ import { Logger, getScheduler, constantsConfig, getConn, Birthday, makeEmbed, im import { client } from '../../client'; const gifs: string[] = [ - `${imageBaseUrl}/birthday/bubbles.gif`, - `${imageBaseUrl}/birthday/carrey.gif`, - `${imageBaseUrl}/birthday/cat.gif`, - `${imageBaseUrl}/birthday/cat_2.gif`, - `${imageBaseUrl}/birthday/cat_3.gif`, - `${imageBaseUrl}/birthday/dance.gif`, - `${imageBaseUrl}/birthday/dog.gif`, - `${imageBaseUrl}/birthday/dog_2.gif`, - `${imageBaseUrl}/birthday/dwight.gif`, - `${imageBaseUrl}/birthday/elf.gif`, - `${imageBaseUrl}/birthday/snoop.gif`, - `${imageBaseUrl}/birthday/yoda.gif`, + `${imageBaseUrl}/birthday/bubbles.gif`, + `${imageBaseUrl}/birthday/carrey.gif`, + `${imageBaseUrl}/birthday/cat.gif`, + `${imageBaseUrl}/birthday/cat_2.gif`, + `${imageBaseUrl}/birthday/cat_3.gif`, + `${imageBaseUrl}/birthday/dance.gif`, + `${imageBaseUrl}/birthday/dog.gif`, + `${imageBaseUrl}/birthday/dog_2.gif`, + `${imageBaseUrl}/birthday/dwight.gif`, + `${imageBaseUrl}/birthday/elf.gif`, + `${imageBaseUrl}/birthday/snoop.gif`, + `${imageBaseUrl}/birthday/yoda.gif`, ]; export async function postBirthdays(job: Job) { - const scheduler = getScheduler(); - if (!scheduler) { - Logger.error('Failed to get scheduler instance'); - return; + const scheduler = getScheduler(); + if (!scheduler) { + Logger.error('Failed to get scheduler instance'); + return; + } + + // eslint-disable-next-line no-underscore-dangle + const matchingJobs = await scheduler.jobs({ _id: job.attrs._id }); + if (matchingJobs.length !== 1) { + Logger.debug('Job has been deleted already, skipping execution.'); + return; + } + + const guild = client.guilds.resolve(constantsConfig.guildId) as Guild | null; + if (!guild) { + Logger.error('BirthdayHandler - Guild not found.'); + return; + } + + const channel = guild.channels.resolve(constantsConfig.channels.TEAM) as TextChannel | null; + if (!channel) { + Logger.error('BirthdayHandler - Channel not found.'); + return; + } + + // Get all threads (archived included) + + await channel.threads.fetch({ archived: {} }); + const thread = channel.threads.cache.find( + (t) => t.id === constantsConfig.threads.BIRTHDAY_THREAD, + ) as ThreadChannel | null; + if (!thread) { + Logger.error('Birthday handler - Thread not found'); + return; + } + + // Unarchive thread if needed + + if (thread.archived) { + await thread.setArchived(false); + } + + // Get DB Connection + + const conn = getConn(); + if (!conn) { + Logger.error('BirthdayHandler - DB Connection not found, skipping processing.'); + return; + } + + // Get current date + const currentDate = new Date(); + + // Get all birthdays for today + const birthdays = await Birthday.find({ utcDatetime: { $lt: currentDate } }); + + // If there are no birthdays, return + if (!birthdays.length) { + Logger.info('BirthdayHandler - No birthdays found.'); + return; + } + Logger.info(`BirthdayHandler - Processing ${birthdays.length} birthdays.`); + + // Send birthday messages + + for (const birthday of birthdays) { + let user; + try { + // eslint-disable-next-line no-await-in-loop + user = await guild.members.fetch(birthday.userID!); + } catch (error) { + Logger.error('BirthdayHandler - Failed to fetch user', error); } - // eslint-disable-next-line no-underscore-dangle - const matchingJobs = await scheduler.jobs({ _id: job.attrs._id }); - if (matchingJobs.length !== 1) { - Logger.debug('Job has been deleted already, skipping execution.'); - return; + if (!user) { + continue; } - const guild = client.guilds.resolve(constantsConfig.guildId) as Guild | null; - if (!guild) { - Logger.error('BirthdayHandler - Guild not found.'); - return; + const gif = gifs[Math.floor(Math.random() * gifs.length)]; + + // Happy birthday! + const birthdayEmbed = makeEmbed({ + title: 'Happy Birthday!', + description: `${user.displayName}'s birthday is today!`, + color: Colors.Green, + image: { url: gif }, + }); + + // Update birthday to next year + const nextBirthdayDatetime = new Date( + Date.UTC(currentDate.getUTCFullYear() + 1, birthday.month! - 1, birthday.day!), + ); + nextBirthdayDatetime.setUTCHours(10 - birthday.timezone!); + birthday.utcDatetime = nextBirthdayDatetime; + try { + birthday.save(); + } catch (e) { + Logger.error(`Birthday handler - Failed to save the new birthday trigger: ${e}`); } - const channel = guild.channels.resolve(constantsConfig.channels.TEAM) as TextChannel | null; - if (!channel) { - Logger.error('BirthdayHandler - Channel not found.'); - return; - } - - // Get all threads (archived included) - - await channel.threads.fetch({ archived: {} }); - const thread = channel.threads.cache.find( - (t) => t.id === constantsConfig.threads.BIRTHDAY_THREAD, - ) as ThreadChannel | null; - if (!thread) { - Logger.error('Birthday handler - Thread not found'); - return; - } - - // Unarchive thread if needed - - if (thread.archived) { - await thread.setArchived(false); - } - - // Get DB Connection - - const conn = getConn(); - if (!conn) { - Logger.error('BirthdayHandler - DB Connection not found, skipping processing.'); - return; - } - - // Get current date - const currentDate = new Date(); - - // Get all birthdays for today - const birthdays = await Birthday.find({ utcDatetime: { $lt: currentDate } }); - - // If there are no birthdays, return - if (!birthdays.length) { - Logger.info('BirthdayHandler - No birthdays found.'); - return; - } - Logger.info(`BirthdayHandler - Processing ${birthdays.length} birthdays.`); - - // Send birthday messages - - for (const birthday of birthdays) { - let user; - try { - // eslint-disable-next-line no-await-in-loop - user = await guild.members.fetch(birthday.userID!); - } catch (error) { - Logger.error('BirthdayHandler - Failed to fetch user', error); - } - - if (!user) { - continue; - } - - const gif = gifs[Math.floor(Math.random() * gifs.length)]; - - // Happy birthday! - const birthdayEmbed = makeEmbed({ - title: 'Happy Birthday!', - description: `${user.displayName}'s birthday is today!`, - color: Colors.Green, - image: { url: gif }, - }); - - // Update birthday to next year - const nextBirthdayDatetime = new Date( - Date.UTC(currentDate.getUTCFullYear() + 1, birthday.month! - 1, birthday.day!), - ); - nextBirthdayDatetime.setUTCHours(10 - birthday.timezone!); - birthday.utcDatetime = nextBirthdayDatetime; - try { - birthday.save(); - } catch (e) { - Logger.error(`Birthday handler - Failed to save the new birthday trigger: ${e}`); - } - - // Send the birthday message - try { - thread.send({ - content: user.toString(), - embeds: [birthdayEmbed], - }); - } catch (error) { - Logger.error('BirthdayHandler - Failed to send birthday message', error); - } + // Send the birthday message + try { + thread.send({ + content: user.toString(), + embeds: [birthdayEmbed], + }); + } catch (error) { + Logger.error('BirthdayHandler - Failed to send birthday message', error); } + } } diff --git a/src/lib/schedulerJobs/sendHeartbeat.ts b/src/lib/schedulerJobs/sendHeartbeat.ts index 8aa36286..09f57e35 100644 --- a/src/lib/schedulerJobs/sendHeartbeat.ts +++ b/src/lib/schedulerJobs/sendHeartbeat.ts @@ -2,32 +2,32 @@ import { Job } from '@hokify/agenda'; import { Logger, getScheduler } from '../index'; export async function sendHeartbeat(job: Job) { - const scheduler = getScheduler(); - if (!scheduler) { - Logger.error('Failed to get scheduler instance'); - return; - } + const scheduler = getScheduler(); + if (!scheduler) { + Logger.error('Failed to get scheduler instance'); + return; + } - // Needed because of https://github.com/agenda/agenda/issues/401 - // eslint-disable-next-line no-underscore-dangle - const matchingJobs = await scheduler.jobs({ _id: job.attrs._id }); - if (matchingJobs.length !== 1) { - Logger.debug('Job has been deleted already, skipping execution.'); - return; - } + // Needed because of https://github.com/agenda/agenda/issues/401 + // eslint-disable-next-line no-underscore-dangle + const matchingJobs = await scheduler.jobs({ _id: job.attrs._id }); + if (matchingJobs.length !== 1) { + Logger.debug('Job has been deleted already, skipping execution.'); + return; + } - const heartbeatUrl = process.env.HEARTBEAT_URL; - if (!heartbeatUrl) { - Logger.error('HEARTBEAT_URL environment variable not set'); - return; - } - try { - const heartBeatResult = await fetch(`${heartbeatUrl}`); - if (heartBeatResult.status !== 200) { - Logger.error('Failed to send heartbeat:', heartBeatResult.statusText); - } - } catch (error) { - Logger.error('Failed to send heartbeat:', error); + const heartbeatUrl = process.env.HEARTBEAT_URL; + if (!heartbeatUrl) { + Logger.error('HEARTBEAT_URL environment variable not set'); + return; + } + try { + const heartBeatResult = await fetch(`${heartbeatUrl}`); + if (heartBeatResult.status !== 200) { + Logger.error('Failed to send heartbeat:', heartBeatResult.statusText); } - Logger.info('Heartbeat sent successfully'); + } catch (error) { + Logger.error('Failed to send heartbeat:', error); + } + Logger.info('Heartbeat sent successfully'); } diff --git a/src/lib/schemas/birthdaySchema.ts b/src/lib/schemas/birthdaySchema.ts index c9cddb78..122e466b 100644 --- a/src/lib/schemas/birthdaySchema.ts +++ b/src/lib/schemas/birthdaySchema.ts @@ -1,11 +1,11 @@ import mongoose, { Schema } from 'mongoose'; const birthdaySchema = new Schema({ - userID: String, - month: Number, - day: Number, - utcDatetime: Date, - timezone: Number, + userID: String, + month: Number, + day: Number, + utcDatetime: Date, + timezone: Number, }); export const Birthday = mongoose.model('Birthday', birthdaySchema); diff --git a/src/lib/schemas/faqSchema.ts b/src/lib/schemas/faqSchema.ts index f96c47cb..6269e71b 100644 --- a/src/lib/schemas/faqSchema.ts +++ b/src/lib/schemas/faqSchema.ts @@ -1,10 +1,10 @@ import mongoose, { Schema } from 'mongoose'; const faqSchema = new Schema({ - faqTitle: String, - faqAnswer: String, - moderatorID: String, - dateSet: Date, + faqTitle: String, + faqAnswer: String, + moderatorID: String, + dateSet: Date, }); export const FAQ = mongoose.model('FAQ', faqSchema); diff --git a/src/lib/schemas/infractionSchema.ts b/src/lib/schemas/infractionSchema.ts index ab3f6767..22114336 100644 --- a/src/lib/schemas/infractionSchema.ts +++ b/src/lib/schemas/infractionSchema.ts @@ -1,20 +1,20 @@ import mongoose, { Schema } from 'mongoose'; const infractionSchema = new Schema({ - userID: String, - infractions: [ - { - // All infractions must contain the below fields - infractionType: String, // Ban, Kick, Timeout, ScamLog, Note, etc. - moderatorID: String, - reason: String, - date: Date, - infractionID: mongoose.Schema.Types.ObjectId, - // Additional fields specific to each infraction type - duration: String, // Used for timeouts - _id: false, - }, - ], + userID: String, + infractions: [ + { + // All infractions must contain the below fields + infractionType: String, // Ban, Kick, Timeout, ScamLog, Note, etc. + moderatorID: String, + reason: String, + date: Date, + infractionID: mongoose.Schema.Types.ObjectId, + // Additional fields specific to each infraction type + duration: String, // Used for timeouts + _id: false, + }, + ], }); export const Infraction = mongoose.model('Infraction', infractionSchema); diff --git a/src/lib/slashCommand.ts b/src/lib/slashCommand.ts index 94f3e359..19fd8c24 100644 --- a/src/lib/slashCommand.ts +++ b/src/lib/slashCommand.ts @@ -1,47 +1,47 @@ import type { - Awaitable, - Client, - ChatInputCommandInteraction, - SlashCommandBuilder, - SlashCommandSubcommandsOnlyBuilder, - RESTPostAPIApplicationCommandsJSONBody, + Awaitable, + Client, + ChatInputCommandInteraction, + SlashCommandBuilder, + SlashCommandSubcommandsOnlyBuilder, + RESTPostAPIApplicationCommandsJSONBody, } from 'discord.js'; import { LogMethods, AutocompleteCallback } from './index'; /// Props that will be passed through the command callback. export interface SlashCommandProps { - interaction: ChatInputCommandInteraction<'cached'>; - client: Client; - log: LogMethods; + interaction: ChatInputCommandInteraction<'cached'>; + client: Client; + log: LogMethods; } export type SlashCommandCallback = (props: SlashCommandProps) => Awaitable; /// Command structure for slash commands export type SlashCommandStructure = - | (SlashCommandBuilder & { category?: string }) - | (SlashCommandSubcommandsOnlyBuilder & { category?: string }) - | (Omit & { category?: string }) - | (RESTPostAPIApplicationCommandsJSONBody & { category?: string }); + | (SlashCommandBuilder & { category?: string }) + | (SlashCommandSubcommandsOnlyBuilder & { category?: string }) + | (Omit & { category?: string }) + | (RESTPostAPIApplicationCommandsJSONBody & { category?: string }); /// Internal structure that represents a command and its callback. export interface SlashCommand { - meta: SlashCommandStructure; - callback: SlashCommandCallback; - autocompleteCallback?: AutocompleteCallback; + meta: SlashCommandStructure; + callback: SlashCommandCallback; + autocompleteCallback?: AutocompleteCallback; } /// Function to provide data for slash commands export function slashCommandStructure( - data: RESTPostAPIApplicationCommandsJSONBody & { category?: string }, + data: RESTPostAPIApplicationCommandsJSONBody & { category?: string }, ): SlashCommandStructure { - return data; + return data; } /// Creates command structure export function slashCommand( - meta: SlashCommandStructure, - callback: SlashCommandCallback, - autocompleteCallback?: AutocompleteCallback, + meta: SlashCommandStructure, + callback: SlashCommandCallback, + autocompleteCallback?: AutocompleteCallback, ): SlashCommand { - return { meta, callback, autocompleteCallback }; + return { meta, callback, autocompleteCallback }; } diff --git a/src/scripts/deployCommands.ts b/src/scripts/deployCommands.ts index 2de43807..2de87cc1 100644 --- a/src/scripts/deployCommands.ts +++ b/src/scripts/deployCommands.ts @@ -2,25 +2,25 @@ import { REST, Routes, APIUser } from 'discord.js'; import { constantsConfig } from '../lib'; if (!constantsConfig.guildId) { - throw new Error('guildId configuratoin constant is not defined.'); + throw new Error('guildId configuratoin constant is not defined.'); } if (!process.env.BOT_SECRET) { - throw new Error('BOT_SECRET environment variable is not defined.'); + throw new Error('BOT_SECRET environment variable is not defined.'); } const rest = new REST({ version: '10' }).setToken(process.env.BOT_SECRET); export async function deployCommands(commandArray: any[], contextArray: any[]) { - const body = [...commandArray.map((cmd) => cmd.meta), ...contextArray.map((ctx) => ctx.meta)]; - const currentUser = (await rest.get(Routes.user())) as APIUser; + const body = [...commandArray.map((cmd) => cmd.meta), ...contextArray.map((ctx) => ctx.meta)]; + const currentUser = (await rest.get(Routes.user())) as APIUser; - const endpoint = - process.env.NODE_ENV === 'production' - ? Routes.applicationCommands(currentUser.id) - : Routes.applicationGuildCommands(currentUser.id, constantsConfig.guildId); + const endpoint = + process.env.NODE_ENV === 'production' + ? Routes.applicationCommands(currentUser.id) + : Routes.applicationGuildCommands(currentUser.id, constantsConfig.guildId); - await rest.put(endpoint, { body }); + await rest.put(endpoint, { body }); - return currentUser; + return currentUser; } diff --git a/tsconfig.json b/tsconfig.json index bb22582a..516305ab 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,17 +1,17 @@ { "compilerOptions": { - "target": "ES2020", // Target ES2020 or later - "module": "CommonJS", // Use CommonJS modules - "outDir": "./build", // Output directory for compiled files - "rootDir": "./src", // Source directory - "strict": true, // Enable strict type checking - "esModuleInterop": true, // Enable import/export interoperability + "target": "ES2020", // Target ES2020 or later + "module": "CommonJS", // Use CommonJS modules + "outDir": "./build", // Output directory for compiled files + "rootDir": "./src", // Source directory + "strict": true, // Enable strict type checking + "esModuleInterop": true, // Enable import/export interoperability "forceConsistentCasingInFileNames": true, // Enforce consistent file naming - "resolveJsonModule": true, // Allow importing JSON files as modules - "lib": ["ES2020", "DOM"], // Include necessary TypeScript typings - "types": ["node", "discord.js"], // Include typings for Node.js and discord.js - "baseUrl": ".", // Base URL for module resolution + "resolveJsonModule": true, // Allow importing JSON files as modules + "lib": ["ES2020", "DOM"], // Include necessary TypeScript typings + "types": ["node", "discord.js"], // Include typings for Node.js and discord.js + "baseUrl": "." // Base URL for module resolution }, - "include": ["src/**/*.ts"], // Include TypeScript source files + "include": ["src/**/*.ts"], // Include TypeScript source files "exclude": ["node_modules", "dist"] // Exclude files from compilation } From 362b6f8116f40cb2975cd4f6b31435aa0b3664c9 Mon Sep 17 00:00:00 2001 From: ExampleWasTaken <58574351+ExampleWasTaken@users.noreply.github.com> Date: Tue, 18 Jun 2024 01:10:04 +0200 Subject: [PATCH 12/82] add .prettierignore and improve script --- .prettierignore | 1 + .prettierrc | 2 +- package.json | 5 ++--- 3 files changed, 4 insertions(+), 4 deletions(-) create mode 100644 .prettierignore diff --git a/.prettierignore b/.prettierignore new file mode 100644 index 00000000..7e2f179b --- /dev/null +++ b/.prettierignore @@ -0,0 +1 @@ +assets diff --git a/.prettierrc b/.prettierrc index b005b62a..05e23b16 100644 --- a/.prettierrc +++ b/.prettierrc @@ -2,4 +2,4 @@ "singleQuote": true, "printWidth": 120, "endOfLine": "auto" -} \ No newline at end of file +} diff --git a/package.json b/package.json index ef2d46ba..7ced1815 100644 --- a/package.json +++ b/package.json @@ -11,9 +11,8 @@ "build:digitalocean": "npm ci --include=dev && npm run build", "lint": "eslint", "lint-fix": "eslint --fix", - "prettier": "prettier \"**/*.ts\" \"**/*.js\" \"**/*.json\" \"**/*.yaml\" \"**/*.yml\" \"**/*.md\"", - "prettier:check": "npm run prettier -- --check", - "prettier:write": "npm run prettier -- --write", + "prettier:check": "prettier . --check", + "prettier:write": "prettier . --write", "test": "tsc --noEmit && eslint & npm run prettier:check" }, "author": "FlyByWire Simulations", From 0c2913f1b7f6f76b9f4df066e688414c701226a7 Mon Sep 17 00:00:00 2001 From: ExampleWasTaken <58574351+ExampleWasTaken@users.noreply.github.com> Date: Tue, 18 Jun 2024 01:29:36 +0200 Subject: [PATCH 13/82] eslint --fix mk1 --- src/commands/moderation/faq/functions/addFaq.ts | 4 ++-- src/commands/moderation/faq/functions/faqPrintAll.ts | 1 - src/commands/moderation/faq/functions/listFaq.ts | 4 ++-- .../utils/birthday/functions/listBirthday.ts | 4 ++-- .../utils/vatsim/functions/vatsimControllers.ts | 2 -- src/commands/utils/vatsim/functions/vatsimEvents.ts | 1 - .../utils/vatsim/functions/vatsimObservers.ts | 2 -- src/commands/utils/vatsim/functions/vatsimPilots.ts | 2 -- src/commands/utils/vatsim/vatsim.ts | 1 - src/events/logging/detectBan.ts | 5 ++--- src/events/logging/messageDelete.ts | 2 +- src/events/logging/messageUpdate.ts | 2 +- src/events/slashCommandHandler.ts | 2 -- src/lib/events.ts | 1 - src/lib/schedulerJobs/autoDisableSlowMode.ts | 2 +- src/lib/schedulerJobs/postBirthdays.ts | 12 ++++-------- src/lib/schedulerJobs/sendHeartbeat.ts | 2 +- 17 files changed, 16 insertions(+), 33 deletions(-) diff --git a/src/commands/moderation/faq/functions/addFaq.ts b/src/commands/moderation/faq/functions/addFaq.ts index 5b08875e..d21f094a 100644 --- a/src/commands/moderation/faq/functions/addFaq.ts +++ b/src/commands/moderation/faq/functions/addFaq.ts @@ -90,8 +90,8 @@ export async function handleAddFaq(interaction: ChatInputCommandInteraction<'cac if (!faqData) { faqData = new FAQ({ - faqTitle: faqTitle!, - faqAnswer: faqAnswer!, + faqTitle: faqTitle, + faqAnswer: faqAnswer, moderatorID: discordUser.id, dateSet: currentDate, }); diff --git a/src/commands/moderation/faq/functions/faqPrintAll.ts b/src/commands/moderation/faq/functions/faqPrintAll.ts index cb67a9c3..cd2c18f5 100644 --- a/src/commands/moderation/faq/functions/faqPrintAll.ts +++ b/src/commands/moderation/faq/functions/faqPrintAll.ts @@ -56,7 +56,6 @@ export async function handlePrintAllFAQ(interaction: ChatInputCommandInteraction })), }); - // eslint-disable-next-line no-await-in-loop await interaction.channel.send({ embeds: [faqEmbed] }); } diff --git a/src/commands/moderation/faq/functions/listFaq.ts b/src/commands/moderation/faq/functions/listFaq.ts index 7cd9322b..ef27824a 100644 --- a/src/commands/moderation/faq/functions/listFaq.ts +++ b/src/commands/moderation/faq/functions/listFaq.ts @@ -25,9 +25,9 @@ export async function handleListFaq(interaction: ChatInputCommandInteraction<'ca const moderatorPromises = faqs.map((currentFaq) => interaction.client.users - .fetch(currentFaq.moderatorID!) + .fetch(currentFaq.moderatorID) // Added for better readability - // eslint-disable-next-line arrow-body-style + .catch(() => { return new Promise((resolve) => { resolve(`I can't find the moderator, here is the stored ID: ${currentFaq.moderatorID}`); diff --git a/src/commands/utils/birthday/functions/listBirthday.ts b/src/commands/utils/birthday/functions/listBirthday.ts index acdbafb7..3369c05c 100644 --- a/src/commands/utils/birthday/functions/listBirthday.ts +++ b/src/commands/utils/birthday/functions/listBirthday.ts @@ -13,7 +13,7 @@ export async function handleListBirthday(interaction: ChatInputCommandInteractio try { const birthdays = await Birthday.find({}).sort({ day: 1 }); // Only day sort required, months are bucketized - const members = await interaction.guild!.members.fetch(); + const members = await interaction.guild.members.fetch(); const monthBuckets: Array> = [ ['January', []], @@ -31,7 +31,7 @@ export async function handleListBirthday(interaction: ChatInputCommandInteractio ]; for (const birthday of birthdays) { - const member = members.get(birthday.userID!); + const member = members.get(birthday.userID); if (member) { monthBuckets[birthday.utcDatetime!.getUTCMonth()][1].push( diff --git a/src/commands/utils/vatsim/functions/vatsimControllers.ts b/src/commands/utils/vatsim/functions/vatsimControllers.ts index 83a65b52..af0c1c27 100644 --- a/src/commands/utils/vatsim/functions/vatsimControllers.ts +++ b/src/commands/utils/vatsim/functions/vatsimControllers.ts @@ -1,8 +1,6 @@ import { ChatInputCommandInteraction, EmbedField } from 'discord.js'; import { makeEmbed } from '../../../../lib'; -/* eslint-disable camelcase */ - const listEmbed = (type: string, fields: EmbedField[], totalCount: number, shownCount: number, callsign: string) => makeEmbed({ title: `VATSIM Data - ${callsign} - ${totalCount} ${type} online`, diff --git a/src/commands/utils/vatsim/functions/vatsimEvents.ts b/src/commands/utils/vatsim/functions/vatsimEvents.ts index 66803fe9..1762eb78 100644 --- a/src/commands/utils/vatsim/functions/vatsimEvents.ts +++ b/src/commands/utils/vatsim/functions/vatsimEvents.ts @@ -28,7 +28,6 @@ export async function handleVatsimEvents(interaction: ChatInputCommandInteractio const fields: EmbedField[] = eventsList .map((event: any) => { - // eslint-disable-next-line camelcase const { name, organisers, end_time, start_time, link } = event; const { division } = organisers[0]; const startDate = new Date(start_time); diff --git a/src/commands/utils/vatsim/functions/vatsimObservers.ts b/src/commands/utils/vatsim/functions/vatsimObservers.ts index 907b9b70..e06faa8d 100644 --- a/src/commands/utils/vatsim/functions/vatsimObservers.ts +++ b/src/commands/utils/vatsim/functions/vatsimObservers.ts @@ -1,8 +1,6 @@ import { ChatInputCommandInteraction, EmbedField } from 'discord.js'; import { makeEmbed } from '../../../../lib'; -/* eslint-disable camelcase */ - const listEmbed = (type: string, fields: EmbedField[], totalCount: number, shownCount: number, callsign: string) => makeEmbed({ title: `VATSIM Data - ${callsign} - ${totalCount} ${type} online`, diff --git a/src/commands/utils/vatsim/functions/vatsimPilots.ts b/src/commands/utils/vatsim/functions/vatsimPilots.ts index 47ef8127..281b3812 100644 --- a/src/commands/utils/vatsim/functions/vatsimPilots.ts +++ b/src/commands/utils/vatsim/functions/vatsimPilots.ts @@ -1,8 +1,6 @@ import { ChatInputCommandInteraction, EmbedField } from 'discord.js'; import { makeEmbed } from '../../../../lib'; -/* eslint-disable camelcase */ - const listEmbed = (type: string, fields: EmbedField[], totalCount: number, shownCount: number, callsign: string) => makeEmbed({ title: `VATSIM Data - ${callsign} - ${totalCount} ${type} online`, diff --git a/src/commands/utils/vatsim/vatsim.ts b/src/commands/utils/vatsim/vatsim.ts index 8861090b..11ebd74b 100644 --- a/src/commands/utils/vatsim/vatsim.ts +++ b/src/commands/utils/vatsim/vatsim.ts @@ -113,7 +113,6 @@ export default slashCommand(data, async ({ interaction }) => { const regexMatches = callsign.match(regexCheck); if (!regexMatches || !regexMatches.groups || !regexMatches.groups.callsignSearch) { - // eslint-disable-next-line consistent-return return interaction.reply({ content: 'You need to provide a valid callsign or part of a callsign to search for', ephemeral: true, diff --git a/src/events/logging/detectBan.ts b/src/events/logging/detectBan.ts index 3a4163f9..6315fb17 100644 --- a/src/events/logging/detectBan.ts +++ b/src/events/logging/detectBan.ts @@ -108,7 +108,7 @@ const logFailed = makeEmbed({ export default event(Events.GuildBanAdd, async (_, msg) => { Logger.debug('Starting Ban Handler'); - const guildBanAdd = msg as GuildBan; + const guildBanAdd = msg; if (guildBanAdd.guild === null) { // DMs @@ -133,10 +133,9 @@ export default event(Events.GuildBanAdd, async (_, msg) => { do { Logger.debug(`Ban Handler - Finding Audit Log entry retries left: ${retryCount}`); if (retryCount < MAX_RETRIES) { - // eslint-disable-next-line no-await-in-loop await new Promise((f) => setTimeout(f, SLEEP_TIMER)); } - // eslint-disable-next-line no-await-in-loop + const fetchedLogs = await guildBanAdd.guild.fetchAuditLogs({ limit: 1, type: AuditLogEvent.MemberBanAdd, diff --git a/src/events/logging/messageDelete.ts b/src/events/logging/messageDelete.ts index fbe95f76..32c66e63 100644 --- a/src/events/logging/messageDelete.ts +++ b/src/events/logging/messageDelete.ts @@ -106,7 +106,7 @@ export default event(Events.MessageDelete, async (_, msg) => { footer: { text: `User ID: ${msg.author.id}` }, }); - if (userLogsChannel && !constantsConfig.userLogExclude.includes(msg.author!.id)) { + if (userLogsChannel && !constantsConfig.userLogExclude.includes(msg.author.id)) { await userLogsChannel.send({ embeds: [messageDeleteEmbed] }); } } catch (error) { diff --git a/src/events/logging/messageUpdate.ts b/src/events/logging/messageUpdate.ts index 6a86e3c3..292500bd 100644 --- a/src/events/logging/messageUpdate.ts +++ b/src/events/logging/messageUpdate.ts @@ -40,7 +40,7 @@ export default event(Events.MessageUpdate, async (_, oldMessage, newMessage) => editedMessageFieldTitle = 'Edited Message (truncated)'; } - if (userLogsChannel && !constantsConfig.userLogExclude.includes(oldMessage.author!.id)) { + if (userLogsChannel && !constantsConfig.userLogExclude.includes(oldMessage.author.id)) { const messageUpdateEmbed = makeEmbed({ color: Colors.Orange, thumbnail: { url: `${imageBaseUrl}/moderation/message_edited.png` }, diff --git a/src/events/slashCommandHandler.ts b/src/events/slashCommandHandler.ts index cce29f0f..88a701fe 100644 --- a/src/events/slashCommandHandler.ts +++ b/src/events/slashCommandHandler.ts @@ -1,8 +1,6 @@ import { Color, SlashCommand, event, Events, Reply, makeEmbed } from '../lib'; import commandArray from '../commands'; -/* eslint-disable no-underscore-dangle */ - const commandMap = new Map(); for (const cmd of commandArray) { diff --git a/src/lib/events.ts b/src/lib/events.ts index f9143c2d..0b16a43d 100644 --- a/src/lib/events.ts +++ b/src/lib/events.ts @@ -25,7 +25,6 @@ export function event(key: T, callback: EventCallback): export function registerEvents(client: Client, events: Event[]): void { for (const { key, callback } of events) { client.on(key, (...args) => { - // eslint-disable-next-line no-console const log = console.log.bind(Logger, `[Event: ${key}]`); try { diff --git a/src/lib/schedulerJobs/autoDisableSlowMode.ts b/src/lib/schedulerJobs/autoDisableSlowMode.ts index 5a20124c..7ebc3ddf 100644 --- a/src/lib/schedulerJobs/autoDisableSlowMode.ts +++ b/src/lib/schedulerJobs/autoDisableSlowMode.ts @@ -24,7 +24,7 @@ export async function autoDisableSlowMode(job: Job) { return; } // Needed because of https://github.com/agenda/agenda/issues/401 - // eslint-disable-next-line no-underscore-dangle + const matchingJobs = await scheduler.jobs({ _id: job.attrs._id }); if (matchingJobs.length !== 1) { Logger.debug('Job has been deleted already, skipping execution.'); diff --git a/src/lib/schedulerJobs/postBirthdays.ts b/src/lib/schedulerJobs/postBirthdays.ts index 963e3267..9fbf5691 100644 --- a/src/lib/schedulerJobs/postBirthdays.ts +++ b/src/lib/schedulerJobs/postBirthdays.ts @@ -25,14 +25,13 @@ export async function postBirthdays(job: Job) { return; } - // eslint-disable-next-line no-underscore-dangle const matchingJobs = await scheduler.jobs({ _id: job.attrs._id }); if (matchingJobs.length !== 1) { Logger.debug('Job has been deleted already, skipping execution.'); return; } - const guild = client.guilds.resolve(constantsConfig.guildId) as Guild | null; + const guild = client.guilds.resolve(constantsConfig.guildId); if (!guild) { Logger.error('BirthdayHandler - Guild not found.'); return; @@ -47,9 +46,7 @@ export async function postBirthdays(job: Job) { // Get all threads (archived included) await channel.threads.fetch({ archived: {} }); - const thread = channel.threads.cache.find( - (t) => t.id === constantsConfig.threads.BIRTHDAY_THREAD, - ) as ThreadChannel | null; + const thread = channel.threads.cache.find((t) => t.id === constantsConfig.threads.BIRTHDAY_THREAD); if (!thread) { Logger.error('Birthday handler - Thread not found'); return; @@ -87,8 +84,7 @@ export async function postBirthdays(job: Job) { for (const birthday of birthdays) { let user; try { - // eslint-disable-next-line no-await-in-loop - user = await guild.members.fetch(birthday.userID!); + user = await guild.members.fetch(birthday.userID); } catch (error) { Logger.error('BirthdayHandler - Failed to fetch user', error); } @@ -109,7 +105,7 @@ export async function postBirthdays(job: Job) { // Update birthday to next year const nextBirthdayDatetime = new Date( - Date.UTC(currentDate.getUTCFullYear() + 1, birthday.month! - 1, birthday.day!), + Date.UTC(currentDate.getUTCFullYear() + 1, birthday.month! - 1, birthday.day), ); nextBirthdayDatetime.setUTCHours(10 - birthday.timezone!); birthday.utcDatetime = nextBirthdayDatetime; diff --git a/src/lib/schedulerJobs/sendHeartbeat.ts b/src/lib/schedulerJobs/sendHeartbeat.ts index 09f57e35..32c36f1c 100644 --- a/src/lib/schedulerJobs/sendHeartbeat.ts +++ b/src/lib/schedulerJobs/sendHeartbeat.ts @@ -9,7 +9,7 @@ export async function sendHeartbeat(job: Job) { } // Needed because of https://github.com/agenda/agenda/issues/401 - // eslint-disable-next-line no-underscore-dangle + const matchingJobs = await scheduler.jobs({ _id: job.attrs._id }); if (matchingJobs.length !== 1) { Logger.debug('Job has been deleted already, skipping execution.'); From b7bf1bce6a79195c76a0a73a021ab3be90c6aa85 Mon Sep 17 00:00:00 2001 From: ExampleWasTaken <58574351+ExampleWasTaken@users.noreply.github.com> Date: Tue, 18 Jun 2024 01:30:33 +0200 Subject: [PATCH 14/82] eslint --fix mk2 --- .../moderation/infractions/functions/listInfractions.ts | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/commands/moderation/infractions/functions/listInfractions.ts b/src/commands/moderation/infractions/functions/listInfractions.ts index 8ddb46ed..81d76a95 100644 --- a/src/commands/moderation/infractions/functions/listInfractions.ts +++ b/src/commands/moderation/infractions/functions/listInfractions.ts @@ -67,6 +67,8 @@ export async function handleListInfraction( notesLength: userNotes.length.toString(), }; + // Added for future compatibility with other types. + /* eslint-disable @typescript-eslint/no-duplicate-type-constituents */ type InfractionArray = | typeof warnInfractions | typeof timeoutInfractions @@ -74,13 +76,14 @@ export async function handleListInfraction( | typeof banInfractions | typeof unbanInfractions | typeof userNotes; + /* eslint-enable @typescript-eslint/no-duplicate-type-constituents */ const fetchModerators = (infractions: InfractionArray) => { const moderatorPromises = infractions.map((infraction) => interaction.client.users - .fetch(infraction.moderatorID!) + .fetch(infraction.moderatorID) // Disabled for readability - // eslint-disable-next-line arrow-body-style + .catch(() => { return new Promise((resolve) => { resolve(`I can't find the moderator, here is the stored ID: ${infraction.moderatorID}`); From 5c2a5cf3f2e657e0ab0af65c0c7fabab2a9a24ca Mon Sep 17 00:00:00 2001 From: ExampleWasTaken <58574351+ExampleWasTaken@users.noreply.github.com> Date: Tue, 18 Jun 2024 07:28:35 +0200 Subject: [PATCH 15/82] add proposed eslint rule additions --- eslint.config.mjs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/eslint.config.mjs b/eslint.config.mjs index c11b0d4d..1f29c7c7 100644 --- a/eslint.config.mjs +++ b/eslint.config.mjs @@ -25,6 +25,13 @@ export default tseslint.config( argsIgnorePattern: '^_', }, ], + + // The rules below are proposed to best leverage eslint's capabilities and reduce work during code review. + 'no-await-in-loop': 'error', // possible performance impact - see: https://eslint.org/docs/latest/rules/no-await-in-loop + 'no-constructor-return': 'error', // Returing values from constructors is bad practice and can be confusing as constructors always return the object they instantiated (this). + 'no-self-compare': 'error', // Saves time during code review (https://eslint.org/docs/latest/rules/no-self-compare) + 'no-unreachable-loop': 'error', // Saves time during code review (https://eslint.org/docs/latest/rules/no-unreachable-loop) + 'no-console': 'warn', // Using winston should be preferred over direct console.log statements. }, }, { From 8356dc4f0393ad8e66583228de46be8813f3a987 Mon Sep 17 00:00:00 2001 From: ExampleWasTaken <58574351+ExampleWasTaken@users.noreply.github.com> Date: Tue, 18 Jun 2024 07:31:53 +0200 Subject: [PATCH 16/82] improve eslint rule proposal comment --- eslint.config.mjs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/eslint.config.mjs b/eslint.config.mjs index 1f29c7c7..971a5faa 100644 --- a/eslint.config.mjs +++ b/eslint.config.mjs @@ -29,8 +29,8 @@ export default tseslint.config( // The rules below are proposed to best leverage eslint's capabilities and reduce work during code review. 'no-await-in-loop': 'error', // possible performance impact - see: https://eslint.org/docs/latest/rules/no-await-in-loop 'no-constructor-return': 'error', // Returing values from constructors is bad practice and can be confusing as constructors always return the object they instantiated (this). - 'no-self-compare': 'error', // Saves time during code review (https://eslint.org/docs/latest/rules/no-self-compare) - 'no-unreachable-loop': 'error', // Saves time during code review (https://eslint.org/docs/latest/rules/no-unreachable-loop) + 'no-self-compare': 'error', // Saves time during code review .(https://eslint.org/docs/latest/rules/no-self-compare) + 'no-unreachable-loop': 'error', // Saves time during code review by preventing unecessary one-time-loops. (https://eslint.org/docs/latest/rules/no-unreachable-loop) 'no-console': 'warn', // Using winston should be preferred over direct console.log statements. }, }, From 9e9e3d7bdf9b82344d53137a83a1fd9beed1a6d2 Mon Sep 17 00:00:00 2001 From: ExampleWasTaken <58574351+ExampleWasTaken@users.noreply.github.com> Date: Wed, 19 Jun 2024 15:22:39 +0200 Subject: [PATCH 17/82] fix TS build failing --- src/commands/moderation/faq/functions/listFaq.ts | 2 +- .../moderation/infractions/functions/listInfractions.ts | 2 +- src/commands/utils/birthday/functions/listBirthday.ts | 2 +- src/lib/schedulerJobs/postBirthdays.ts | 4 ++-- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/commands/moderation/faq/functions/listFaq.ts b/src/commands/moderation/faq/functions/listFaq.ts index ef27824a..0b887b33 100644 --- a/src/commands/moderation/faq/functions/listFaq.ts +++ b/src/commands/moderation/faq/functions/listFaq.ts @@ -25,7 +25,7 @@ export async function handleListFaq(interaction: ChatInputCommandInteraction<'ca const moderatorPromises = faqs.map((currentFaq) => interaction.client.users - .fetch(currentFaq.moderatorID) + .fetch(currentFaq.moderatorID!) // Added for better readability .catch(() => { diff --git a/src/commands/moderation/infractions/functions/listInfractions.ts b/src/commands/moderation/infractions/functions/listInfractions.ts index 81d76a95..0428e88d 100644 --- a/src/commands/moderation/infractions/functions/listInfractions.ts +++ b/src/commands/moderation/infractions/functions/listInfractions.ts @@ -81,7 +81,7 @@ export async function handleListInfraction( const fetchModerators = (infractions: InfractionArray) => { const moderatorPromises = infractions.map((infraction) => interaction.client.users - .fetch(infraction.moderatorID) + .fetch(infraction.moderatorID!) // Disabled for readability .catch(() => { diff --git a/src/commands/utils/birthday/functions/listBirthday.ts b/src/commands/utils/birthday/functions/listBirthday.ts index 3369c05c..65e52373 100644 --- a/src/commands/utils/birthday/functions/listBirthday.ts +++ b/src/commands/utils/birthday/functions/listBirthday.ts @@ -31,7 +31,7 @@ export async function handleListBirthday(interaction: ChatInputCommandInteractio ]; for (const birthday of birthdays) { - const member = members.get(birthday.userID); + const member = members.get(birthday.userID!); if (member) { monthBuckets[birthday.utcDatetime!.getUTCMonth()][1].push( diff --git a/src/lib/schedulerJobs/postBirthdays.ts b/src/lib/schedulerJobs/postBirthdays.ts index 9fbf5691..28dab494 100644 --- a/src/lib/schedulerJobs/postBirthdays.ts +++ b/src/lib/schedulerJobs/postBirthdays.ts @@ -84,7 +84,7 @@ export async function postBirthdays(job: Job) { for (const birthday of birthdays) { let user; try { - user = await guild.members.fetch(birthday.userID); + user = await guild.members.fetch(birthday.userID!); } catch (error) { Logger.error('BirthdayHandler - Failed to fetch user', error); } @@ -105,7 +105,7 @@ export async function postBirthdays(job: Job) { // Update birthday to next year const nextBirthdayDatetime = new Date( - Date.UTC(currentDate.getUTCFullYear() + 1, birthday.month! - 1, birthday.day), + Date.UTC(currentDate.getUTCFullYear() + 1, birthday.month! - 1, birthday.day!), ); nextBirthdayDatetime.setUTCHours(10 - birthday.timezone!); birthday.utcDatetime = nextBirthdayDatetime; From 74dceec5c1d36dea274346750ee666966d6aeb73 Mon Sep 17 00:00:00 2001 From: ExampleWasTaken <58574351+ExampleWasTaken@users.noreply.github.com> Date: Wed, 19 Jun 2024 15:24:44 +0200 Subject: [PATCH 18/82] temp test script --- package.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/package.json b/package.json index 7ced1815..bef3ab18 100644 --- a/package.json +++ b/package.json @@ -13,7 +13,8 @@ "lint-fix": "eslint --fix", "prettier:check": "prettier . --check", "prettier:write": "prettier . --write", - "test": "tsc --noEmit && eslint & npm run prettier:check" + "dtest": "tsc --noEmit && eslint & npm run prettier:check", + "test": "tsc --noEmit" }, "author": "FlyByWire Simulations", "license": "AGPL-3.0", From 2f2e5bc00dfa357d7e43fcae2338fa9241d706ad Mon Sep 17 00:00:00 2001 From: ExampleWasTaken <58574351+ExampleWasTaken@users.noreply.github.com> Date: Wed, 19 Jun 2024 15:25:00 +0200 Subject: [PATCH 19/82] fix lint deployCommands.ts --- src/scripts/deployCommands.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/scripts/deployCommands.ts b/src/scripts/deployCommands.ts index 2de87cc1..200dbb78 100644 --- a/src/scripts/deployCommands.ts +++ b/src/scripts/deployCommands.ts @@ -1,5 +1,5 @@ import { REST, Routes, APIUser } from 'discord.js'; -import { constantsConfig } from '../lib'; +import { ContextMenuCommand, SlashCommand, constantsConfig } from '../lib'; if (!constantsConfig.guildId) { throw new Error('guildId configuratoin constant is not defined.'); @@ -11,7 +11,7 @@ if (!process.env.BOT_SECRET) { const rest = new REST({ version: '10' }).setToken(process.env.BOT_SECRET); -export async function deployCommands(commandArray: any[], contextArray: any[]) { +export async function deployCommands(commandArray: SlashCommand[], contextArray: ContextMenuCommand[]) { const body = [...commandArray.map((cmd) => cmd.meta), ...contextArray.map((ctx) => ctx.meta)]; const currentUser = (await rest.get(Routes.user())) as APIUser; From fd6f39da7df2e700502ff066d9d18d1ace9495d8 Mon Sep 17 00:00:00 2001 From: ExampleWasTaken <58574351+ExampleWasTaken@users.noreply.github.com> Date: Wed, 19 Jun 2024 16:16:16 +0200 Subject: [PATCH 20/82] fix lint postBirthday.ts --- src/lib/schedulerJobs/postBirthdays.ts | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/src/lib/schedulerJobs/postBirthdays.ts b/src/lib/schedulerJobs/postBirthdays.ts index 28dab494..6ab599c9 100644 --- a/src/lib/schedulerJobs/postBirthdays.ts +++ b/src/lib/schedulerJobs/postBirthdays.ts @@ -1,5 +1,5 @@ import { Job } from '@hokify/agenda'; -import { Colors, Guild, TextChannel, ThreadChannel } from 'discord.js'; +import { Colors, TextChannel } from 'discord.js'; import { Logger, getScheduler, constantsConfig, getConn, Birthday, makeEmbed, imageBaseUrl } from '../index'; import { client } from '../../client'; @@ -80,8 +80,7 @@ export async function postBirthdays(job: Job) { Logger.info(`BirthdayHandler - Processing ${birthdays.length} birthdays.`); // Send birthday messages - - for (const birthday of birthdays) { + const birthdayPromises = birthdays.map(async (birthday) => { let user; try { user = await guild.members.fetch(birthday.userID!); @@ -90,7 +89,7 @@ export async function postBirthdays(job: Job) { } if (!user) { - continue; + return; } const gif = gifs[Math.floor(Math.random() * gifs.length)]; @@ -110,19 +109,21 @@ export async function postBirthdays(job: Job) { nextBirthdayDatetime.setUTCHours(10 - birthday.timezone!); birthday.utcDatetime = nextBirthdayDatetime; try { - birthday.save(); - } catch (e) { - Logger.error(`Birthday handler - Failed to save the new birthday trigger: ${e}`); + await birthday.save(); + } catch (error) { + Logger.error(`Birthday handler - Failed to save the new birthday trigger:`, error); } // Send the birthday message try { - thread.send({ + await thread.send({ content: user.toString(), embeds: [birthdayEmbed], }); } catch (error) { Logger.error('BirthdayHandler - Failed to send birthday message', error); } - } + }); + + await Promise.all(birthdayPromises); } From 1b21636adf33037e749b1be4b48030e8a7b231a9 Mon Sep 17 00:00:00 2001 From: ExampleWasTaken <58574351+ExampleWasTaken@users.noreply.github.com> Date: Wed, 19 Jun 2024 16:23:58 +0200 Subject: [PATCH 21/82] fix lint autoDisableSlowMode.ts --- src/lib/schedulerJobs/autoDisableSlowMode.ts | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/lib/schedulerJobs/autoDisableSlowMode.ts b/src/lib/schedulerJobs/autoDisableSlowMode.ts index 7ebc3ddf..f544edf0 100644 --- a/src/lib/schedulerJobs/autoDisableSlowMode.ts +++ b/src/lib/schedulerJobs/autoDisableSlowMode.ts @@ -1,5 +1,5 @@ import { Job } from '@hokify/agenda'; -import { ChannelType, TextChannel, Colors } from 'discord.js'; +import { ChannelType, TextChannel, Colors, EmbedField } from 'discord.js'; import { client } from '../../client'; import { constantsConfig, makeEmbed, Logger, getScheduler } from '../index'; @@ -10,7 +10,7 @@ const failedEmbed = (action: string, channel: string) => color: Colors.Red, }); -const modLogEmbed = (action: string, fields: any, color: number) => +const modLogEmbed = (action: string, fields: EmbedField[], color: number) => makeEmbed({ title: `Slow Mode - ${action}`, fields, @@ -45,6 +45,7 @@ export async function autoDisableSlowMode(job: Job) { } return; } + try { if ( slowmodeChannel.type === ChannelType.GuildForum || @@ -56,13 +57,12 @@ export async function autoDisableSlowMode(job: Job) { } await job.remove(); } catch (err) { - Logger.error(`Failed to auto disable slow mode for channel <#${channelId}>: ${err}`); + Logger.error(`Failed to auto disable slow mode for channel <#${channelId}>:`, err); return; } try { - // @ts-ignore - await modLogsChannel.send({ + await modLogsChannel!.send({ embeds: [ modLogEmbed( 'Auto Disable', @@ -93,6 +93,6 @@ export async function autoDisableSlowMode(job: Job) { ], }); } catch (err) { - Logger.warn(`Failed to send Mod Log for auto disable of slow mode for channel <#${channelId}>: ${err}`); + Logger.warn(`Failed to send Mod Log for auto disable of slow mode for channel <#${channelId}>:`, err); } } From 8b5fe3583afa0389bfd3bd5f8c61ae54bcad9c04 Mon Sep 17 00:00:00 2001 From: ExampleWasTaken <58574351+ExampleWasTaken@users.noreply.github.com> Date: Wed, 19 Jun 2024 16:26:14 +0200 Subject: [PATCH 22/82] fix lint infractionEmbedPagination.ts --- src/lib/infractionEmbedPagination.ts | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/lib/infractionEmbedPagination.ts b/src/lib/infractionEmbedPagination.ts index 59d974f1..e1a972ed 100644 --- a/src/lib/infractionEmbedPagination.ts +++ b/src/lib/infractionEmbedPagination.ts @@ -92,14 +92,14 @@ export async function createPaginatedInfractionEmbedHandler( currentPage = 6; } - updateEmbed(); + await updateEmbed(); }); collector.on('end', async () => { - handleEmbedExpire(); + await handleEmbedExpire(); }); - function updateEmbed() { + async function updateEmbed() { aboutButton.setStyle(currentPage === 0 ? ButtonStyle.Success : ButtonStyle.Primary); warnButton.setStyle(currentPage === 1 ? ButtonStyle.Success : ButtonStyle.Primary); timeoutButton.setStyle(currentPage === 2 ? ButtonStyle.Success : ButtonStyle.Primary); @@ -108,12 +108,12 @@ export async function createPaginatedInfractionEmbedHandler( unbanButton.setStyle(currentPage === 5 ? ButtonStyle.Success : ButtonStyle.Primary); noteButton.setStyle(currentPage === 6 ? ButtonStyle.Success : ButtonStyle.Primary); - initialInteraction.editReply({ embeds: [embeds[currentPage]], components: [buttonRow1, buttonRow2] }); + await initialInteraction.editReply({ embeds: [embeds[currentPage]], components: [buttonRow1, buttonRow2] }); } - function handleEmbedExpire() { + async function handleEmbedExpire() { const embed = embeds[currentPage]; - initialInteraction.editReply({ + await initialInteraction.editReply({ embeds: [ embed.setFooter({ text: `${embed.data.footer ? `${embed.data.footer.text} - ` : ''}This embed has expired.`, From 22e8d600345ce19d1c5117a780f0148c0b0caed1 Mon Sep 17 00:00:00 2001 From: ExampleWasTaken <58574351+ExampleWasTaken@users.noreply.github.com> Date: Wed, 19 Jun 2024 16:27:19 +0200 Subject: [PATCH 23/82] fix genericEmbedPagination.ts --- src/lib/genericEmbedPagination.ts | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/lib/genericEmbedPagination.ts b/src/lib/genericEmbedPagination.ts index 6758ad29..80a19208 100644 --- a/src/lib/genericEmbedPagination.ts +++ b/src/lib/genericEmbedPagination.ts @@ -56,20 +56,20 @@ export async function createPaginatedEmbedHandler( setButtonDisabledStates(); - updateEmbed(); + await updateEmbed(); }); collector.on('end', async () => { - handleEmbedExpire(); + await handleEmbedExpire(); }); - function updateEmbed() { - initialInteraction.editReply({ embeds: [embeds[currentPage]], components: [buttonRow] }); + async function updateEmbed() { + await initialInteraction.editReply({ embeds: [embeds[currentPage]], components: [buttonRow] }); } - function handleEmbedExpire() { + async function handleEmbedExpire() { const embed = embeds[currentPage]; - initialInteraction.editReply({ + await initialInteraction.editReply({ embeds: [ embed.setFooter({ text: `${embed.data.footer ? `${embed.data.footer.text} - ` : ''}This embed has expired.`, From c109cf88c8c2e230cd1e290c247828e32dd25433 Mon Sep 17 00:00:00 2001 From: ExampleWasTaken <58574351+ExampleWasTaken@users.noreply.github.com> Date: Wed, 19 Jun 2024 16:28:19 +0200 Subject: [PATCH 24/82] temp lint script --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index bef3ab18..c996e806 100644 --- a/package.json +++ b/package.json @@ -9,7 +9,7 @@ "dev": "nodemon --config nodemon.json src/index.ts", "build": "tsc", "build:digitalocean": "npm ci --include=dev && npm run build", - "lint": "eslint", + "lint": "eslint --quiet", "lint-fix": "eslint --fix", "prettier:check": "prettier . --check", "prettier:write": "prettier . --write", From 630ad36ad98f452197cf55ac8585d3d1e62e3999 Mon Sep 17 00:00:00 2001 From: ExampleWasTaken <58574351+ExampleWasTaken@users.noreply.github.com> Date: Wed, 19 Jun 2024 16:29:03 +0200 Subject: [PATCH 25/82] fix lint durationInEnglish.ts --- src/lib/durationInEnglish.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib/durationInEnglish.ts b/src/lib/durationInEnglish.ts index ef29981a..204c7ac5 100644 --- a/src/lib/durationInEnglish.ts +++ b/src/lib/durationInEnglish.ts @@ -1,4 +1,4 @@ -export function durationInEnglish(milliseconds: any) { +export function durationInEnglish(milliseconds: number) { const seconds = milliseconds / 1000; if (seconds < 60) { From e8a9ec453c414e18633268365f46e4de25017301 Mon Sep 17 00:00:00 2001 From: ExampleWasTaken <58574351+ExampleWasTaken@users.noreply.github.com> Date: Wed, 19 Jun 2024 16:45:38 +0200 Subject: [PATCH 26/82] fix missing type update --- src/commands/moderation/infractions/functions/timeout.ts | 4 ++-- src/commands/moderation/slowmode/slowmode.ts | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/commands/moderation/infractions/functions/timeout.ts b/src/commands/moderation/infractions/functions/timeout.ts index 0e7f35be..277850be 100644 --- a/src/commands/moderation/infractions/functions/timeout.ts +++ b/src/commands/moderation/infractions/functions/timeout.ts @@ -24,7 +24,7 @@ const DMEmbed = (moderator: User, timeoutDuration: string, reason: string, guild { inline: true, name: 'Duration', - value: durationInEnglish(timeoutDuration), + value: durationInEnglish(Number.parseInt(timeoutDuration)), }, { inline: true, @@ -80,7 +80,7 @@ const modLogEmbed = ( }, { name: 'Duration', - value: durationInEnglish(timeoutDuration), + value: durationInEnglish(Number.parseInt(timeoutDuration)), }, { name: 'Date', diff --git a/src/commands/moderation/slowmode/slowmode.ts b/src/commands/moderation/slowmode/slowmode.ts index 1c863f8a..e5e48a65 100644 --- a/src/commands/moderation/slowmode/slowmode.ts +++ b/src/commands/moderation/slowmode/slowmode.ts @@ -125,7 +125,7 @@ const slowModeEmbedField = ( { inline: true, name: 'Auto disable timeout', - value: durationInEnglish(autoDisable), + value: durationInEnglish(Number.parseInt(autoDisable)), }, { inline: true, From d99a59e373d31e2a092984e677765fbf8a0e1096 Mon Sep 17 00:00:00 2001 From: ExampleWasTaken <58574351+ExampleWasTaken@users.noreply.github.com> Date: Wed, 19 Jun 2024 16:56:42 +0200 Subject: [PATCH 27/82] fix error logging --- src/lib/schedulerJobs/postBirthdays.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/lib/schedulerJobs/postBirthdays.ts b/src/lib/schedulerJobs/postBirthdays.ts index 6ab599c9..933b0f5f 100644 --- a/src/lib/schedulerJobs/postBirthdays.ts +++ b/src/lib/schedulerJobs/postBirthdays.ts @@ -85,7 +85,7 @@ export async function postBirthdays(job: Job) { try { user = await guild.members.fetch(birthday.userID!); } catch (error) { - Logger.error('BirthdayHandler - Failed to fetch user', error); + Logger.error(`BirthdayHandler - Failed to fetch user: ${JSON.stringify(error)}`); } if (!user) { @@ -111,7 +111,7 @@ export async function postBirthdays(job: Job) { try { await birthday.save(); } catch (error) { - Logger.error(`Birthday handler - Failed to save the new birthday trigger:`, error); + Logger.error(`Birthday handler - Failed to save the new birthday trigger: ${JSON.stringify(error)}`); } // Send the birthday message @@ -121,7 +121,7 @@ export async function postBirthdays(job: Job) { embeds: [birthdayEmbed], }); } catch (error) { - Logger.error('BirthdayHandler - Failed to send birthday message', error); + Logger.error(`BirthdayHandler - Failed to send birthday message: ${JSON.stringify(error)}`); } }); From cc53b0337588ab27b38fd5714f158a7e4df0f73c Mon Sep 17 00:00:00 2001 From: ExampleWasTaken <58574351+ExampleWasTaken@users.noreply.github.com> Date: Wed, 19 Jun 2024 16:58:24 +0200 Subject: [PATCH 28/82] fix error logging mk2 --- src/lib/schedulerJobs/autoDisableSlowMode.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib/schedulerJobs/autoDisableSlowMode.ts b/src/lib/schedulerJobs/autoDisableSlowMode.ts index f544edf0..620b5bdd 100644 --- a/src/lib/schedulerJobs/autoDisableSlowMode.ts +++ b/src/lib/schedulerJobs/autoDisableSlowMode.ts @@ -57,7 +57,7 @@ export async function autoDisableSlowMode(job: Job) { } await job.remove(); } catch (err) { - Logger.error(`Failed to auto disable slow mode for channel <#${channelId}>:`, err); + Logger.error(`Failed to auto disable slow mode for channel <#${channelId}>: ${JSON.stringify(err)}`); return; } From 68b212ef124c80f175bb143a211ff67332e1b6a5 Mon Sep 17 00:00:00 2001 From: ExampleWasTaken <58574351+ExampleWasTaken@users.noreply.github.com> Date: Wed, 19 Jun 2024 16:59:55 +0200 Subject: [PATCH 29/82] fix lint config.ts --- src/lib/config.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib/config.ts b/src/lib/config.ts index 51a7ba52..e6ed09d2 100644 --- a/src/lib/config.ts +++ b/src/lib/config.ts @@ -113,7 +113,7 @@ try { } parsedConfig.roleAssignmentIds = newRoleAssignmentIds; } catch (e) { - Logger.error(`Failed to load config: ${e}`); + Logger.error(`Failed to load config: ${JSON.stringify(e)}`); exit(1); } From f1807ed931e086cc148ec5249d8a948b39626d59 Mon Sep 17 00:00:00 2001 From: ExampleWasTaken <58574351+ExampleWasTaken@users.noreply.github.com> Date: Thu, 20 Jun 2024 00:42:08 +0200 Subject: [PATCH 30/82] fix lint slashCommandHandler.ts --- src/events/slashCommandHandler.ts | 25 +++++++++++++++++++------ 1 file changed, 19 insertions(+), 6 deletions(-) diff --git a/src/events/slashCommandHandler.ts b/src/events/slashCommandHandler.ts index 88a701fe..83312df6 100644 --- a/src/events/slashCommandHandler.ts +++ b/src/events/slashCommandHandler.ts @@ -1,5 +1,6 @@ -import { Color, SlashCommand, event, Events, Reply, makeEmbed } from '../lib'; +import { ApplicationCommandOptionType, CommandInteractionOption, CommandInteractionOptionResolver } from 'discord.js'; import commandArray from '../commands'; +import { Color, Events, Reply, SlashCommand, event, makeEmbed } from '../lib'; const commandMap = new Map(); @@ -18,11 +19,23 @@ export default event(Events.InteractionCreate, async ({ log, client }, interacti } try { - const { commandName, options } = interaction as { - commandName: any; - options: any; + /** + * @deprecated This is a hacky workaround to use private members of the [CommandInteractionOptionResolver](https://discord.js.org/docs/packages/discord.js/14.15.2/CommandInteractionOptionResolver:Class) class. + * + * As minor version updates may break this, we should instead use the public properties to achieve this functionality. + */ + type ChatInputCommandInteractionWithPrivateFields = Omit< + CommandInteractionOptionResolver<'cached'>, + 'getMessage' | 'getFocused' + > & { + _group: string | null; + _hoistedOptions: CommandInteractionOption[]; + _subcommand: string | null; }; + const { commandName } = interaction; + const options = interaction.options as ChatInputCommandInteractionWithPrivateFields; + const command = commandMap.get(commandName); if (!command) { @@ -41,7 +54,7 @@ export default event(Events.InteractionCreate, async ({ log, client }, interacti } if (options._hoistedOptions) { for (const subcommandOption of options._hoistedOptions) { - if (subcommandOption.type === 1) { + if (subcommandOption.type === ApplicationCommandOptionType.Subcommand) { logMessage += `, ${subcommandOption.name}`; } } @@ -56,7 +69,7 @@ export default event(Events.InteractionCreate, async ({ log, client }, interacti } catch (error) { const errorEmbed = makeEmbed({ title: 'An error occurred while executing this command.', - description: `${error}`, + description: String(error), color: Color.Error, }); From f21bfae6ab6c49b1110d8fb4b7c041424485e2f4 Mon Sep 17 00:00:00 2001 From: ExampleWasTaken <58574351+ExampleWasTaken@users.noreply.github.com> Date: Thu, 20 Jun 2024 01:02:11 +0200 Subject: [PATCH 31/82] fix lint ready.ts --- src/events/ready.ts | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/events/ready.ts b/src/events/ready.ts index b99cba82..8b8a2ee2 100644 --- a/src/events/ready.ts +++ b/src/events/ready.ts @@ -13,10 +13,10 @@ export default event(Events.ClientReady, async ({ log }, client) => { log('Production environment detected, setting username, activity, status and avatar.'); try { - client.user?.setUsername('FlyByWire Simulations Utilities'); + await client.user?.setUsername('FlyByWire Simulations Utilities'); client.user?.setActivity('the A380X', { type: ActivityType.Watching }); client.user?.setStatus('online'); - client.user?.setAvatar(`${imageBaseUrl}/fbw_tail.png`); + await client.user?.setAvatar(`${imageBaseUrl}/fbw_tail.png`); } catch (error) { log('Failed to set username, activity, status and avatar:', error); } @@ -26,7 +26,7 @@ export default event(Events.ClientReady, async ({ log }, client) => { if (process.env.DEPLOY === 'true') { log('DEPLOY variable set to true, deploying commands and contexts.'); try { - await deployCommands(commandArray, contextArray).then(async (user) => { + await deployCommands(commandArray, contextArray).then((user) => { const bot = `<@${user.id}>`; const response = @@ -53,7 +53,7 @@ export default event(Events.ClientReady, async ({ log }, client) => { dbConnected = true; }) .catch((error) => { - dbError = error; + dbError = error instanceof Error ? error : undefined; Logger.error(error); }); await setupScheduler('fbwBotScheduler', process.env.MONGODB_URL) @@ -61,7 +61,7 @@ export default event(Events.ClientReady, async ({ log }, client) => { schedulerConnected = true; }) .catch((error) => { - schedulerError = error; + schedulerError = error instanceof Error ? error : undefined; Logger.error(error); }); } @@ -72,7 +72,7 @@ export default event(Events.ClientReady, async ({ log }, client) => { if (scheduler) { const heartbeatJobList = await scheduler.jobs({ name: 'sendHeartbeat' }); if (heartbeatJobList.length === 0) { - scheduler.every(`${process.env.HEARTBEAT_INTERVAL} seconds`, 'sendHeartbeat', { + await scheduler.every(`${process.env.HEARTBEAT_INTERVAL} seconds`, 'sendHeartbeat', { interval: process.env.HEARTBEAT_INTERVAL, }); Logger.info(`Heartbeat job scheduled with interval ${process.env.HEARTBEAT_INTERVAL}`); @@ -81,7 +81,7 @@ export default event(Events.ClientReady, async ({ log }, client) => { const { interval } = heartbeatJob.attrs.data as { interval: string }; if (interval !== process.env.HEARTBEAT_INTERVAL) { await scheduler.cancel({ name: 'sendHeartbeat' }); - scheduler.every(`${process.env.HEARTBEAT_INTERVAL} seconds`, 'sendHeartbeat', { + await scheduler.every(`${process.env.HEARTBEAT_INTERVAL} seconds`, 'sendHeartbeat', { interval: process.env.HEARTBEAT_INTERVAL, }); Logger.info(`Heartbeat job rescheduled with new interval ${process.env.HEARTBEAT_INTERVAL}`); @@ -98,7 +98,7 @@ export default event(Events.ClientReady, async ({ log }, client) => { if (scheduler) { const birthdayJobList = await scheduler.jobs({ name: 'postBirthdays' }); if (birthdayJobList.length === 0) { - scheduler.every(`${process.env.BIRTHDAY_INTERVAL} seconds`, 'postBirthdays', { + await scheduler.every(`${process.env.BIRTHDAY_INTERVAL} seconds`, 'postBirthdays', { interval: process.env.BIRTHDAY_INTERVAL, }); Logger.info(`Birthday job scheduled with interval ${process.env.BIRTHDAY_INTERVAL}`); @@ -107,7 +107,7 @@ export default event(Events.ClientReady, async ({ log }, client) => { const { interval } = birthdayJob.attrs.data as { interval: string }; if (interval !== process.env.BIRTHDAY_INTERVAL) { await scheduler.cancel({ name: 'postBirthdays' }); - scheduler.every(`${process.env.BIRTHDAY_INTERVAL} seconds`, 'postBirthdays', { + await scheduler.every(`${process.env.BIRTHDAY_INTERVAL} seconds`, 'postBirthdays', { interval: process.env.BIRTHDAY_INTERVAL, }); Logger.info(`Birthday job rescheduled with new interval ${process.env.BIRTHDAY_INTERVAL}`); From eb5d19d557b014a15d48163d443266e3c0e4918c Mon Sep 17 00:00:00 2001 From: ExampleWasTaken <58574351+ExampleWasTaken@users.noreply.github.com> Date: Thu, 20 Jun 2024 01:05:52 +0200 Subject: [PATCH 32/82] fix lint scamLogs.ts --- src/events/logging/scamLogs.ts | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/src/events/logging/scamLogs.ts b/src/events/logging/scamLogs.ts index 2ae9bd28..658bdb38 100644 --- a/src/events/logging/scamLogs.ts +++ b/src/events/logging/scamLogs.ts @@ -68,8 +68,8 @@ export default event(Events.MessageCreate, async ({ log }, msg) => { let hasRole = false; try { excludedRoles.forEach((roleList) => { - // @ts-ignore - if (msg.member.roles.cache.some((role) => role.id === roleList)) { + // FIXME: assert msg.member type + if (msg.member!.roles.cache.some((role) => role.id === roleList)) { hasRole = true; } }); @@ -89,11 +89,11 @@ export default event(Events.MessageCreate, async ({ log }, msg) => { fields: [ { name: 'User:', - value: `${msg.author}`, + value: `${msg.author.toString()}`, }, { name: 'Channel:', - value: `${msg.channel}`, + value: `${msg.channel.toString()}`, }, { name: messageContentFieldTitle, @@ -123,11 +123,11 @@ export default event(Events.MessageCreate, async ({ log }, msg) => { fields: [ { name: 'User:', - value: `${msg.author}`, + value: `${msg.author.toString()}`, }, { name: 'Channel:', - value: `${msg.channel}`, + value: `${msg.channel.toString()}`, }, { name: messageContentFieldTitle, @@ -137,13 +137,16 @@ export default event(Events.MessageCreate, async ({ log }, msg) => { }); // Time out try { - // @ts-ignore - await msg.member.timeout(60 * 60 * 24 * 7 * 1000, 'Scam log'); + // FIXME: assert msg.member type + await msg.member!.timeout(60 * 60 * 24 * 7 * 1000, 'Scam log'); } catch (e) { log(e); const errorEmbed = makeEmbed({ title: 'Error timing out user', - description: makeLines([`An error occurred while timing out ${msg.author}`, `${codeBlock(`Error : ${e}`)}`]), + description: makeLines([ + `An error occurred while timing out ${msg.author.toString()}`, + `${codeBlock(`Error : ${String(e)}`)}`, + ]), color: Colors.Red, }); await scamReportLogs.send({ embeds: [errorEmbed] }); From 34ec947cd3f6159b9fc156185c2224d8eb2c0f1f Mon Sep 17 00:00:00 2001 From: ExampleWasTaken <58574351+ExampleWasTaken@users.noreply.github.com> Date: Thu, 20 Jun 2024 01:09:57 +0200 Subject: [PATCH 33/82] fix lint messageUpdate.ts --- src/events/logging/messageUpdate.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/events/logging/messageUpdate.ts b/src/events/logging/messageUpdate.ts index 292500bd..9252bd13 100644 --- a/src/events/logging/messageUpdate.ts +++ b/src/events/logging/messageUpdate.ts @@ -49,8 +49,8 @@ export default event(Events.MessageUpdate, async (_, oldMessage, newMessage) => iconURL: oldMessage.author.displayAvatarURL(), }, fields: [ - { name: 'Author', value: `${oldMessage.author}`, inline: true }, - { name: 'Channel', value: `${oldMessage.channel}`, inline: true }, + { name: 'Author', value: `${oldMessage.author.toString()}`, inline: true }, + { name: 'Channel', value: `${oldMessage.channel.toString()}`, inline: true }, { name: originalMessageFieldTitle, value: oldMessageContent ? `\`\`\`${oldMessageContent}\`\`\`` : FEATURE_NOT_AVAIL, From 83193fb4ed0114f82e59acb9d89e6d66e10b7d4d Mon Sep 17 00:00:00 2001 From: ExampleWasTaken <58574351+ExampleWasTaken@users.noreply.github.com> Date: Sun, 23 Jun 2024 04:46:29 +0200 Subject: [PATCH 34/82] fix lint messageDelete.ts --- src/events/logging/messageDelete.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/events/logging/messageDelete.ts b/src/events/logging/messageDelete.ts index 32c66e63..3915a6b5 100644 --- a/src/events/logging/messageDelete.ts +++ b/src/events/logging/messageDelete.ts @@ -76,12 +76,12 @@ export default event(Events.MessageDelete, async (_, msg) => { }, { name: 'Author', - value: `${msg.author}`, + value: `${msg.author.toString()}`, inline: true, }, { name: 'Channel', - value: `${msg.channel}`, + value: `${msg.channel.toString()}`, inline: true, }, { @@ -93,7 +93,7 @@ export default event(Events.MessageDelete, async (_, msg) => { name: 'Deleted by', value: deletionLog && deletionLog.target.id === msg.author.id - ? `${deletionLog.executor}` + ? `${deletionLog.executor ? deletionLog.executor.toString() : 'Could not find executor.'}` : 'No audit log was found, message was either deleted by author, or a bot', inline: false, }, From e499b94276d1404a5fe3f98298df1583fd804a5b Mon Sep 17 00:00:00 2001 From: ExampleWasTaken <58574351+ExampleWasTaken@users.noreply.github.com> Date: Sun, 23 Jun 2024 04:57:07 +0200 Subject: [PATCH 35/82] fix lint detectBan.ts --- src/events/logging/detectBan.ts | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/events/logging/detectBan.ts b/src/events/logging/detectBan.ts index 6315fb17..0019c7ce 100644 --- a/src/events/logging/detectBan.ts +++ b/src/events/logging/detectBan.ts @@ -1,6 +1,6 @@ //This detects non bot bans and sends a message to the mod logs channel -import { AuditLogEvent, bold, Colors, GuildBan, TextChannel, User } from 'discord.js'; +import { AuditLogEvent, bold, Colors, TextChannel, User } from 'discord.js'; import moment from 'moment/moment'; import mongoose from 'mongoose'; import { constantsConfig, event, Events, Infraction, Logger, makeEmbed, makeLines } from '../../lib'; @@ -40,11 +40,11 @@ const modLogEmbed = (user: User, executor: User, reason: string, formattedDate: fields: [ { name: 'User', - value: `${user}`, + value: `${user.toString()}`, }, { name: 'Moderator', - value: `${executor}`, + value: `${executor.toString()}`, }, { name: 'Reason', @@ -115,9 +115,7 @@ export default event(Events.GuildBanAdd, async (_, msg) => { return; } - const modLogsChannel = (await guildBanAdd.guild.channels.resolve( - constantsConfig.channels.MOD_LOGS, - )) as TextChannel | null; + const modLogsChannel = guildBanAdd.guild.channels.resolve(constantsConfig.channels.MOD_LOGS) as TextChannel | null; if (!modLogsChannel) { // Exit as can't post return; @@ -130,6 +128,9 @@ export default event(Events.GuildBanAdd, async (_, msg) => { let reason; let target; let retryCount = MAX_RETRIES; + + // No performance impact by await. + /* eslint-disable no-await-in-loop */ do { Logger.debug(`Ban Handler - Finding Audit Log entry retries left: ${retryCount}`); if (retryCount < MAX_RETRIES) { @@ -147,6 +148,7 @@ export default event(Events.GuildBanAdd, async (_, msg) => { retryCount--; } while ((!target || target.id !== guildBanAdd.user.id) && retryCount > 0); + /* eslint-enable no-await-in-loop */ if (!target) { await modLogsChannel.send({ embeds: [noLogEmbed(guildBanAdd.user, guildBanAdd.guild.name)] }); From fa42392d4002b1aa5fa3ed8452b69cd017ecb3cd Mon Sep 17 00:00:00 2001 From: ExampleWasTaken <58574351+ExampleWasTaken@users.noreply.github.com> Date: Sun, 23 Jun 2024 04:58:01 +0200 Subject: [PATCH 36/82] fix lint contextInteractionHandler.ts --- src/events/contextInteractionHandler.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/events/contextInteractionHandler.ts b/src/events/contextInteractionHandler.ts index 94927443..a4c9de3c 100644 --- a/src/events/contextInteractionHandler.ts +++ b/src/events/contextInteractionHandler.ts @@ -28,7 +28,7 @@ export default event(Events.InteractionCreate, async ({ log, client }, interacti } catch (error) { const errorEmbed = makeEmbed({ title: 'An error occurred while executing this context command.', - description: `${error}`, + description: String(error), color: Color.Error, }); From 3a59e5a8587f474a11dce91e41c9b326980c841a Mon Sep 17 00:00:00 2001 From: ExampleWasTaken <58574351+ExampleWasTaken@users.noreply.github.com> Date: Sun, 23 Jun 2024 04:58:32 +0200 Subject: [PATCH 37/82] fix lint handleRoleAssignment.ts --- src/events/buttonHandlers/functions/handleRoleAssignment.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/events/buttonHandlers/functions/handleRoleAssignment.ts b/src/events/buttonHandlers/functions/handleRoleAssignment.ts index c1feb3d2..25570602 100644 --- a/src/events/buttonHandlers/functions/handleRoleAssignment.ts +++ b/src/events/buttonHandlers/functions/handleRoleAssignment.ts @@ -14,7 +14,7 @@ export async function handleRoleAssignment(interaction: ButtonInteraction, roleI if (!role) { Logger.error('Role Assignment: Role not found'); - interaction.editReply({ content: "I couldn't find that role" }); + await interaction.editReply({ content: "I couldn't find that role" }); return; } From 1ae09189a59e6376292a40bae0eeadf91f0ea9d8 Mon Sep 17 00:00:00 2001 From: ExampleWasTaken <58574351+ExampleWasTaken@users.noreply.github.com> Date: Sun, 23 Jun 2024 04:59:11 +0200 Subject: [PATCH 38/82] fix lint buttonHandler.ts --- src/events/buttonHandlers/buttonHandler.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/events/buttonHandlers/buttonHandler.ts b/src/events/buttonHandlers/buttonHandler.ts index 9069cc2c..b7937745 100644 --- a/src/events/buttonHandlers/buttonHandler.ts +++ b/src/events/buttonHandlers/buttonHandler.ts @@ -14,11 +14,12 @@ export default event(Events.InteractionCreate, async ({ log }, interaction) => { const [prefix, ...params] = interaction.customId.split('_'); switch (prefix) { - case 'roleAssignment': + case 'roleAssignment': { const [roleID] = params; await handleRoleAssignment(interaction, roleID); log(`Button Handler: Role assignment button pressed by ${user.tag} (${user.id}). roleID: ${roleID}`); break; + } default: if (buttonLabel) { log( From ce55c1b971b6a1c13245cac786d3e1763e609624 Mon Sep 17 00:00:00 2001 From: ExampleWasTaken <58574351+ExampleWasTaken@users.noreply.github.com> Date: Sun, 23 Jun 2024 05:00:59 +0200 Subject: [PATCH 39/82] fix lint autocompleteHandler.ts --- src/events/autocompleteHandler.ts | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/events/autocompleteHandler.ts b/src/events/autocompleteHandler.ts index 0ab4ee5d..b1a5e295 100644 --- a/src/events/autocompleteHandler.ts +++ b/src/events/autocompleteHandler.ts @@ -17,10 +17,7 @@ export default event(Events.InteractionCreate, async ({ log, client }, interacti } try { - const { commandName } = interaction as { - commandName: any; - options: any; - }; + const { commandName } = interaction; const command = commandMap.get(commandName); From c14e17078fe6dcc9325a527ab39a235a9a469e85 Mon Sep 17 00:00:00 2001 From: ExampleWasTaken <58574351+ExampleWasTaken@users.noreply.github.com> Date: Sun, 23 Jun 2024 06:03:01 +0200 Subject: [PATCH 40/82] fix lint wolframAlpha.ts --- src/commands/utils/wolframAlpha.ts | 44 +++++++++++++++++++++++++++--- 1 file changed, 40 insertions(+), 4 deletions(-) diff --git a/src/commands/utils/wolframAlpha.ts b/src/commands/utils/wolframAlpha.ts index c9d51cf8..5ea57376 100644 --- a/src/commands/utils/wolframAlpha.ts +++ b/src/commands/utils/wolframAlpha.ts @@ -1,5 +1,6 @@ import { ApplicationCommandOptionType, ApplicationCommandType, Colors } from 'discord.js'; import { slashCommand, slashCommandStructure, makeEmbed, makeLines, Logger } from '../../lib'; +import { Response } from 'node-fetch'; const data = slashCommandStructure({ name: 'wolframalpha', @@ -52,12 +53,14 @@ export default slashCommand(data, async ({ interaction }) => { const searchParams = new URLSearchParams(params); try { - const response = await fetch(`${WOLFRAMALPHA_API_URL}${searchParams.toString()}`).then((res) => res.json()); + const response = (await fetch(`${WOLFRAMALPHA_API_URL}${searchParams.toString()}`).then((res) => + res.json(), + )) as WolframAlphaResponse; if (response.error) { const errorEmbed = makeEmbed({ title: 'Wolfram Alpha Error', - description: response.error, + description: response.error.toString(), color: Colors.Red, }); return interaction.followUp({ embeds: [errorEmbed], ephemeral: true }); @@ -65,10 +68,10 @@ export default slashCommand(data, async ({ interaction }) => { if (response.queryresult.success === true) { const podTexts: string[] = []; - response.queryresult.pods.forEach((pod: any) => { + response.queryresult.pods.forEach((pod: Pod) => { if (pod.id !== 'Input' && pod.primary === true) { const results: string[] = []; - pod.subpods.forEach((subpod: any) => { + pod.subpods.forEach((subpod: SubPod) => { results.push(subpod.plaintext); }); if (results.length > 0) { @@ -115,3 +118,36 @@ export default slashCommand(data, async ({ interaction }) => { return interaction.followUp({ embeds: [fetchErrorEmbed], ephemeral: true }); } }); + +/** + * This is a very hacky approach to satisfy TS-ESLint. However, there are no type packages or API wrappers that are somewhat up-to-date. + * Therefore, I would recommend using our own types. + * Note, that the types below are not complete and only cover our current needs. + * Changes to the JSON data returned by the API may break this code, whether or not proper typing is used. + * Therefore, this approach is probably better than simply disabling ESLint for this file. + * See WolframAlpha API docs: https://products.wolframalpha.com/api/documentation + */ + +interface WolframAlphaResponse extends Response { + queryresult: QueryResult; + error?: string; +} + +interface QueryResult { + success: boolean; + error: boolean; + pods: Pod[]; +} + +interface Pod { + title: string; + id: string; + primary: boolean; + subpods: SubPod[]; +} + +interface SubPod { + title: string; + plaintext: string; + primary: boolean; +} From 486edb98b442a30615d4b394c99616f2c44a7ea0 Mon Sep 17 00:00:00 2001 From: ExampleWasTaken <58574351+ExampleWasTaken@users.noreply.github.com> Date: Mon, 24 Jun 2024 20:56:20 +0200 Subject: [PATCH 41/82] disable eslint for vatsim commands --- src/commands/utils/vatsim/functions/vatsimControllers.ts | 3 +++ src/commands/utils/vatsim/functions/vatsimEvents.ts | 3 +++ src/commands/utils/vatsim/functions/vatsimObservers.ts | 3 +++ src/commands/utils/vatsim/functions/vatsimPilots.ts | 3 +++ src/commands/utils/vatsim/functions/vatsimStats.ts | 3 +++ src/commands/utils/vatsim/vatsim.ts | 3 +++ 6 files changed, 18 insertions(+) diff --git a/src/commands/utils/vatsim/functions/vatsimControllers.ts b/src/commands/utils/vatsim/functions/vatsimControllers.ts index af0c1c27..35b9067c 100644 --- a/src/commands/utils/vatsim/functions/vatsimControllers.ts +++ b/src/commands/utils/vatsim/functions/vatsimControllers.ts @@ -1,3 +1,6 @@ +/* eslint-disable */ +// Safer to be done separately due to complexity. + import { ChatInputCommandInteraction, EmbedField } from 'discord.js'; import { makeEmbed } from '../../../../lib'; diff --git a/src/commands/utils/vatsim/functions/vatsimEvents.ts b/src/commands/utils/vatsim/functions/vatsimEvents.ts index 1762eb78..a63e4cbd 100644 --- a/src/commands/utils/vatsim/functions/vatsimEvents.ts +++ b/src/commands/utils/vatsim/functions/vatsimEvents.ts @@ -1,3 +1,6 @@ +/* eslint-disable */ +// Safer to be done separately due to complexity. + import { ChatInputCommandInteraction, Colors, EmbedField } from 'discord.js'; import { Logger, makeEmbed } from '../../../../lib'; diff --git a/src/commands/utils/vatsim/functions/vatsimObservers.ts b/src/commands/utils/vatsim/functions/vatsimObservers.ts index e06faa8d..102fa2e8 100644 --- a/src/commands/utils/vatsim/functions/vatsimObservers.ts +++ b/src/commands/utils/vatsim/functions/vatsimObservers.ts @@ -1,3 +1,6 @@ +/* eslint-disable */ +// Safer to be done separately due to complexity. + import { ChatInputCommandInteraction, EmbedField } from 'discord.js'; import { makeEmbed } from '../../../../lib'; diff --git a/src/commands/utils/vatsim/functions/vatsimPilots.ts b/src/commands/utils/vatsim/functions/vatsimPilots.ts index 281b3812..f8157839 100644 --- a/src/commands/utils/vatsim/functions/vatsimPilots.ts +++ b/src/commands/utils/vatsim/functions/vatsimPilots.ts @@ -1,3 +1,6 @@ +/* eslint-disable */ +// Safer to be done separately due to complexity. + import { ChatInputCommandInteraction, EmbedField } from 'discord.js'; import { makeEmbed } from '../../../../lib'; diff --git a/src/commands/utils/vatsim/functions/vatsimStats.ts b/src/commands/utils/vatsim/functions/vatsimStats.ts index b5a02f2c..1e7e78a9 100644 --- a/src/commands/utils/vatsim/functions/vatsimStats.ts +++ b/src/commands/utils/vatsim/functions/vatsimStats.ts @@ -1,3 +1,6 @@ +/* eslint-disable */ +// Safer to be done separately due to complexity. + import { ChatInputCommandInteraction } from 'discord.js'; import { makeEmbed } from '../../../../lib'; diff --git a/src/commands/utils/vatsim/vatsim.ts b/src/commands/utils/vatsim/vatsim.ts index 11ebd74b..a5fc98ff 100644 --- a/src/commands/utils/vatsim/vatsim.ts +++ b/src/commands/utils/vatsim/vatsim.ts @@ -1,3 +1,6 @@ +/* eslint-disable */ +// Safer to be done separately due to complexity. + import { ApplicationCommandOptionType, ApplicationCommandType, Colors } from 'discord.js'; import { makeEmbed, slashCommand, slashCommandStructure } from '../../../lib'; import { handleVatsimStats } from './functions/vatsimStats'; From 21d7d46fad9770f531d3e8bd1b15cc27fd9f6fbd Mon Sep 17 00:00:00 2001 From: ExampleWasTaken <58574351+ExampleWasTaken@users.noreply.github.com> Date: Sun, 14 Jul 2024 04:24:56 +0200 Subject: [PATCH 42/82] bump typescript-eslint to latest rc --- package-lock.json | 381 +++++++++++++--------------------------------- package.json | 2 +- 2 files changed, 110 insertions(+), 273 deletions(-) diff --git a/package-lock.json b/package-lock.json index fdc3313d..668e3d41 100644 --- a/package-lock.json +++ b/package-lock.json @@ -37,7 +37,7 @@ "prettier": "^3.3.2", "ts-node": "^10.4.0", "typescript": "^5.4.5", - "typescript-eslint": "^8.0.0-alpha.30" + "typescript-eslint": "^8.0.0-alpha.42" }, "engines": { "node": "18.x" @@ -2667,15 +2667,20 @@ "@types/node": "*" } }, - "node_modules/@typescript-eslint/type-utils": { - "version": "8.0.0-alpha.30", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.0.0-alpha.30.tgz", - "integrity": "sha512-FrnhlCKEKZKRbpDviHkIU9tayIUGTOfa+SjvrRv6p/AJIUv6QT8oRboRjLH/cCuwUEbM0k5UtRWYug4albHUqQ==", + "node_modules/@typescript-eslint/eslint-plugin": { + "version": "8.0.0-alpha.42", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.0.0-alpha.42.tgz", + "integrity": "sha512-la2sVBOUd6oKsSXSrLgDTu0+m6+TeA3YodHtPqUY231ETdd835hWbJkyVU893MWRRDuOyC09I528RRiGjBAODA==", "dev": true, "dependencies": { - "@typescript-eslint/typescript-estree": "8.0.0-alpha.30", - "@typescript-eslint/utils": "8.0.0-alpha.30", - "debug": "^4.3.4", + "@eslint-community/regexpp": "^4.10.0", + "@typescript-eslint/scope-manager": "8.0.0-alpha.42", + "@typescript-eslint/type-utils": "8.0.0-alpha.42", + "@typescript-eslint/utils": "8.0.0-alpha.42", + "@typescript-eslint/visitor-keys": "8.0.0-alpha.42", + "graphemer": "^1.4.0", + "ignore": "^5.3.1", + "natural-compare": "^1.4.0", "ts-api-utils": "^1.3.0" }, "engines": { @@ -2685,39 +2690,27 @@ "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" }, + "peerDependencies": { + "@typescript-eslint/parser": "^8.0.0 || ^8.0.0-alpha.0", + "eslint": "^8.57.0 || ^9.0.0" + }, "peerDependenciesMeta": { "typescript": { "optional": true } } }, - "node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/types": { - "version": "8.0.0-alpha.30", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.0.0-alpha.30.tgz", - "integrity": "sha512-4WzLlw27SO9pK9UFj/Hu7WGo8WveT0SEiIpFVsV2WwtQmLps6kouwtVCB8GJPZKJyurhZhcqCoQVQFmpv441Vg==", - "dev": true, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/typescript-estree": { - "version": "8.0.0-alpha.30", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.0.0-alpha.30.tgz", - "integrity": "sha512-WSXbc9ZcXI+7yC+6q95u77i8FXz6HOLsw3ST+vMUlFy1lFbXyFL/3e6HDKQCm2Clt0krnoCPiTGvIn+GkYPn4Q==", + "node_modules/@typescript-eslint/parser": { + "version": "8.0.0-alpha.42", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.0.0-alpha.42.tgz", + "integrity": "sha512-lOUDE+wJwQMq+/KJFCNo9SkJvQ1WGyoubucCWtgDHzr2itfmg0c51Z1wZLyeLSVBsHAWSiR+TIsGoCpHy+5D5Q==", "dev": true, "dependencies": { - "@typescript-eslint/types": "8.0.0-alpha.30", - "@typescript-eslint/visitor-keys": "8.0.0-alpha.30", - "debug": "^4.3.4", - "globby": "^11.1.0", - "is-glob": "^4.0.3", - "minimatch": "^9.0.4", - "semver": "^7.6.0", - "ts-api-utils": "^1.3.0" + "@typescript-eslint/scope-manager": "8.0.0-alpha.42", + "@typescript-eslint/types": "8.0.0-alpha.42", + "@typescript-eslint/typescript-estree": "8.0.0-alpha.42", + "@typescript-eslint/visitor-keys": "8.0.0-alpha.42", + "debug": "^4.3.4" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -2726,20 +2719,23 @@ "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0" + }, "peerDependenciesMeta": { "typescript": { "optional": true } } }, - "node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/visitor-keys": { - "version": "8.0.0-alpha.30", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.0.0-alpha.30.tgz", - "integrity": "sha512-XZuNurZxBqmr6ZIRIwWFq7j5RZd6ZlkId/HZEWyfciK+CWoyOxSF9Pv2VXH9Rlu2ZG2PfbhLz2Veszl4Pfn7yA==", + "node_modules/@typescript-eslint/scope-manager": { + "version": "8.0.0-alpha.42", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.0.0-alpha.42.tgz", + "integrity": "sha512-3nS6VEzxUPEMvqadRaGkjZuL+fsjNf5lCYbvS0IQYzqJl7338yhxvPCraHmXe/xlB08p+5BAd6JYAbkTeSXxJw==", "dev": true, "dependencies": { - "@typescript-eslint/types": "8.0.0-alpha.30", - "eslint-visitor-keys": "^3.4.3" + "@typescript-eslint/types": "8.0.0-alpha.42", + "@typescript-eslint/visitor-keys": "8.0.0-alpha.42" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -2749,31 +2745,16 @@ "url": "https://opencollective.com/typescript-eslint" } }, - "node_modules/@typescript-eslint/type-utils/node_modules/minimatch": { - "version": "9.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.4.tgz", - "integrity": "sha512-KqWh+VchfxcMNRAJjj2tnsSJdNbHsVgnkBhTNrW7AjVo6OvLtxw8zfT9oLw1JSohlFzJ8jCoTgaoXvJ+kHt6fw==", - "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": "8.0.0-alpha.30", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.0.0-alpha.30.tgz", - "integrity": "sha512-rfhqfLqFyXhHNDwMnHiVGxl/Z2q/3guQ1jLlGQ0hi9Rb7inmwz42crM+NnLPR+2vEnwyw1P/g7fnQgQ3qvFx4g==", + "node_modules/@typescript-eslint/type-utils": { + "version": "8.0.0-alpha.42", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.0.0-alpha.42.tgz", + "integrity": "sha512-vmmJgOHycCTUe/d7DdbBkhz1NAJ08wVptyFP17pcmagIq2oTTan9ffIMbIxCKepGi0l5UzdSGf3l9IYZ+xjD8w==", "dev": true, "dependencies": { - "@eslint-community/eslint-utils": "^4.4.0", - "@typescript-eslint/scope-manager": "8.0.0-alpha.30", - "@typescript-eslint/types": "8.0.0-alpha.30", - "@typescript-eslint/typescript-estree": "8.0.0-alpha.30" + "@typescript-eslint/typescript-estree": "8.0.0-alpha.42", + "@typescript-eslint/utils": "8.0.0-alpha.42", + "debug": "^4.3.4", + "ts-api-utils": "^1.3.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -2782,31 +2763,16 @@ "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" }, - "peerDependencies": { - "eslint": "^8.57.0 || ^9.0.0" - } - }, - "node_modules/@typescript-eslint/utils/node_modules/@typescript-eslint/scope-manager": { - "version": "8.0.0-alpha.30", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.0.0-alpha.30.tgz", - "integrity": "sha512-FGW/iPWGyPFamAVZ60oCAthMqQrqafUGebF8UKuq/ha+e9SVG6YhJoRzurlQXOVf8dHfOhJ0ADMXyFnMc53clg==", - "dev": true, - "dependencies": { - "@typescript-eslint/types": "8.0.0-alpha.30", - "@typescript-eslint/visitor-keys": "8.0.0-alpha.30" - }, - "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/@typescript-eslint/utils/node_modules/@typescript-eslint/types": { - "version": "8.0.0-alpha.30", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.0.0-alpha.30.tgz", - "integrity": "sha512-4WzLlw27SO9pK9UFj/Hu7WGo8WveT0SEiIpFVsV2WwtQmLps6kouwtVCB8GJPZKJyurhZhcqCoQVQFmpv441Vg==", + "node_modules/@typescript-eslint/types": { + "version": "8.0.0-alpha.42", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.0.0-alpha.42.tgz", + "integrity": "sha512-cvfuxLiSVi6EfsgE/1A07JD67pnv+Grf9YMhGAKUsokIvsMcusLSI1h2On6qoyZghJuFXkH3hiMsg7DtxZBtsw==", "dev": true, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -2816,14 +2782,14 @@ "url": "https://opencollective.com/typescript-eslint" } }, - "node_modules/@typescript-eslint/utils/node_modules/@typescript-eslint/typescript-estree": { - "version": "8.0.0-alpha.30", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.0.0-alpha.30.tgz", - "integrity": "sha512-WSXbc9ZcXI+7yC+6q95u77i8FXz6HOLsw3ST+vMUlFy1lFbXyFL/3e6HDKQCm2Clt0krnoCPiTGvIn+GkYPn4Q==", + "node_modules/@typescript-eslint/typescript-estree": { + "version": "8.0.0-alpha.42", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.0.0-alpha.42.tgz", + "integrity": "sha512-rIHLylSgsfY5hTE68hd8UXcacZxOq4DWAitRKF8xs33hEBDyxInj4FtUglYU420HvFqyVFtVdB7WEFY4cFQ+iA==", "dev": true, "dependencies": { - "@typescript-eslint/types": "8.0.0-alpha.30", - "@typescript-eslint/visitor-keys": "8.0.0-alpha.30", + "@typescript-eslint/types": "8.0.0-alpha.42", + "@typescript-eslint/visitor-keys": "8.0.0-alpha.42", "debug": "^4.3.4", "globby": "^11.1.0", "is-glob": "^4.0.3", @@ -2844,14 +2810,16 @@ } } }, - "node_modules/@typescript-eslint/utils/node_modules/@typescript-eslint/visitor-keys": { - "version": "8.0.0-alpha.30", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.0.0-alpha.30.tgz", - "integrity": "sha512-XZuNurZxBqmr6ZIRIwWFq7j5RZd6ZlkId/HZEWyfciK+CWoyOxSF9Pv2VXH9Rlu2ZG2PfbhLz2Veszl4Pfn7yA==", + "node_modules/@typescript-eslint/utils": { + "version": "8.0.0-alpha.42", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.0.0-alpha.42.tgz", + "integrity": "sha512-ousp9L07jDosMqnayZNF8QOJB2FDZP7lSN2lUI7BknV5B1beUoPizWZl0yDHxrk64ldZu5JoqkhAbOcbPNJu5Q==", "dev": true, "dependencies": { - "@typescript-eslint/types": "8.0.0-alpha.30", - "eslint-visitor-keys": "^3.4.3" + "@eslint-community/eslint-utils": "^4.4.0", + "@typescript-eslint/scope-manager": "8.0.0-alpha.42", + "@typescript-eslint/types": "8.0.0-alpha.42", + "@typescript-eslint/typescript-estree": "8.0.0-alpha.42" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -2859,21 +2827,26 @@ "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0" } }, - "node_modules/@typescript-eslint/utils/node_modules/minimatch": { - "version": "9.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.4.tgz", - "integrity": "sha512-KqWh+VchfxcMNRAJjj2tnsSJdNbHsVgnkBhTNrW7AjVo6OvLtxw8zfT9oLw1JSohlFzJ8jCoTgaoXvJ+kHt6fw==", + "node_modules/@typescript-eslint/visitor-keys": { + "version": "8.0.0-alpha.42", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.0.0-alpha.42.tgz", + "integrity": "sha512-Bf/BObckzDnCS9AslkTsuH1vU+h4rppUrmPbTbhGlPurmss6Lt/Ft9H8vQ8wXeN8rk0drRhML2Feo6aODLeKdA==", "dev": true, "dependencies": { - "brace-expansion": "^2.0.1" + "@typescript-eslint/types": "8.0.0-alpha.42", + "eslint-visitor-keys": "^3.4.3" }, "engines": { - "node": ">=16 || 14 >=14.17" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { - "url": "https://github.com/sponsors/isaacs" + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" } }, "node_modules/@vladfrangu/async_event_emitter": { @@ -3089,12 +3062,12 @@ } }, "node_modules/braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", "dev": true, "dependencies": { - "fill-range": "^7.0.1" + "fill-range": "^7.1.1" }, "engines": { "node": ">=8" @@ -3844,9 +3817,9 @@ } }, "node_modules/fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", "dev": true, "dependencies": { "to-regex-range": "^5.0.1" @@ -4412,12 +4385,12 @@ } }, "node_modules/micromatch": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", - "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.7.tgz", + "integrity": "sha512-LPP/3KorzCwBxfeUuZmaR6bG2kdeHSbe0P2tY3FLRU4vYrjYz5hI4QZwV0njUx3jeuKe67YukQ1LSPZBKDqO/Q==", "dev": true, "dependencies": { - "braces": "^3.0.2", + "braces": "^3.0.3", "picomatch": "^2.3.1" }, "engines": { @@ -4443,6 +4416,21 @@ "node": ">= 0.6" } }, + "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/moment": { "version": "2.30.1", "resolved": "https://registry.npmjs.org/moment/-/moment-2.30.1.tgz", @@ -5408,14 +5396,14 @@ } }, "node_modules/typescript-eslint": { - "version": "8.0.0-alpha.30", - "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.0.0-alpha.30.tgz", - "integrity": "sha512-/vGhBMsK1TpadQh1eQ02c5pyiPGmKR9cVzX5C9plZ+LC0HPLpWoJbbTVfQN7BkIK7tUxDt2BFr3pFL5hDDrx7g==", + "version": "8.0.0-alpha.42", + "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.0.0-alpha.42.tgz", + "integrity": "sha512-lD1yEYS0hGOtRheGp7Lyze2r6AQgJeKHjpNyVlXkYEQgDCs9dPlO2VF9/WMvdA1d3TPa24hVGlUcKJ34G5jNKQ==", "dev": true, "dependencies": { - "@typescript-eslint/eslint-plugin": "8.0.0-alpha.30", - "@typescript-eslint/parser": "8.0.0-alpha.30", - "@typescript-eslint/utils": "8.0.0-alpha.30" + "@typescript-eslint/eslint-plugin": "8.0.0-alpha.42", + "@typescript-eslint/parser": "8.0.0-alpha.42", + "@typescript-eslint/utils": "8.0.0-alpha.42" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -5430,157 +5418,6 @@ } } }, - "node_modules/typescript-eslint/node_modules/@typescript-eslint/eslint-plugin": { - "version": "8.0.0-alpha.30", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.0.0-alpha.30.tgz", - "integrity": "sha512-2CBUupdkfbE3eATph4QeZejvT+M+1bVur+zXlVx09WN31phap51ps/qemeclnCbGEz6kTgBDmScrr9XmmF8/Pg==", - "dev": true, - "dependencies": { - "@eslint-community/regexpp": "^4.10.0", - "@typescript-eslint/scope-manager": "8.0.0-alpha.30", - "@typescript-eslint/type-utils": "8.0.0-alpha.30", - "@typescript-eslint/utils": "8.0.0-alpha.30", - "@typescript-eslint/visitor-keys": "8.0.0-alpha.30", - "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.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "@typescript-eslint/parser": "^8.0.0 || ^8.0.0-alpha.0", - "eslint": "^8.57.0 || ^9.0.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/typescript-eslint/node_modules/@typescript-eslint/parser": { - "version": "8.0.0-alpha.30", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.0.0-alpha.30.tgz", - "integrity": "sha512-tAYgFmgXU1MlCK3nbblUvJlDSibBvxtAQXGrF3IG0KmnRza9FXILZifHWL0rrwacDn40K53K607Fk2QkMjiGgw==", - "dev": true, - "dependencies": { - "@typescript-eslint/scope-manager": "8.0.0-alpha.30", - "@typescript-eslint/types": "8.0.0-alpha.30", - "@typescript-eslint/typescript-estree": "8.0.0-alpha.30", - "@typescript-eslint/visitor-keys": "8.0.0-alpha.30", - "debug": "^4.3.4" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^8.57.0 || ^9.0.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/typescript-eslint/node_modules/@typescript-eslint/scope-manager": { - "version": "8.0.0-alpha.30", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.0.0-alpha.30.tgz", - "integrity": "sha512-FGW/iPWGyPFamAVZ60oCAthMqQrqafUGebF8UKuq/ha+e9SVG6YhJoRzurlQXOVf8dHfOhJ0ADMXyFnMc53clg==", - "dev": true, - "dependencies": { - "@typescript-eslint/types": "8.0.0-alpha.30", - "@typescript-eslint/visitor-keys": "8.0.0-alpha.30" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/typescript-eslint/node_modules/@typescript-eslint/types": { - "version": "8.0.0-alpha.30", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.0.0-alpha.30.tgz", - "integrity": "sha512-4WzLlw27SO9pK9UFj/Hu7WGo8WveT0SEiIpFVsV2WwtQmLps6kouwtVCB8GJPZKJyurhZhcqCoQVQFmpv441Vg==", - "dev": true, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/typescript-eslint/node_modules/@typescript-eslint/typescript-estree": { - "version": "8.0.0-alpha.30", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.0.0-alpha.30.tgz", - "integrity": "sha512-WSXbc9ZcXI+7yC+6q95u77i8FXz6HOLsw3ST+vMUlFy1lFbXyFL/3e6HDKQCm2Clt0krnoCPiTGvIn+GkYPn4Q==", - "dev": true, - "dependencies": { - "@typescript-eslint/types": "8.0.0-alpha.30", - "@typescript-eslint/visitor-keys": "8.0.0-alpha.30", - "debug": "^4.3.4", - "globby": "^11.1.0", - "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.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/typescript-eslint/node_modules/@typescript-eslint/visitor-keys": { - "version": "8.0.0-alpha.30", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.0.0-alpha.30.tgz", - "integrity": "sha512-XZuNurZxBqmr6ZIRIwWFq7j5RZd6ZlkId/HZEWyfciK+CWoyOxSF9Pv2VXH9Rlu2ZG2PfbhLz2Veszl4Pfn7yA==", - "dev": true, - "dependencies": { - "@typescript-eslint/types": "8.0.0-alpha.30", - "eslint-visitor-keys": "^3.4.3" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/typescript-eslint/node_modules/minimatch": { - "version": "9.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.4.tgz", - "integrity": "sha512-KqWh+VchfxcMNRAJjj2tnsSJdNbHsVgnkBhTNrW7AjVo6OvLtxw8zfT9oLw1JSohlFzJ8jCoTgaoXvJ+kHt6fw==", - "dev": true, - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, "node_modules/undefsafe": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/undefsafe/-/undefsafe-2.0.5.tgz", diff --git a/package.json b/package.json index c996e806..c488f465 100644 --- a/package.json +++ b/package.json @@ -47,7 +47,7 @@ "prettier": "^3.3.2", "ts-node": "^10.4.0", "typescript": "^5.4.5", - "typescript-eslint": "^8.0.0-alpha.30" + "typescript-eslint": "^8.0.0-alpha.42" }, "engines": { "node": "18.x" From 9ffd5722fc47794c01079c2fc1f43815ce1fa88c Mon Sep 17 00:00:00 2001 From: ExampleWasTaken <58574351+ExampleWasTaken@users.noreply.github.com> Date: Sat, 27 Jul 2024 19:43:32 +0200 Subject: [PATCH 43/82] bump ts-eslint --- package-lock.json | 338 +++++++++++++++++++++------------------------- package.json | 9 +- 2 files changed, 157 insertions(+), 190 deletions(-) diff --git a/package-lock.json b/package-lock.json index 668e3d41..1a73ee5e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -23,21 +23,22 @@ "winston": "^3.3.4" }, "devDependencies": { - "@eslint/js": "^9.3.0", + "@eslint/js": "^9.8.0", "@types/bad-words": "^3.0.3", "@types/config": "^3.3.1", + "@types/eslint__js": "^8.42.3", "@types/jsdom": "^21.1.6", "@types/node": "^18.0.0", "@types/node-fetch": "^2.6.10", "dotenv": "^16.0.0", - "eslint": "^9.4.0", + "eslint": "^9.8.0", "eslint-config-prettier": "^9.1.0", "eslint-plugin-prettier": "^5.1.3", "nodemon": "^3.0.2", "prettier": "^3.3.2", "ts-node": "^10.4.0", - "typescript": "^5.4.5", - "typescript-eslint": "^8.0.0-alpha.42" + "typescript": "^5.5.4", + "typescript-eslint": "^8.0.0-alpha.54" }, "engines": { "node": "18.x" @@ -1613,50 +1614,28 @@ } }, "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.0", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.11.0.tgz", + "integrity": "sha512-G/M/tIiMrTAxEWRfLfQJMmGNX28IxBg4PBz8XqQhqUHLFI6TL2htpIB1iQCj144V5ee/JaKyT9/WZ0MGZWfA7A==", "dev": true, "engines": { "node": "^12.0.0 || ^14.0.0 || >=16.0.0" } }, "node_modules/@eslint/config-array": { - "version": "0.15.1", - "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.15.1.tgz", - "integrity": "sha512-K4gzNq+yymn/EVsXYmf+SBcBro8MTf+aXJZUphM96CdzUEr+ClGDvAbpmaEK+cGVigVXIgs9gNmvHAlrzzY5JQ==", + "version": "0.17.1", + "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.17.1.tgz", + "integrity": "sha512-BlYOpej8AQ8Ev9xVqroV7a02JK3SkBAaN9GfMMH9W6Ch8FlQlkjGw4Ir7+FgYwfirivAf4t+GtzuAxqfukmISA==", "dev": true, "dependencies": { - "@eslint/object-schema": "^2.1.3", + "@eslint/object-schema": "^2.1.4", "debug": "^4.3.1", - "minimatch": "^3.0.5" + "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, - "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, - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, "node_modules/@eslint/eslintrc": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.1.0.tgz", @@ -1680,32 +1659,10 @@ "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, - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "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, - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, "node_modules/@eslint/js": { - "version": "9.4.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.4.0.tgz", - "integrity": "sha512-fdI7VJjP3Rvc70lC4xkFXHB0fiPeojiL1PxVG6t1ZvXQrarj893PweuBTujxDUFk0Fxj4R7PIIAZ/aiiyZPZcg==", + "version": "9.8.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.8.0.tgz", + "integrity": "sha512-MfluB7EUfxXtv3i/++oh89uzAr4PDI4nn201hsp+qaXqsjAWzinlZEHEfPgAX4doIlKvPG/i0A9dpKxOLII8yA==", "dev": true, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -2605,6 +2562,31 @@ "integrity": "sha512-BB8DBAud88EgiAKlz8WQStzI771Kb6F3j4dioRJ4GD+tP4tzcZyMlz86aXuZT4s9hyesFORehMQE6eqtA5O+Vg==", "dev": true }, + "node_modules/@types/eslint": { + "version": "9.6.0", + "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-9.6.0.tgz", + "integrity": "sha512-gi6WQJ7cHRgZxtkQEoyHMppPjq9Kxo5Tjn2prSKDSmZrCz8TZ3jSRCeTJm+WoM+oB0WG37bRqLzaaU3q7JypGg==", + "dev": true, + "dependencies": { + "@types/estree": "*", + "@types/json-schema": "*" + } + }, + "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, + "dependencies": { + "@types/eslint": "*" + } + }, + "node_modules/@types/estree": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.5.tgz", + "integrity": "sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==", + "dev": true + }, "node_modules/@types/jsdom": { "version": "21.1.6", "resolved": "https://registry.npmjs.org/@types/jsdom/-/jsdom-21.1.6.tgz", @@ -2616,6 +2598,12 @@ "parse5": "^7.0.0" } }, + "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 + }, "node_modules/@types/node": { "version": "18.19.6", "resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.6.tgz", @@ -2668,16 +2656,16 @@ } }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "8.0.0-alpha.42", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.0.0-alpha.42.tgz", - "integrity": "sha512-la2sVBOUd6oKsSXSrLgDTu0+m6+TeA3YodHtPqUY231ETdd835hWbJkyVU893MWRRDuOyC09I528RRiGjBAODA==", + "version": "8.0.0-alpha.54", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.0.0-alpha.54.tgz", + "integrity": "sha512-JBuk5rdo9XfoAc797uPh2QdzfnbQmYTnOZ//IKiXm96a2AzS05VmXSVka4GQyrp7giGWSNjW6y2wPpsWheqd9Q==", "dev": true, "dependencies": { "@eslint-community/regexpp": "^4.10.0", - "@typescript-eslint/scope-manager": "8.0.0-alpha.42", - "@typescript-eslint/type-utils": "8.0.0-alpha.42", - "@typescript-eslint/utils": "8.0.0-alpha.42", - "@typescript-eslint/visitor-keys": "8.0.0-alpha.42", + "@typescript-eslint/scope-manager": "8.0.0-alpha.54", + "@typescript-eslint/type-utils": "8.0.0-alpha.54", + "@typescript-eslint/utils": "8.0.0-alpha.54", + "@typescript-eslint/visitor-keys": "8.0.0-alpha.54", "graphemer": "^1.4.0", "ignore": "^5.3.1", "natural-compare": "^1.4.0", @@ -2701,15 +2689,15 @@ } }, "node_modules/@typescript-eslint/parser": { - "version": "8.0.0-alpha.42", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.0.0-alpha.42.tgz", - "integrity": "sha512-lOUDE+wJwQMq+/KJFCNo9SkJvQ1WGyoubucCWtgDHzr2itfmg0c51Z1wZLyeLSVBsHAWSiR+TIsGoCpHy+5D5Q==", + "version": "8.0.0-alpha.54", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.0.0-alpha.54.tgz", + "integrity": "sha512-473V2mTNH+KPNVPj8MIGizDXmmJ56gpYsh+ILa8uEWUYMhvE0DNnozEt59TonS1Y9D15AJZGas6+1hcpQ77Dbg==", "dev": true, "dependencies": { - "@typescript-eslint/scope-manager": "8.0.0-alpha.42", - "@typescript-eslint/types": "8.0.0-alpha.42", - "@typescript-eslint/typescript-estree": "8.0.0-alpha.42", - "@typescript-eslint/visitor-keys": "8.0.0-alpha.42", + "@typescript-eslint/scope-manager": "8.0.0-alpha.54", + "@typescript-eslint/types": "8.0.0-alpha.54", + "@typescript-eslint/typescript-estree": "8.0.0-alpha.54", + "@typescript-eslint/visitor-keys": "8.0.0-alpha.54", "debug": "^4.3.4" }, "engines": { @@ -2729,13 +2717,13 @@ } }, "node_modules/@typescript-eslint/scope-manager": { - "version": "8.0.0-alpha.42", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.0.0-alpha.42.tgz", - "integrity": "sha512-3nS6VEzxUPEMvqadRaGkjZuL+fsjNf5lCYbvS0IQYzqJl7338yhxvPCraHmXe/xlB08p+5BAd6JYAbkTeSXxJw==", + "version": "8.0.0-alpha.54", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.0.0-alpha.54.tgz", + "integrity": "sha512-z+5GlCAskUTTWOFF2G7olTyKZyn+AVdDkiNCP2fhDtOCV1ePX1EaXy1uwqRRROf8p8uryj7vR7OtIErZE5yAng==", "dev": true, "dependencies": { - "@typescript-eslint/types": "8.0.0-alpha.42", - "@typescript-eslint/visitor-keys": "8.0.0-alpha.42" + "@typescript-eslint/types": "8.0.0-alpha.54", + "@typescript-eslint/visitor-keys": "8.0.0-alpha.54" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -2746,13 +2734,13 @@ } }, "node_modules/@typescript-eslint/type-utils": { - "version": "8.0.0-alpha.42", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.0.0-alpha.42.tgz", - "integrity": "sha512-vmmJgOHycCTUe/d7DdbBkhz1NAJ08wVptyFP17pcmagIq2oTTan9ffIMbIxCKepGi0l5UzdSGf3l9IYZ+xjD8w==", + "version": "8.0.0-alpha.54", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.0.0-alpha.54.tgz", + "integrity": "sha512-aGqNg1vP3a1tAE7lN8VDw+JhAefhqotMEcxw+2NKQm3vG4BqzIQNeF87xle9+94t8MPPmUPzRjRmO7GySu8LRg==", "dev": true, "dependencies": { - "@typescript-eslint/typescript-estree": "8.0.0-alpha.42", - "@typescript-eslint/utils": "8.0.0-alpha.42", + "@typescript-eslint/typescript-estree": "8.0.0-alpha.54", + "@typescript-eslint/utils": "8.0.0-alpha.54", "debug": "^4.3.4", "ts-api-utils": "^1.3.0" }, @@ -2770,9 +2758,9 @@ } }, "node_modules/@typescript-eslint/types": { - "version": "8.0.0-alpha.42", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.0.0-alpha.42.tgz", - "integrity": "sha512-cvfuxLiSVi6EfsgE/1A07JD67pnv+Grf9YMhGAKUsokIvsMcusLSI1h2On6qoyZghJuFXkH3hiMsg7DtxZBtsw==", + "version": "8.0.0-alpha.54", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.0.0-alpha.54.tgz", + "integrity": "sha512-p4CGzb2UW2tJgk7zRL1Iwyd4qMuPnF2TL5/VdEcz2KANHkTReagQ6B3MzJGcuNIK7t+ysolZZILJpj+8cHBzsQ==", "dev": true, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -2783,13 +2771,13 @@ } }, "node_modules/@typescript-eslint/typescript-estree": { - "version": "8.0.0-alpha.42", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.0.0-alpha.42.tgz", - "integrity": "sha512-rIHLylSgsfY5hTE68hd8UXcacZxOq4DWAitRKF8xs33hEBDyxInj4FtUglYU420HvFqyVFtVdB7WEFY4cFQ+iA==", + "version": "8.0.0-alpha.54", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.0.0-alpha.54.tgz", + "integrity": "sha512-oCgHCQm88pBx9QwfGVE42LXVRG3M5PUIP4w521yGMijHn5FEt+E/NGMPU3NXWKUvp0LpEkxABSinYdz69aZITA==", "dev": true, "dependencies": { - "@typescript-eslint/types": "8.0.0-alpha.42", - "@typescript-eslint/visitor-keys": "8.0.0-alpha.42", + "@typescript-eslint/types": "8.0.0-alpha.54", + "@typescript-eslint/visitor-keys": "8.0.0-alpha.54", "debug": "^4.3.4", "globby": "^11.1.0", "is-glob": "^4.0.3", @@ -2810,16 +2798,40 @@ } } }, + "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": "8.0.0-alpha.42", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.0.0-alpha.42.tgz", - "integrity": "sha512-ousp9L07jDosMqnayZNF8QOJB2FDZP7lSN2lUI7BknV5B1beUoPizWZl0yDHxrk64ldZu5JoqkhAbOcbPNJu5Q==", + "version": "8.0.0-alpha.54", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.0.0-alpha.54.tgz", + "integrity": "sha512-Xu+dl3SJ4NOuzSHpRj1nIJPsoNTcPuG6EFVolrEVl+GZReaiBdexwpTo4/gV64khZEVewEIdYV3FBs5elIjI0g==", "dev": true, "dependencies": { "@eslint-community/eslint-utils": "^4.4.0", - "@typescript-eslint/scope-manager": "8.0.0-alpha.42", - "@typescript-eslint/types": "8.0.0-alpha.42", - "@typescript-eslint/typescript-estree": "8.0.0-alpha.42" + "@typescript-eslint/scope-manager": "8.0.0-alpha.54", + "@typescript-eslint/types": "8.0.0-alpha.54", + "@typescript-eslint/typescript-estree": "8.0.0-alpha.54" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -2833,12 +2845,12 @@ } }, "node_modules/@typescript-eslint/visitor-keys": { - "version": "8.0.0-alpha.42", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.0.0-alpha.42.tgz", - "integrity": "sha512-Bf/BObckzDnCS9AslkTsuH1vU+h4rppUrmPbTbhGlPurmss6Lt/Ft9H8vQ8wXeN8rk0drRhML2Feo6aODLeKdA==", + "version": "8.0.0-alpha.54", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.0.0-alpha.54.tgz", + "integrity": "sha512-lS8wrI6Vxw6ebIi+ehocAjXLG43bN5JCC8+wtGDD3Xw9O/EVpanAVdftefJs/mlK87eyccvVIiiHgD294TpIEQ==", "dev": true, "dependencies": { - "@typescript-eslint/types": "8.0.0-alpha.42", + "@typescript-eslint/types": "8.0.0-alpha.54", "eslint-visitor-keys": "^3.4.3" }, "engines": { @@ -2865,9 +2877,9 @@ "dev": true }, "node_modules/acorn": { - "version": "8.11.3", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.3.tgz", - "integrity": "sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==", + "version": "8.12.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.12.1.tgz", + "integrity": "sha512-tcpGyI9zbizT9JbV6oYE477V6mTlXvvi0T0G3SNIYE2apm/G5huBa1+K89VGeovbg+jycCrfhl3ADxErOuO6Jg==", "dev": true, "bin": { "acorn": "bin/acorn" @@ -3053,12 +3065,13 @@ "integrity": "sha512-AlcaJBi/pqqJBIQ8U9Mcpc9i8Aqxn88Skv5d+xBX006BY5u8N3mGLHa5Lgppa7L/HfwgwLgZ6NYs+Ag6uUmJRA==" }, "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==", + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", "dev": true, "dependencies": { - "balanced-match": "^1.0.0" + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" } }, "node_modules/braces": { @@ -3485,16 +3498,16 @@ } }, "node_modules/eslint": { - "version": "9.4.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.4.0.tgz", - "integrity": "sha512-sjc7Y8cUD1IlwYcTS9qPSvGjAC8Ne9LctpxKKu3x/1IC9bnOg98Zy6GxEJUfr1NojMgVPlyANXYns8oE2c1TAA==", + "version": "9.8.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.8.0.tgz", + "integrity": "sha512-K8qnZ/QJzT2dLKdZJVX6W4XOwBzutMYmt0lqUS+JdXgd+HTYFlonFgkJ8s44d/zMPPCnOOk0kMWCApCPhiOy9A==", "dev": true, "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", - "@eslint-community/regexpp": "^4.6.1", - "@eslint/config-array": "^0.15.1", + "@eslint-community/regexpp": "^4.11.0", + "@eslint/config-array": "^0.17.1", "@eslint/eslintrc": "^3.1.0", - "@eslint/js": "9.4.0", + "@eslint/js": "9.8.0", "@humanwhocodes/module-importer": "^1.0.1", "@humanwhocodes/retry": "^0.3.0", "@nodelib/fs.walk": "^1.2.8", @@ -3503,10 +3516,10 @@ "cross-spawn": "^7.0.2", "debug": "^4.3.2", "escape-string-regexp": "^4.0.0", - "eslint-scope": "^8.0.1", + "eslint-scope": "^8.0.2", "eslint-visitor-keys": "^4.0.0", - "espree": "^10.0.1", - "esquery": "^1.4.2", + "espree": "^10.1.0", + "esquery": "^1.5.0", "esutils": "^2.0.2", "fast-deep-equal": "^3.1.3", "file-entry-cache": "^8.0.0", @@ -3532,7 +3545,7 @@ "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { - "url": "https://opencollective.com/eslint" + "url": "https://eslint.org/donate" } }, "node_modules/eslint-config-prettier": { @@ -3578,9 +3591,9 @@ } }, "node_modules/eslint-scope": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.0.1.tgz", - "integrity": "sha512-pL8XjgP4ZOmmwfFE8mEhSxA7ZY4C+LWyqjQ3o4yWkkmD0qcMT9kkW3zWHOczhWcjTSgqycYAgwSlXvZltv65og==", + "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, "dependencies": { "esrecurse": "^4.3.0", @@ -3605,16 +3618,6 @@ "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, - "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", @@ -3639,25 +3642,13 @@ "node": ">=10.13.0" } }, - "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, - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, "node_modules/espree": { - "version": "10.0.1", - "resolved": "https://registry.npmjs.org/espree/-/espree-10.0.1.tgz", - "integrity": "sha512-MWkrWZbJsL2UwnjxTX3gG8FneachS/Mwg7tdGXce011sJd5b0JG54vat5KHnfSBODZ3Wvzd2WnjxyzsRoVv+ww==", + "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, "dependencies": { - "acorn": "^8.11.3", + "acorn": "^8.12.0", "acorn-jsx": "^5.3.2", "eslint-visitor-keys": "^4.0.0" }, @@ -4417,18 +4408,15 @@ } }, "node_modules/minimatch": { - "version": "9.0.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", - "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", "dev": true, "dependencies": { - "brace-expansion": "^2.0.1" + "brace-expansion": "^1.1.7" }, "engines": { - "node": ">=16 || 14 >=14.17" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" + "node": "*" } }, "node_modules/moment": { @@ -4640,16 +4628,6 @@ "url": "https://opencollective.com/nodemon" } }, - "node_modules/nodemon/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, - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, "node_modules/nodemon/node_modules/has-flag": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", @@ -4659,18 +4637,6 @@ "node": ">=4" } }, - "node_modules/nodemon/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, - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, "node_modules/nodemon/node_modules/supports-color": { "version": "5.5.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", @@ -5383,9 +5349,9 @@ } }, "node_modules/typescript": { - "version": "5.4.5", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.4.5.tgz", - "integrity": "sha512-vcI4UpRgg81oIRUFwR0WSIHKt11nJ7SAVlYNIu+QpqeyXP+gpQJy/Z4+F0aGxSE4MqwjyXvW/TzgkLAx2AGHwQ==", + "version": "5.5.4", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.5.4.tgz", + "integrity": "sha512-Mtq29sKDAEYP7aljRgtPOpTvOfbwRWlS6dPRzwjdE+C0R4brX/GUyhHSecbHMFLNBLcJIPt9nl9yG5TZ1weH+Q==", "dev": true, "bin": { "tsc": "bin/tsc", @@ -5396,14 +5362,14 @@ } }, "node_modules/typescript-eslint": { - "version": "8.0.0-alpha.42", - "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.0.0-alpha.42.tgz", - "integrity": "sha512-lD1yEYS0hGOtRheGp7Lyze2r6AQgJeKHjpNyVlXkYEQgDCs9dPlO2VF9/WMvdA1d3TPa24hVGlUcKJ34G5jNKQ==", + "version": "8.0.0-alpha.54", + "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.0.0-alpha.54.tgz", + "integrity": "sha512-5rTqLSAgzum8W0dIh8jgDosXNQufhfc9pyDXaBpBTgwtTypBzrcRgCz8Xp0XKrpSBCuLdfFt+X/ueEnoqrOcJA==", "dev": true, "dependencies": { - "@typescript-eslint/eslint-plugin": "8.0.0-alpha.42", - "@typescript-eslint/parser": "8.0.0-alpha.42", - "@typescript-eslint/utils": "8.0.0-alpha.42" + "@typescript-eslint/eslint-plugin": "8.0.0-alpha.54", + "@typescript-eslint/parser": "8.0.0-alpha.54", + "@typescript-eslint/utils": "8.0.0-alpha.54" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" diff --git a/package.json b/package.json index c488f465..56102d8d 100644 --- a/package.json +++ b/package.json @@ -33,21 +33,22 @@ "winston": "^3.3.4" }, "devDependencies": { - "@eslint/js": "^9.3.0", + "@eslint/js": "^9.8.0", "@types/bad-words": "^3.0.3", "@types/config": "^3.3.1", + "@types/eslint__js": "^8.42.3", "@types/jsdom": "^21.1.6", "@types/node": "^18.0.0", "@types/node-fetch": "^2.6.10", "dotenv": "^16.0.0", - "eslint": "^9.4.0", + "eslint": "^9.8.0", "eslint-config-prettier": "^9.1.0", "eslint-plugin-prettier": "^5.1.3", "nodemon": "^3.0.2", "prettier": "^3.3.2", "ts-node": "^10.4.0", - "typescript": "^5.4.5", - "typescript-eslint": "^8.0.0-alpha.42" + "typescript": "^5.5.4", + "typescript-eslint": "^8.0.0-alpha.54" }, "engines": { "node": "18.x" From 13a35cde637161d19b382e6091bd1933d8194278 Mon Sep 17 00:00:00 2001 From: ExampleWasTaken <58574351+ExampleWasTaken@users.noreply.github.com> Date: Mon, 5 Aug 2024 22:22:05 +0200 Subject: [PATCH 44/82] bump to typescript-eslint v8 --- package-lock.json | 4 +++- package.json | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index f549625f..c070c14f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -38,7 +38,7 @@ "prettier": "^3.3.2", "ts-node": "^10.4.0", "typescript": "^5.5.4", - "typescript-eslint": "^8.0.0-alpha.54" + "typescript-eslint": "^8.0.1" }, "engines": { "node": "18.x" @@ -1715,6 +1715,7 @@ "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.8.0.tgz", "integrity": "sha512-MfluB7EUfxXtv3i/++oh89uzAr4PDI4nn201hsp+qaXqsjAWzinlZEHEfPgAX4doIlKvPG/i0A9dpKxOLII8yA==", "dev": true, + "license": "MIT", "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } @@ -5487,6 +5488,7 @@ "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" diff --git a/package.json b/package.json index 56102d8d..7c1173b2 100644 --- a/package.json +++ b/package.json @@ -48,7 +48,7 @@ "prettier": "^3.3.2", "ts-node": "^10.4.0", "typescript": "^5.5.4", - "typescript-eslint": "^8.0.0-alpha.54" + "typescript-eslint": "^8.0.1" }, "engines": { "node": "18.x" From c96c2d2e98188650cd57017565af02393c29f685 Mon Sep 17 00:00:00 2001 From: ExampleWasTaken <58574351+ExampleWasTaken@users.noreply.github.com> Date: Wed, 7 Aug 2024 01:46:00 +0200 Subject: [PATCH 45/82] pin ts --- package-lock.json | 8 ++++---- package.json | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package-lock.json b/package-lock.json index c070c14f..74acfa1b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -37,7 +37,7 @@ "nodemon": "^3.0.2", "prettier": "^3.3.2", "ts-node": "^10.4.0", - "typescript": "^5.5.4", + "typescript": "~5.4.5", "typescript-eslint": "^8.0.1" }, "engines": { @@ -5484,9 +5484,9 @@ } }, "node_modules/typescript": { - "version": "5.5.4", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.5.4.tgz", - "integrity": "sha512-Mtq29sKDAEYP7aljRgtPOpTvOfbwRWlS6dPRzwjdE+C0R4brX/GUyhHSecbHMFLNBLcJIPt9nl9yG5TZ1weH+Q==", + "version": "5.4.5", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.4.5.tgz", + "integrity": "sha512-vcI4UpRgg81oIRUFwR0WSIHKt11nJ7SAVlYNIu+QpqeyXP+gpQJy/Z4+F0aGxSE4MqwjyXvW/TzgkLAx2AGHwQ==", "dev": true, "license": "Apache-2.0", "bin": { diff --git a/package.json b/package.json index 7c1173b2..4752736c 100644 --- a/package.json +++ b/package.json @@ -47,7 +47,7 @@ "nodemon": "^3.0.2", "prettier": "^3.3.2", "ts-node": "^10.4.0", - "typescript": "^5.5.4", + "typescript": "~5.4.5", "typescript-eslint": "^8.0.1" }, "engines": { From cba3c092a8c4a5520dae310e2496baf6ac095f14 Mon Sep 17 00:00:00 2001 From: ExampleWasTaken <58574351+ExampleWasTaken@users.noreply.github.com> Date: Wed, 7 Aug 2024 01:49:57 +0200 Subject: [PATCH 46/82] fix prettier regressions --- .../utils/locate/panels/a32nx/overhead.ts | 35 ++++++++----------- src/commands/utils/locate/panels/panel.ts | 16 ++++----- src/commands/utils/simbriefData.ts | 16 ++++----- 3 files changed, 30 insertions(+), 37 deletions(-) diff --git a/src/commands/utils/locate/panels/a32nx/overhead.ts b/src/commands/utils/locate/panels/a32nx/overhead.ts index 8a1d2448..16da59e4 100644 --- a/src/commands/utils/locate/panels/a32nx/overhead.ts +++ b/src/commands/utils/locate/panels/a32nx/overhead.ts @@ -117,27 +117,20 @@ export const fltCtlPanel: Panel = { }; export const adirsPanel: Panel = { - name: 'ADIRS Panel', - title: 'FlyByWire A32NX | ADIRS Panel', - description: { - name: 'Aligning the ADIRSs', - value: makeLines([ - 'On the overhead panel you will see the three switches under \'ADIRS\'. Turn these three to the \'NAV\' position. It takes several minutes for the ADIRUs to align.', - 'You can check how long you have to wait by looking at the align time on your Upper Ecam.', - ]), - inline: false, - }, - docsUrl: `${OVHD_DOCS_BASE_URL}/adirs/`, - flightDeckUrl: LOCATE_DOCS_BASE_URLS.a32nx.flightdeck, - imageUrl: `${OVHD_IMAGE_BASE_URL}/adirs.png`, - identifiers: [ - 'adirs-panel', - 'adirs', - 'adiru', - 'irs', - 'adr', - 'ir-selector', - ], + name: 'ADIRS Panel', + title: 'FlyByWire A32NX | ADIRS Panel', + description: { + name: 'Aligning the ADIRSs', + value: makeLines([ + "On the overhead panel you will see the three switches under 'ADIRS'. Turn these three to the 'NAV' position. It takes several minutes for the ADIRUs to align.", + 'You can check how long you have to wait by looking at the align time on your Upper Ecam.', + ]), + inline: false, + }, + docsUrl: `${OVHD_DOCS_BASE_URL}/adirs/`, + flightDeckUrl: LOCATE_DOCS_BASE_URLS.a32nx.flightdeck, + imageUrl: `${OVHD_IMAGE_BASE_URL}/adirs.png`, + identifiers: ['adirs-panel', 'adirs', 'adiru', 'irs', 'adr', 'ir-selector'], }; export const paVideoPanel: Panel = { diff --git a/src/commands/utils/locate/panels/panel.ts b/src/commands/utils/locate/panels/panel.ts index 5a53245a..296ddf9e 100644 --- a/src/commands/utils/locate/panels/panel.ts +++ b/src/commands/utils/locate/panels/panel.ts @@ -11,15 +11,15 @@ export interface Panel { */ title: string; - /** - * Optional description for a panel such as instructions on aligning the ADIRSs. - */ - description?: EmbedField; + /** + * Optional description for a panel such as instructions on aligning the ADIRSs. + */ + description?: EmbedField; - /** - * The URL to the relevant documentation. - */ - docsUrl: string; + /** + * The URL to the relevant documentation. + */ + docsUrl: string; /** * The URL to documentation of the flight deck this panel belongs to. diff --git a/src/commands/utils/simbriefData.ts b/src/commands/utils/simbriefData.ts index c109e6cd..a51157c5 100644 --- a/src/commands/utils/simbriefData.ts +++ b/src/commands/utils/simbriefData.ts @@ -32,14 +32,14 @@ const data = slashCommandStructure({ const FBW_AIRFRAME_ID = '337364_1631550522735'; const simbriefdatarequestEmbed = makeEmbed({ - title: 'FlyByWire Support | SimBrief Data Request', - description: makeLines([ - 'To evaluate your problem we kindly ask you to enter the following bot command into a new message.', - '```/simbrief-data retrieve```', - 'Enter your `pilotId` with your simbrief pilotId or userName (as set in the EFB settings). The Bot will read your last generated flight plan and display some details about it including the route.', - '', - '**Privacy notice**: If you share your pilotId or username it is possible to read your pilot name from the API the bot uses. This pilot name is by default your real name, but you can change it in the flight edit screen or your user profile in SimBrief. No data is stored by FlyByWire when using the command.', - ]), + title: 'FlyByWire Support | SimBrief Data Request', + description: makeLines([ + 'To evaluate your problem we kindly ask you to enter the following bot command into a new message.', + '```/simbrief-data retrieve```', + 'Enter your `pilotId` with your simbrief pilotId or userName (as set in the EFB settings). The Bot will read your last generated flight plan and display some details about it including the route.', + '', + '**Privacy notice**: If you share your pilotId or username it is possible to read your pilot name from the API the bot uses. This pilot name is by default your real name, but you can change it in the flight edit screen or your user profile in SimBrief. No data is stored by FlyByWire when using the command.', + ]), }); const errorEmbed = (errorMessage: any) => From 7fbe86b7440914a567dc4e11ced4ce2d4b4054f1 Mon Sep 17 00:00:00 2001 From: ExampleWasTaken <58574351+ExampleWasTaken@users.noreply.github.com> Date: Wed, 7 Aug 2024 01:52:48 +0200 Subject: [PATCH 47/82] fix src/ --- src/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/index.ts b/src/index.ts index 68418da1..0b7c9e22 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,3 +1,3 @@ import 'dotenv/config'; -import('./client'); +void import('./client'); From 89e9fc5324a474fcffb6f41c3d1e4ab32ab3ce9d Mon Sep 17 00:00:00 2001 From: ExampleWasTaken <58574351+ExampleWasTaken@users.noreply.github.com> Date: Wed, 7 Aug 2024 02:01:21 +0200 Subject: [PATCH 48/82] update vscode settings and extension recommendations --- .vscode/extensions.json | 7 +++++++ .vscode/settings.json | 31 +++++++++++++++++++++++++++++++ 2 files changed, 38 insertions(+) create mode 100644 .vscode/extensions.json create mode 100644 .vscode/settings.json diff --git a/.vscode/extensions.json b/.vscode/extensions.json new file mode 100644 index 00000000..ffa5bcfc --- /dev/null +++ b/.vscode/extensions.json @@ -0,0 +1,7 @@ +{ + "recommendations": [ + "editorconfig.editorconfig", + "dbaeumer.vscode-eslint", + "esbenp.prettier-vscode" + ] +} diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 00000000..de5a526a --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,31 @@ +{ + "typescript.tsdk": "node_modules\\typescript\\lib", + "eslint.lintTask.enable": true, + "eslint.useFlatConfig": true, + "eslint.format.enable": true, + "editor.formatOnSave": true, + "editor.codeActionsOnSave": { + "source.fixAll.eslint": "explicit" + }, + "typescript.preferences.quoteStyle": "single", + "[yaml]": { + "editor.defaultFormatter": "esbenp.prettier-vscode", + "editor.formatOnSave": true, + }, + "[markdown]": { + "editor.defaultFormatter": "esbenp.prettier-vscode", + "editor.formatOnSave": true + }, + "[json]": { + "editor.defaultFormatter": "esbenp.prettier-vscode", + "editor.formatOnSave": true + }, + "[typescript]": { + "editor.defaultFormatter": "dbaeumer.vscode-eslint", + "editor.formatOnSave": true + }, + "[javascript]": { + "editor.defaultFormatter": "dbaeumer.vscode-eslint", + "editor.formatOnSave": true + }, +} From b5708a451cc60de1eaa2e627d332c1a1573762d4 Mon Sep 17 00:00:00 2001 From: ExampleWasTaken <58574351+ExampleWasTaken@users.noreply.github.com> Date: Wed, 7 Aug 2024 02:02:15 +0200 Subject: [PATCH 49/82] fix prettier (again) --- .github/CHANGELOG.md | 2 +- .vscode/extensions.json | 6 +----- .vscode/settings.json | 4 ++-- 3 files changed, 4 insertions(+), 8 deletions(-) diff --git a/.github/CHANGELOG.md b/.github/CHANGELOG.md index acb6ef89..bfc5a5b3 100644 --- a/.github/CHANGELOG.md +++ b/.github/CHANGELOG.md @@ -1,6 +1,6 @@ ## Changelog -Update _ July 2024 +Update \_ July 2024 - fix: resolve security vulnerabilities in 3rd-party packages (27/07/2024) - fix: corrected typo in the embed for simbrief-data support-request (27/07/2024) diff --git a/.vscode/extensions.json b/.vscode/extensions.json index ffa5bcfc..604a8694 100644 --- a/.vscode/extensions.json +++ b/.vscode/extensions.json @@ -1,7 +1,3 @@ { - "recommendations": [ - "editorconfig.editorconfig", - "dbaeumer.vscode-eslint", - "esbenp.prettier-vscode" - ] + "recommendations": ["editorconfig.editorconfig", "dbaeumer.vscode-eslint", "esbenp.prettier-vscode"] } diff --git a/.vscode/settings.json b/.vscode/settings.json index de5a526a..dd01cc2f 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -10,7 +10,7 @@ "typescript.preferences.quoteStyle": "single", "[yaml]": { "editor.defaultFormatter": "esbenp.prettier-vscode", - "editor.formatOnSave": true, + "editor.formatOnSave": true }, "[markdown]": { "editor.defaultFormatter": "esbenp.prettier-vscode", @@ -27,5 +27,5 @@ "[javascript]": { "editor.defaultFormatter": "dbaeumer.vscode-eslint", "editor.formatOnSave": true - }, + } } From daee70784cdb964bab5ecc4c088aff26a288ba17 Mon Sep 17 00:00:00 2001 From: ExampleWasTaken <58574351+ExampleWasTaken@users.noreply.github.com> Date: Thu, 12 Sep 2024 19:15:46 +0200 Subject: [PATCH 50/82] fix casting --- src/events/buttonHandlers/buttonHandler.ts | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/events/buttonHandlers/buttonHandler.ts b/src/events/buttonHandlers/buttonHandler.ts index b7937745..7607b4d6 100644 --- a/src/events/buttonHandlers/buttonHandler.ts +++ b/src/events/buttonHandlers/buttonHandler.ts @@ -1,3 +1,4 @@ +import { ButtonComponent } from 'discord.js'; import { event, Events } from '../../lib'; import { handleRoleAssignment } from './functions/handleRoleAssignment'; @@ -6,9 +7,10 @@ export default event(Events.InteractionCreate, async ({ log }, interaction) => { log('Button Handler: Button pressed'); - const { customId, component, user } = interaction; + const component = interaction.component as ButtonComponent; + const { customId, user } = interaction; - const buttonLabel = component?.label; + const buttonLabel = component.label; try { const [prefix, ...params] = interaction.customId.split('_'); From 0fc89e3ba4b516d9a7e357bc8bf4353c8125e6ab Mon Sep 17 00:00:00 2001 From: ExampleWasTaken <58574351+ExampleWasTaken@users.noreply.github.com> Date: Thu, 12 Sep 2024 19:58:10 +0200 Subject: [PATCH 51/82] several eslint fixes --- .../utils/birthday/functions/listBirthday.ts | 11 ++++---- .../birthday/functions/removeBirthday.ts | 4 +-- .../utils/birthday/functions/setBirthday.ts | 2 +- src/commands/utils/count.ts | 2 +- src/commands/utils/docSearch.ts | 2 +- src/commands/utils/reportedIssues.ts | 25 +++++++++++++++---- 6 files changed, 31 insertions(+), 15 deletions(-) diff --git a/src/commands/utils/birthday/functions/listBirthday.ts b/src/commands/utils/birthday/functions/listBirthday.ts index 65e52373..47748637 100644 --- a/src/commands/utils/birthday/functions/listBirthday.ts +++ b/src/commands/utils/birthday/functions/listBirthday.ts @@ -1,21 +1,21 @@ -import { ChatInputCommandInteraction } from 'discord.js'; +import { APIEmbedField, ChatInputCommandInteraction, EmbedField } from 'discord.js'; import { Birthday, Logger, makeEmbed } from '../../../../lib'; -const birthdayListEmbed = (fields: Array) => +const birthdayListEmbed = (fields: EmbedField[]) => makeEmbed({ title: 'Birthday - Birthday List', description: fields.length > 0 ? undefined : 'No birthdays set', fields, }); -export async function handleListBirthday(interaction: ChatInputCommandInteraction<'cached'>) { +export async function handleListBirthday(interaction: ChatInputCommandInteraction<'cached'>) { await interaction.deferReply(); try { const birthdays = await Birthday.find({}).sort({ day: 1 }); // Only day sort required, months are bucketized const members = await interaction.guild.members.fetch(); - const monthBuckets: Array> = [ + const monthBuckets: Array<[string, string[]]> = [ ['January', []], ['February', []], ['March', []], @@ -40,13 +40,14 @@ export async function handleListBirthday(interaction: ChatInputCommandInteractio } } - const fields = []; + const fields: EmbedField[] = []; for (const monthBucket of monthBuckets) { if (monthBucket[1].length > 0) { fields.push({ name: monthBucket[0], value: monthBucket[1].join('\n'), + inline: false, }); } } diff --git a/src/commands/utils/birthday/functions/removeBirthday.ts b/src/commands/utils/birthday/functions/removeBirthday.ts index a891bb09..e021b56e 100644 --- a/src/commands/utils/birthday/functions/removeBirthday.ts +++ b/src/commands/utils/birthday/functions/removeBirthday.ts @@ -4,14 +4,14 @@ import { Birthday, makeEmbed } from '../../../../lib'; const noBirthdayEmbed = (discordUser: User) => makeEmbed({ title: 'Birthday remove failed', - description: `${discordUser} doesn't have a birthday set`, + description: `${discordUser.toString()} doesn't have a birthday set`, color: Colors.Red, }); const birthdayRemovedEmbed = (discordUser: User) => makeEmbed({ title: 'Birthday removed', - description: `${discordUser}'s birthday has been removed`, + description: `${discordUser.toString()}'s birthday has been removed`, }); export async function handleRemoveBirthday(interaction: ChatInputCommandInteraction<'cached'>) { diff --git a/src/commands/utils/birthday/functions/setBirthday.ts b/src/commands/utils/birthday/functions/setBirthday.ts index 682fcb38..c5a2615e 100644 --- a/src/commands/utils/birthday/functions/setBirthday.ts +++ b/src/commands/utils/birthday/functions/setBirthday.ts @@ -34,7 +34,7 @@ const invalidDateEmbed = makeEmbed({ const birthdaySetEmbed = (discordUser: User, birthdayDay: number, birthdayMonth: number, birthdayTimezone: number) => makeEmbed({ title: 'Birthday - Birthday Set', - description: `${discordUser}'s birthday has been set to ${birthdayDay}/${birthdayMonth} and their timezone is UTC${birthdayTimezone < 0 ? '' : '+'}${birthdayTimezone}`, + description: `${discordUser.toString()}'s birthday has been set to ${birthdayDay}/${birthdayMonth} and their timezone is UTC${birthdayTimezone < 0 ? '' : '+'}${birthdayTimezone}`, }); export async function handleSetBirthday(interaction: ChatInputCommandInteraction<'cached'>) { diff --git a/src/commands/utils/count.ts b/src/commands/utils/count.ts index 5bc7447a..a6b855ee 100644 --- a/src/commands/utils/count.ts +++ b/src/commands/utils/count.ts @@ -34,7 +34,7 @@ export default slashCommand(data, async ({ interaction }) => { const countNumber = interaction.options.getInteger('number'); - await countThread.send(`${interaction.user} says ${countNumber}`); + await countThread.send(`${interaction.user.toString()} says ${countNumber}`); await interaction.reply({ content: 'Counted!', ephemeral: true }); }); diff --git a/src/commands/utils/docSearch.ts b/src/commands/utils/docSearch.ts index f87d1639..6d4238b3 100644 --- a/src/commands/utils/docSearch.ts +++ b/src/commands/utils/docSearch.ts @@ -35,7 +35,7 @@ export default slashCommand(data, async ({ interaction }) => { color: Colors.Red, }); return interaction.reply({ embeds: [URLEmbed] }); - } catch (_) { + } catch { /**/ } diff --git a/src/commands/utils/reportedIssues.ts b/src/commands/utils/reportedIssues.ts index 4ac03e04..ca54aea8 100644 --- a/src/commands/utils/reportedIssues.ts +++ b/src/commands/utils/reportedIssues.ts @@ -91,8 +91,13 @@ export default slashCommand(data, async ({ interaction }) => { } } + interface ReportedIssue { + id: string; + title: string | null; + } + try { - const reportedIssues: any = []; + const reportedIssues: ReportedIssue[] = []; const dom = await JSDOM.fromURL(`${FBW_DOCS_REPORTED_ISSUES_URL}`); const { document } = dom.window; const h3Elements = document.querySelectorAll('h3'); @@ -111,15 +116,25 @@ export default slashCommand(data, async ({ interaction }) => { } const fields = reportedIssues - .map((sectionElement: any) => subsectionLinkEmbedField(sectionElement.id, sectionElement.title)) + .map((sectionElement) => subsectionLinkEmbedField(sectionElement.id, sectionElement.title ?? '')) .flat(); return interaction.reply({ embeds: [issueInSubsectionEmbed(fields)] }); - } catch (error: any) { + } catch (error) { Logger.error(error); - Logger.error(error.stack); + if (error instanceof Error) { + Logger.error(error.stack); + + const errorEmbed = makeEmbed({ + title: 'Error | Reported Issues', + description: error.message, + color: Colors.Red, + }); + return interaction.reply({ embeds: [errorEmbed] }); + } + const errorEmbed = makeEmbed({ title: 'Error | Reported Issues', - description: error.message, + description: 'An unknown error occurred.', color: Colors.Red, }); return interaction.reply({ embeds: [errorEmbed] }); From 4c329da08c4c5190f25a2d6ccca2c345e880103a Mon Sep 17 00:00:00 2001 From: ExampleWasTaken <58574351+ExampleWasTaken@users.noreply.github.com> Date: Thu, 12 Sep 2024 19:58:57 +0200 Subject: [PATCH 52/82] configure prettier as default formatter for ts/js --- .vscode/settings.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index dd01cc2f..e596331e 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -21,11 +21,11 @@ "editor.formatOnSave": true }, "[typescript]": { - "editor.defaultFormatter": "dbaeumer.vscode-eslint", + "editor.defaultFormatter": "esbenp.prettier-vscode", "editor.formatOnSave": true }, "[javascript]": { - "editor.defaultFormatter": "dbaeumer.vscode-eslint", + "editor.defaultFormatter": "esbenp.prettier-vscode", "editor.formatOnSave": true } } From 6a4852224d018d518da88c7b2e69bd730e3e4823 Mon Sep 17 00:00:00 2001 From: ExampleWasTaken <58574351+ExampleWasTaken@users.noreply.github.com> Date: Thu, 12 Sep 2024 20:00:19 +0200 Subject: [PATCH 53/82] fix prettier --- .../utils/birthday/functions/listBirthday.ts | 2 +- src/commands/utils/simbriefData.ts | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/commands/utils/birthday/functions/listBirthday.ts b/src/commands/utils/birthday/functions/listBirthday.ts index 47748637..12a10db6 100644 --- a/src/commands/utils/birthday/functions/listBirthday.ts +++ b/src/commands/utils/birthday/functions/listBirthday.ts @@ -8,7 +8,7 @@ const birthdayListEmbed = (fields: EmbedField[]) => fields, }); -export async function handleListBirthday(interaction: ChatInputCommandInteraction<'cached'>) { +export async function handleListBirthday(interaction: ChatInputCommandInteraction<'cached'>) { await interaction.deferReply(); try { diff --git a/src/commands/utils/simbriefData.ts b/src/commands/utils/simbriefData.ts index b6c56d60..fe124566 100644 --- a/src/commands/utils/simbriefData.ts +++ b/src/commands/utils/simbriefData.ts @@ -61,12 +61,12 @@ const simbriefEmbed = (flightplan: any) => makeEmbed({ title: 'SimBrief Data', description: makeLines([ - `**Generated at**: ${moment(flightplan.params.time_generated * 1000).format('DD.MM.YYYY, HH:mm:ss')}`, - `**AirFrame**: ${flightplan.aircraft.name} ${flightplan.aircraft.internal_id} ${(flightplan.aircraft.internal_id === FBW_AIRFRAME_ID) ? '(provided by FBW)' : ''}`, - `**AIRAC Cycle**: ${flightplan.params.airac}`, - `**Origin**: ${flightplan.origin.icao_code} ${flightplan.origin.plan_rwy}`, - `**Destination**: ${flightplan.destination.icao_code} ${flightplan.destination.plan_rwy}`, - `**Route**: ${flightplan.general.route}`, + `**Generated at**: ${moment(flightplan.params.time_generated * 1000).format('DD.MM.YYYY, HH:mm:ss')}`, + `**AirFrame**: ${flightplan.aircraft.name} ${flightplan.aircraft.internal_id} ${flightplan.aircraft.internal_id === FBW_AIRFRAME_ID ? '(provided by FBW)' : ''}`, + `**AIRAC Cycle**: ${flightplan.params.airac}`, + `**Origin**: ${flightplan.origin.icao_code} ${flightplan.origin.plan_rwy}`, + `**Destination**: ${flightplan.destination.icao_code} ${flightplan.destination.plan_rwy}`, + `**Route**: ${flightplan.general.route}`, ]), }); From b37065b0fcce309310672193047d577747127ce5 Mon Sep 17 00:00:00 2001 From: ExampleWasTaken <58574351+ExampleWasTaken@users.noreply.github.com> Date: Thu, 12 Sep 2024 20:04:53 +0200 Subject: [PATCH 54/82] fix infractionEmbedPagination.ts --- src/lib/infractionEmbedPagination.ts | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/lib/infractionEmbedPagination.ts b/src/lib/infractionEmbedPagination.ts index e1a972ed..49f26e28 100644 --- a/src/lib/infractionEmbedPagination.ts +++ b/src/lib/infractionEmbedPagination.ts @@ -73,8 +73,8 @@ export async function createPaginatedInfractionEmbedHandler( const filter = (interaction: Interaction) => interaction.user.id === user; const collector = message.createMessageComponentCollector({ filter, time: 120_000 }); - collector.on('collect', async (collectedInteraction: ButtonInteraction) => { - await collectedInteraction.deferUpdate(); + collector.on('collect', (collectedInteraction: ButtonInteraction) => { + void collectedInteraction.deferUpdate(); if (collectedInteraction.customId === 'infractions_about') { currentPage = 0; @@ -92,11 +92,11 @@ export async function createPaginatedInfractionEmbedHandler( currentPage = 6; } - await updateEmbed(); + void updateEmbed(); }); - collector.on('end', async () => { - await handleEmbedExpire(); + collector.on('end', () => { + void handleEmbedExpire(); }); async function updateEmbed() { From 5444e9af695ca4e3a9d1d13acfc88751522ab9ec Mon Sep 17 00:00:00 2001 From: ExampleWasTaken <58574351+ExampleWasTaken@users.noreply.github.com> Date: Thu, 12 Sep 2024 20:06:03 +0200 Subject: [PATCH 55/82] fix genericEmbedPagination.ts --- src/lib/genericEmbedPagination.ts | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/lib/genericEmbedPagination.ts b/src/lib/genericEmbedPagination.ts index 80a19208..033c2756 100644 --- a/src/lib/genericEmbedPagination.ts +++ b/src/lib/genericEmbedPagination.ts @@ -45,8 +45,8 @@ export async function createPaginatedEmbedHandler( time: 120_000, }); - collector.on('collect', async (collectedInteraction: ButtonInteraction) => { - await collectedInteraction.deferUpdate(); + collector.on('collect', (collectedInteraction: ButtonInteraction) => { + void collectedInteraction.deferUpdate(); if (collectedInteraction.customId === 'pagination_nextPage') { currentPage++; @@ -56,11 +56,11 @@ export async function createPaginatedEmbedHandler( setButtonDisabledStates(); - await updateEmbed(); + void updateEmbed(); }); - collector.on('end', async () => { - await handleEmbedExpire(); + collector.on('end', () => { + void handleEmbedExpire(); }); async function updateEmbed() { From b91b3f75ea2db2a6607c0ecec18fc2be8e4d44a5 Mon Sep 17 00:00:00 2001 From: ExampleWasTaken <58574351+ExampleWasTaken@users.noreply.github.com> Date: Thu, 12 Sep 2024 20:20:02 +0200 Subject: [PATCH 56/82] fix github commands --- src/commands/utils/github/functions/githubPullRequest.ts | 6 ++++++ src/commands/utils/github/functions/handleGithubIssue.ts | 6 ++++++ 2 files changed, 12 insertions(+) diff --git a/src/commands/utils/github/functions/githubPullRequest.ts b/src/commands/utils/github/functions/githubPullRequest.ts index 84ed6faf..f9dd4518 100644 --- a/src/commands/utils/github/functions/githubPullRequest.ts +++ b/src/commands/utils/github/functions/githubPullRequest.ts @@ -29,6 +29,9 @@ export async function handleGithubPullRequest(interaction: ChatInputCommandInter repo: repoName, pull_number: cleanedPrNumber, }); + + // octokit returns untyped data - nothing we can do about + // eslint-disable-next-line @typescript-eslint/no-unsafe-argument, @typescript-eslint/no-unsafe-member-access return interaction.reply(response.data.html_url); } catch { return interaction.reply({ embeds: [invalidEmbed] }); @@ -38,6 +41,9 @@ export async function handleGithubPullRequest(interaction: ChatInputCommandInter const response = await request('GET /repos/flybywiresim/a32nx/pulls/{pull_number}', { pull_number: cleanedPrNumber, }); + + // octokit returns untyped data - nothing we can do about + // eslint-disable-next-line @typescript-eslint/no-unsafe-argument, @typescript-eslint/no-unsafe-member-access return interaction.reply(response.data.html_url); } catch { return interaction.reply({ embeds: [invalidEmbed] }); diff --git a/src/commands/utils/github/functions/handleGithubIssue.ts b/src/commands/utils/github/functions/handleGithubIssue.ts index 3cf9d330..bf0c1421 100644 --- a/src/commands/utils/github/functions/handleGithubIssue.ts +++ b/src/commands/utils/github/functions/handleGithubIssue.ts @@ -29,6 +29,9 @@ export async function handleGithubIssue(interaction: ChatInputCommandInteraction repo: repoName, issue_number: cleanedIssueNumber, }); + + // octokit returns untyped data - nothing we can do about + // eslint-disable-next-line @typescript-eslint/no-unsafe-argument, @typescript-eslint/no-unsafe-member-access return interaction.reply(response.data.html_url); } catch { return interaction.reply({ embeds: [invalidEmbed] }); @@ -38,6 +41,9 @@ export async function handleGithubIssue(interaction: ChatInputCommandInteraction const response = await request('GET /repos/flybywiresim/a32nx/issues/{issue_number}', { issue_number: cleanedIssueNumber, }); + + // octokit returns untyped data - nothing we can do about + // eslint-disable-next-line @typescript-eslint/no-unsafe-argument, @typescript-eslint/no-unsafe-member-access return interaction.reply(response.data.html_url); } catch { return interaction.reply({ embeds: [invalidEmbed] }); From f7d17efaaadb072cf3ab603cff850cc48efaaea1 Mon Sep 17 00:00:00 2001 From: ExampleWasTaken <58574351+ExampleWasTaken@users.noreply.github.com> Date: Thu, 12 Sep 2024 20:21:24 +0200 Subject: [PATCH 57/82] fix birthday.ts --- src/commands/utils/birthday/birthday.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/commands/utils/birthday/birthday.ts b/src/commands/utils/birthday/birthday.ts index 3fbfa2ef..ce94edd3 100644 --- a/src/commands/utils/birthday/birthday.ts +++ b/src/commands/utils/birthday/birthday.ts @@ -74,7 +74,7 @@ const noConnEmbed = makeEmbed({ }); export default slashCommand(data, async ({ interaction }) => { - const conn = await getConn(); + const conn = getConn(); if (!conn) { await interaction.reply({ embeds: [noConnEmbed], ephemeral: true }); From 7a115c758ad720b48414893821c613bb27dbf35c Mon Sep 17 00:00:00 2001 From: ExampleWasTaken <58574351+ExampleWasTaken@users.noreply.github.com> Date: Thu, 12 Sep 2024 20:22:36 +0200 Subject: [PATCH 58/82] remove unused imports --- src/commands/utils/birthday/functions/listBirthday.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/commands/utils/birthday/functions/listBirthday.ts b/src/commands/utils/birthday/functions/listBirthday.ts index 12a10db6..f5b435f9 100644 --- a/src/commands/utils/birthday/functions/listBirthday.ts +++ b/src/commands/utils/birthday/functions/listBirthday.ts @@ -1,4 +1,4 @@ -import { APIEmbedField, ChatInputCommandInteraction, EmbedField } from 'discord.js'; +import { ChatInputCommandInteraction, EmbedField } from 'discord.js'; import { Birthday, Logger, makeEmbed } from '../../../../lib'; const birthdayListEmbed = (fields: EmbedField[]) => From c4ff10077c7aa3605729b42d131025123437b761 Mon Sep 17 00:00:00 2001 From: ExampleWasTaken <58574351+ExampleWasTaken@users.noreply.github.com> Date: Thu, 12 Sep 2024 20:23:21 +0200 Subject: [PATCH 59/82] fix whois --- src/commands/moderation/whois.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/commands/moderation/whois.ts b/src/commands/moderation/whois.ts index 46e5e731..8cede53e 100644 --- a/src/commands/moderation/whois.ts +++ b/src/commands/moderation/whois.ts @@ -45,7 +45,7 @@ export default slashCommand(data, async ({ interaction }) => { name: targetMember.user.username, iconURL: targetMember.user.avatarURL()!, }, - description: `${targetMember}`, + description: `${targetMember.toString()}`, thumbnail: { url: targetMember.user.avatarURL()! }, fields: [ { From 72c09c5a447a842777037d5a02b3fceedbcca5aa Mon Sep 17 00:00:00 2001 From: ExampleWasTaken <58574351+ExampleWasTaken@users.noreply.github.com> Date: Thu, 12 Sep 2024 20:56:14 +0200 Subject: [PATCH 60/82] fix slowmode --- .../moderation/slowmode/functions/disable.ts | 22 ++++++----- .../moderation/slowmode/functions/set.ts | 24 ++++++------ src/commands/moderation/slowmode/slowmode.ts | 37 ++++++++++++++++--- 3 files changed, 56 insertions(+), 27 deletions(-) diff --git a/src/commands/moderation/slowmode/functions/disable.ts b/src/commands/moderation/slowmode/functions/disable.ts index 290786c0..4e485fe7 100644 --- a/src/commands/moderation/slowmode/functions/disable.ts +++ b/src/commands/moderation/slowmode/functions/disable.ts @@ -1,16 +1,18 @@ -import { ChannelType, ChatInputCommandInteraction, Colors } from 'discord.js'; +import { ChannelType, ChatInputCommandInteraction, Colors, EmbedBuilder, EmbedField, TextChannel } from 'discord.js'; import { Logger } from '../../../../lib'; +import { SlowmodeChannel } from '../slowmode'; +import { Agenda } from '@hokify/agenda'; export async function handleDisableSlowmode( interaction: ChatInputCommandInteraction<'cached'>, - slowmodeChannel: any, - modLogsChannel: any, - scheduler: any, - failedEmbed: any, - noChannelEmbed: any, - successEmbed: any, - modLogEmbed: any, - slowModeEmbedField: any, + slowmodeChannel: SlowmodeChannel, + modLogsChannel: TextChannel, + scheduler: Agenda | null, + failedEmbed: (action: string, channel: string) => EmbedBuilder, + noChannelEmbed: (action: string, channel: string) => EmbedBuilder, + successEmbed: (action: string, channel: string) => EmbedBuilder, + modLogEmbed: (action: string, fields: EmbedField[], color: number) => EmbedBuilder, + slowModeEmbedField: (moderator: string, channel: string, duration: number, autoDisable: string) => EmbedField[], ) { try { if ( @@ -35,7 +37,7 @@ export async function handleDisableSlowmode( embeds: [ modLogEmbed( 'disabled', - slowModeEmbedField(interaction.user.toString(), slowmodeChannel.id, 0, 0), + slowModeEmbedField(interaction.user.toString(), slowmodeChannel.id, 0, '0'), Colors.Green, ), ], diff --git a/src/commands/moderation/slowmode/functions/set.ts b/src/commands/moderation/slowmode/functions/set.ts index bf4e83c1..fa97810a 100644 --- a/src/commands/moderation/slowmode/functions/set.ts +++ b/src/commands/moderation/slowmode/functions/set.ts @@ -1,17 +1,19 @@ -import { ChannelType, ChatInputCommandInteraction, Colors } from 'discord.js'; +import { Agenda } from '@hokify/agenda'; +import { ChannelType, ChatInputCommandInteraction, Colors, EmbedBuilder, EmbedField, TextChannel } from 'discord.js'; +import { SlowmodeChannel } from '../slowmode'; export async function handleSetSlowmode( interaction: ChatInputCommandInteraction<'cached'>, duration: number, - slowmodeChannel: any, - autoDisable: any, - modLogsChannel: any, - scheduler: any, - failedEmbed: any, - noChannelEmbed: any, - successEmbed: any, - modLogEmbed: any, - slowModeEmbedField: any, + slowmodeChannel: SlowmodeChannel, + autoDisable: number | null, + modLogsChannel: TextChannel, + scheduler: Agenda | null, + failedEmbed: (action: string, channel: string) => EmbedBuilder, + noChannelEmbed: (action: string, channel: string) => EmbedBuilder, + successEmbed: (action: string, channel: string) => EmbedBuilder, + modLogEmbed: (action: string, fields: EmbedField[], color: number) => EmbedBuilder, + slowModeEmbedField: (moderator: string, channel: string, duration: number, autoDisable: string) => EmbedField[], ) { try { if ( @@ -43,7 +45,7 @@ export async function handleSetSlowmode( interaction.user.toString(), slowmodeChannel.id, duration, - autoDisable && scheduler ? autoDisable.toString() : 0, + autoDisable && scheduler ? autoDisable.toString() : '0', ), Colors.Green, ), diff --git a/src/commands/moderation/slowmode/slowmode.ts b/src/commands/moderation/slowmode/slowmode.ts index e5e48a65..c6dd3254 100644 --- a/src/commands/moderation/slowmode/slowmode.ts +++ b/src/commands/moderation/slowmode/slowmode.ts @@ -1,14 +1,28 @@ -import { ApplicationCommandOptionType, ApplicationCommandType, Colors, EmbedField, TextChannel } from 'discord.js'; +import { + ApplicationCommandOptionType, + ApplicationCommandType, + CategoryChannel, + Colors, + EmbedField, + ForumChannel, + MediaChannel, + NewsChannel, + PrivateThreadChannel, + PublicThreadChannel, + StageChannel, + TextChannel, + VoiceChannel, +} from 'discord.js'; import { constantsConfig, - slashCommand, - slashCommandStructure, - makeEmbed, durationInEnglish, getScheduler, + makeEmbed, + slashCommand, + slashCommandStructure, } from '../../../lib'; -import { handleSetSlowmode } from './functions/set'; import { handleDisableSlowmode } from './functions/disable'; +import { handleSetSlowmode } from './functions/set'; const data = slashCommandStructure({ name: 'slowmode', @@ -86,6 +100,17 @@ const data = slashCommandStructure({ ], }); +export type SlowmodeChannel = + | CategoryChannel + | NewsChannel + | StageChannel + | TextChannel + | PrivateThreadChannel + | PublicThreadChannel + | VoiceChannel + | ForumChannel + | MediaChannel; + const noSchedulerEmbed = makeEmbed({ title: 'Slow Mode - No scheduler', description: 'Could not find an active scheduler. No automatic disable can be scheduled.', @@ -99,7 +124,7 @@ const failedEmbed = (action: string, channel: string) => color: Colors.Red, }); -const modLogEmbed = (action: string, fields: any, color: number) => +const modLogEmbed = (action: string, fields: EmbedField[], color: number) => makeEmbed({ title: `Slow Mode - ${action}`, fields, From 2fdcfd0831620930da597579e8b63bc7bef3b017 Mon Sep 17 00:00:00 2001 From: ExampleWasTaken <58574351+ExampleWasTaken@users.noreply.github.com> Date: Sat, 19 Oct 2024 18:25:29 +0200 Subject: [PATCH 61/82] partly fix infractions --- .../moderation/infractions/functions/timeout.ts | 10 ++++++---- .../infractions/functions/unbanInfractions.ts | 2 +- .../moderation/infractions/functions/userNote.ts | 2 +- src/commands/moderation/infractions/functions/warn.ts | 4 ++-- src/commands/moderation/infractions/infractions.ts | 3 ++- 5 files changed, 12 insertions(+), 9 deletions(-) diff --git a/src/commands/moderation/infractions/functions/timeout.ts b/src/commands/moderation/infractions/functions/timeout.ts index 277850be..8a453138 100644 --- a/src/commands/moderation/infractions/functions/timeout.ts +++ b/src/commands/moderation/infractions/functions/timeout.ts @@ -9,10 +9,10 @@ const noConnEmbed = makeEmbed({ color: Colors.Red, }); -const failedTimeoutEmbed = (discordUser: User, error: any) => +const failedTimeoutEmbed = (discordUser: User, error: Error) => makeEmbed({ title: 'Timeout - Failed', - description: makeLines([`Failed to timeout ${discordUser.toString()}`, '', error]), + description: makeLines([`Failed to timeout ${discordUser.toString()}`, '', error.message]), color: Colors.Red, }); @@ -72,7 +72,7 @@ const modLogEmbed = ( }, { name: 'Moderator', - value: `${moderator}`, + value: `${moderator.toString()}`, }, { name: 'Reason', @@ -135,7 +135,9 @@ export async function handleTimeoutInfraction(interaction: ChatInputCommandInter try { await discordUser.timeout(timeoutDuration, timeoutReason); } catch (error) { - await interaction.editReply({ embeds: [failedTimeoutEmbed(discordUser.user, error)] }); + if (error instanceof Error) { + await interaction.editReply({ embeds: [failedTimeoutEmbed(discordUser.user, error)] }); + } Logger.error(error); return; } diff --git a/src/commands/moderation/infractions/functions/unbanInfractions.ts b/src/commands/moderation/infractions/functions/unbanInfractions.ts index 2924ff29..5e5addfa 100644 --- a/src/commands/moderation/infractions/functions/unbanInfractions.ts +++ b/src/commands/moderation/infractions/functions/unbanInfractions.ts @@ -32,7 +32,7 @@ const modLogEmbed = (moderator: User, userID: string, banReason: string, formatt }, { name: 'Moderator', - value: `${moderator}`, + value: `${moderator.toString()}`, }, { name: 'Reason', diff --git a/src/commands/moderation/infractions/functions/userNote.ts b/src/commands/moderation/infractions/functions/userNote.ts index e66c4920..f58e024e 100644 --- a/src/commands/moderation/infractions/functions/userNote.ts +++ b/src/commands/moderation/infractions/functions/userNote.ts @@ -15,7 +15,7 @@ const noteFailed = makeEmbed({ color: Colors.Red, }); -const modLogEmbed = (formattedDate: any, moderator: User, discordUser: User, note: string) => +const modLogEmbed = (formattedDate: string, moderator: User, discordUser: User, note: string) => makeEmbed({ author: { name: `[NOTE] ${discordUser.tag}`, diff --git a/src/commands/moderation/infractions/functions/warn.ts b/src/commands/moderation/infractions/functions/warn.ts index f9e498ec..16216dac 100644 --- a/src/commands/moderation/infractions/functions/warn.ts +++ b/src/commands/moderation/infractions/functions/warn.ts @@ -16,7 +16,7 @@ const warnFailed = (discordUser: User) => color: Colors.Red, }); -const dmEmbed = (guild: Guild, formattedDate: any, moderator: User, reason: string) => +const dmEmbed = (guild: Guild, formattedDate: string, moderator: User, reason: string) => makeEmbed({ title: `You have been warned in ${guild.name}`, fields: [ @@ -45,7 +45,7 @@ const noDM = (discordUser: User) => color: Colors.Red, }); -const modLogEmbed = (formattedDate: any, moderator: User, discordUser: User, reason: string) => +const modLogEmbed = (formattedDate: string, moderator: User, discordUser: User, reason: string) => makeEmbed({ author: { name: `[WARNED] ${discordUser.tag}`, diff --git a/src/commands/moderation/infractions/infractions.ts b/src/commands/moderation/infractions/infractions.ts index b0c4790d..9b64c43e 100644 --- a/src/commands/moderation/infractions/infractions.ts +++ b/src/commands/moderation/infractions/infractions.ts @@ -197,10 +197,11 @@ export default slashCommand(data, async ({ interaction }) => { const subcommandName = interaction.options.getSubcommand(); switch (subcommandName) { - case 'list': + case 'list': { const userID = interaction.options.getUser('tag_or_id')?.id; await handleListInfraction(interaction, userID, false); break; + } case 'delete': await handleDeleteInfraction(interaction); break; From cbfe3768d8493cac174d246a17d4af9b364b510a Mon Sep 17 00:00:00 2001 From: ExampleWasTaken <58574351+ExampleWasTaken@users.noreply.github.com> Date: Sat, 26 Oct 2024 16:15:06 +0200 Subject: [PATCH 62/82] fix listInfractions.ts --- .../infractions/functions/listInfractions.ts | 51 +++++++++---------- 1 file changed, 23 insertions(+), 28 deletions(-) diff --git a/src/commands/moderation/infractions/functions/listInfractions.ts b/src/commands/moderation/infractions/functions/listInfractions.ts index 0428e88d..623c9a50 100644 --- a/src/commands/moderation/infractions/functions/listInfractions.ts +++ b/src/commands/moderation/infractions/functions/listInfractions.ts @@ -1,4 +1,4 @@ -import { Colors, CommandInteraction } from 'discord.js'; +import { Colors, CommandInteraction, User } from 'discord.js'; import moment from 'moment'; import { getConn, Infraction, makeEmbed, createPaginatedInfractionEmbedHandler } from '../../../../lib'; @@ -78,20 +78,16 @@ export async function handleListInfraction( | typeof userNotes; /* eslint-enable @typescript-eslint/no-duplicate-type-constituents */ - const fetchModerators = (infractions: InfractionArray) => { - const moderatorPromises = infractions.map((infraction) => - interaction.client.users - .fetch(infraction.moderatorID!) - // Disabled for readability - - .catch(() => { - return new Promise((resolve) => { - resolve(`I can't find the moderator, here is the stored ID: ${infraction.moderatorID}`); - }); - }), + const fetchModerators = async (infractions: InfractionArray): Promise<(User | string)[]> => { + return Promise.all( + infractions.map(async (infraction) => { + try { + return await interaction.client.users.fetch(infraction.moderatorID!); + } catch { + return `I can't find the moderator, here is the stored ID: ${infraction.moderatorID}`; + } + }), ); - - return Promise.all(moderatorPromises); }; // Warns @@ -106,10 +102,10 @@ export async function handleListInfraction( name: `Warn #${i + 1}`, value: `**Type:** ${warnInfractions[i].infractionType}\n` + - `**Moderator:** ${warnModeratorUsers[i]}\n` + + `**Moderator:** ${warnModeratorUsers[i].toString()}\n` + `**Reason:** ${warnInfractions[i].reason}\n` + `**Date:** ${formattedDate}\n` + - `**Infraction ID:** ${warnInfractions[i].infractionID}`, + `**Infraction ID:** ${warnInfractions[i].infractionID?.toString() ?? 'n/a'}`, }, { name: '', @@ -140,11 +136,11 @@ export async function handleListInfraction( name: `Timeout #${i + 1}`, value: `**Type:** ${timeoutInfractions[i].infractionType}\n` + - `**Moderator:** ${timeoutModeratorUsers[i]}\n` + + `**Moderator:** ${timeoutModeratorUsers[i].toString()}\n` + `**Reason:** ${timeoutInfractions[i].reason}\n` + `**Duration:** ${timeoutInfractions[i].duration !== undefined ? timeoutInfractions[i].duration : 'No duration specified, this user was timed out before the bot upgrade!'}\n` + `**Date:** ${formattedDate}\n` + - `**Infraction ID:** ${timeoutInfractions[i].infractionID}`, + `**Infraction ID:** ${timeoutInfractions[i].infractionID?.toString() ?? 'n/a'}`, }, { name: '', @@ -175,10 +171,10 @@ export async function handleListInfraction( name: `Scam Log #${i + 1}`, value: `**Type:** ${scamLogInfractions[i].infractionType}\n` + - `**Moderator:** ${scamLogModerators[i]}\n` + + `**Moderator:** ${scamLogModerators[i].toString()}\n` + `**Message Content:** ${scamLogInfractions[i].reason}\n` + `**Date:** ${formattedDate}\n` + - `**Infraction ID:** ${scamLogInfractions[i].infractionID}`, + `**Infraction ID:** ${scamLogInfractions[i].infractionID?.toString() ?? 'n/a'}`, }, { name: '', @@ -209,10 +205,10 @@ export async function handleListInfraction( name: `Ban #${i + 1}`, value: `**Type:** ${banInfractions[i].infractionType}\n` + - `**Moderator:** ${banModerators[i]}\n` + + `**Moderator:** ${banModerators[i].toString()}\n` + `**Reason:** ${banInfractions[i].reason}\n` + `**Date:** ${formattedDate}\n` + - `**Infraction ID:** ${banInfractions[i].infractionID}`, + `**Infraction ID:** ${banInfractions[i].infractionID?.toString() ?? 'n/a'}`, }, { name: '', @@ -242,10 +238,10 @@ export async function handleListInfraction( name: `Unban #${i + 1}`, value: `**Type:** ${unbanInfractions[i].infractionType}\n` + - `**Moderator:** ${unbanModerators[i]}\n` + + `**Moderator:** ${unbanModerators[i].toString()}\n` + `**Reason:** ${unbanInfractions[i].reason}\n` + `**Date:** ${formattedDate}\n` + - `**Infraction ID:** ${unbanInfractions[i].infractionID}`, + `**Infraction ID:** ${unbanInfractions[i].infractionID?.toString() ?? 'n/a'}`, }, { name: '', @@ -276,10 +272,10 @@ export async function handleListInfraction( name: `Note #${i + 1}`, value: `**Type:** ${userNotes[i].infractionType}\n` + - `**Moderator:** ${userNodeModerators[i]}\n` + + `**Moderator:** ${userNodeModerators[i].toString()}\n` + `**Note:** ${userNotes[i].reason}\n` + `**Date:** ${formattedDate}\n` + - `**Infraction ID:** ${userNotes[i].infractionID}`, + `**Infraction ID:** ${userNotes[i].infractionID?.toString() ?? 'n/a'}`, }, { name: '', @@ -355,9 +351,8 @@ export async function handleListInfraction( await interaction.deferReply({ ephemeral }); await createPaginatedInfractionEmbedHandler(interaction, interaction.user.id, embeds, infractionsLengths); - } catch (error) { + } catch { //Error handling - User is no longer on discord (Or ID doesn't exist) - const userNotFound = makeEmbed({ color: Colors.Red, title: 'User not found', From 728689dbc1e5224cbfb84548c2f6cb5fb8153935 Mon Sep 17 00:00:00 2001 From: ExampleWasTaken <58574351+ExampleWasTaken@users.noreply.github.com> Date: Sat, 26 Oct 2024 16:19:20 +0200 Subject: [PATCH 63/82] fix ban infraction --- src/commands/moderation/infractions/functions/ban.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/commands/moderation/infractions/functions/ban.ts b/src/commands/moderation/infractions/functions/ban.ts index ffa4bbb3..59a388dc 100644 --- a/src/commands/moderation/infractions/functions/ban.ts +++ b/src/commands/moderation/infractions/functions/ban.ts @@ -76,7 +76,7 @@ const modLogEmbed = ( }, { name: 'Moderator', - value: `${moderator}`, + value: `${moderator.toString()}`, }, { name: 'Reason', From f01d3d7718f08a4d874ecd7eed91e0a2e0514b1e Mon Sep 17 00:00:00 2001 From: ExampleWasTaken <58574351+ExampleWasTaken@users.noreply.github.com> Date: Sat, 26 Oct 2024 16:27:12 +0200 Subject: [PATCH 64/82] fix faqs --- .../moderation/faq/functions/addFaq.ts | 5 +++-- .../moderation/faq/functions/faqPrintAll.ts | 2 ++ .../moderation/faq/functions/listFaq.ts | 21 ++++++++----------- 3 files changed, 14 insertions(+), 14 deletions(-) diff --git a/src/commands/moderation/faq/functions/addFaq.ts b/src/commands/moderation/faq/functions/addFaq.ts index d21f094a..b700d0a3 100644 --- a/src/commands/moderation/faq/functions/addFaq.ts +++ b/src/commands/moderation/faq/functions/addFaq.ts @@ -3,6 +3,7 @@ import { ChatInputCommandInteraction, Colors, ModalBuilder, + ModalSubmitInteraction, TextChannel, TextInputBuilder, TextInputStyle, @@ -64,8 +65,8 @@ export async function handleAddFaq(interaction: ChatInputCommandInteraction<'cac //Modal sent - const filter = (interaction: { customId: string; user: { id: any } }) => - interaction.customId === 'faqAddModal' && interaction.user.id; + const filter = (interaction: ModalSubmitInteraction) => + !!interaction.user.id && interaction.customId === 'faqAddModal'; try { //Await a modal response diff --git a/src/commands/moderation/faq/functions/faqPrintAll.ts b/src/commands/moderation/faq/functions/faqPrintAll.ts index cd2c18f5..23a07ea8 100644 --- a/src/commands/moderation/faq/functions/faqPrintAll.ts +++ b/src/commands/moderation/faq/functions/faqPrintAll.ts @@ -56,6 +56,8 @@ export async function handlePrintAllFAQ(interaction: ChatInputCommandInteraction })), }); + // This is intended to be sequential + // eslint-disable-next-line no-await-in-loop await interaction.channel.send({ embeds: [faqEmbed] }); } diff --git a/src/commands/moderation/faq/functions/listFaq.ts b/src/commands/moderation/faq/functions/listFaq.ts index 0b887b33..17306f7e 100644 --- a/src/commands/moderation/faq/functions/listFaq.ts +++ b/src/commands/moderation/faq/functions/listFaq.ts @@ -23,18 +23,15 @@ export async function handleListFaq(interaction: ChatInputCommandInteraction<'ca let faqsAddedToPage = 0; const faqFields: { name: string; value: string }[] = []; - const moderatorPromises = faqs.map((currentFaq) => - interaction.client.users - .fetch(currentFaq.moderatorID!) - // Added for better readability - - .catch(() => { - return new Promise((resolve) => { - resolve(`I can't find the moderator, here is the stored ID: ${currentFaq.moderatorID}`); - }); - }), + const moderatorUsers = await Promise.all( + faqs.map(async (currentFaq) => { + try { + return await interaction.client.users.fetch(currentFaq.moderatorID!); + } catch { + return `I can't find the moderator, here is the stored ID: ${currentFaq.moderatorID}`; + } + }), ); - const moderatorUsers = await Promise.all(moderatorPromises); for (let i = 0; i < faqs.length; i++) { const formattedDate = moment(faqs[i].dateSet).utcOffset(0).format(); @@ -44,7 +41,7 @@ export async function handleListFaq(interaction: ChatInputCommandInteraction<'ca name: `**Title:** ${faqs[i].faqTitle}`, value: `**Answer:** ${faqs[i].faqAnswer}\n` + - `**Moderator:** ${moderatorUsers[i]}\n` + + `**Moderator:** ${moderatorUsers[i].toString()}\n` + `**Date Set:** ${formattedDate}\n` + `**FAQ ID:** ${faqs[i].id}\n`, }, From 232de8cd7df5f3018d75a31c509cdaf081a4f1a4 Mon Sep 17 00:00:00 2001 From: ExampleWasTaken <58574351+ExampleWasTaken@users.noreply.github.com> Date: Sat, 26 Oct 2024 16:31:02 +0200 Subject: [PATCH 65/82] fix command deploy --- src/commands/moderation/deployCommands.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/commands/moderation/deployCommands.ts b/src/commands/moderation/deployCommands.ts index 03807188..2ccf3f39 100644 --- a/src/commands/moderation/deployCommands.ts +++ b/src/commands/moderation/deployCommands.ts @@ -33,7 +33,7 @@ export default slashCommand(data, async ({ interaction }) => { response = process.env.NODE_ENV === 'production' ? `Deployed ${commandArray.length} commands and ${contextArray.length} contexts globally as ${bot}!` - : `Deployed ${commandArray.length} commands and ${contextArray.length} contexts to \`${guildName}\` as ${bot}!`; + : `Deployed ${commandArray.length} commands and ${contextArray.length} contexts to \`${guildName.name}\` as ${bot}!`; } else { //If the bot can't gather the guild name, use the ID in the response response = From 1c4feba7cc2455ce0e8308555a0fe175f4fda760 Mon Sep 17 00:00:00 2001 From: ExampleWasTaken <58574351+ExampleWasTaken@users.noreply.github.com> Date: Sat, 26 Oct 2024 16:32:21 +0200 Subject: [PATCH 66/82] fix clear messages cmd --- src/commands/moderation/clearMessages.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/commands/moderation/clearMessages.ts b/src/commands/moderation/clearMessages.ts index ebca1712..23bba86e 100644 --- a/src/commands/moderation/clearMessages.ts +++ b/src/commands/moderation/clearMessages.ts @@ -98,12 +98,12 @@ export default slashCommand(data, async ({ interaction }) => { } catch (e) { Logger.error('An error occurred while trying to send the mod log:', e); } - setTimeout(async () => { + setTimeout(() => { try { - return interaction.deleteReply(); + void interaction.deleteReply(); } catch (error) { Logger.error('Failed to delete the reply message:', error); - return interaction.editReply({ content: 'Failed to delete the reply message.' }); + void interaction.editReply({ content: 'Failed to delete the reply message.' }); } }, 5000); return interaction.editReply({ content: '', embeds: [replyEmbed], components: [] }); @@ -121,7 +121,7 @@ export default slashCommand(data, async ({ interaction }) => { return interaction.editReply({ embeds: [canceledEmbed], components: [] }); } - } catch (e) { + } catch { return interaction.editReply({ content: 'The command timed out.', components: [] }); } }); From e53a13bb159872aa87c9bf2a7c2bec3ead9afa6c Mon Sep 17 00:00:00 2001 From: ExampleWasTaken <58574351+ExampleWasTaken@users.noreply.github.com> Date: Sat, 26 Oct 2024 16:35:03 +0200 Subject: [PATCH 67/82] fix cache update cmd --- src/commands/moderation/cacheUpdate.ts | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/src/commands/moderation/cacheUpdate.ts b/src/commands/moderation/cacheUpdate.ts index bc587ca5..e9947b22 100644 --- a/src/commands/moderation/cacheUpdate.ts +++ b/src/commands/moderation/cacheUpdate.ts @@ -1,5 +1,12 @@ -import { ApplicationCommandOptionType, ApplicationCommandType, Colors, EmbedField, TextChannel } from 'discord.js'; -import { constantsConfig, slashCommand, slashCommandStructure, makeEmbed } from '../../lib'; +import { + APIEmbedField, + ApplicationCommandOptionType, + ApplicationCommandType, + Colors, + EmbedField, + TextChannel, +} from 'discord.js'; +import { constantsConfig, makeEmbed, slashCommand, slashCommandStructure } from '../../lib'; const data = slashCommandStructure({ name: 'cache-update', @@ -31,7 +38,7 @@ const data = slashCommandStructure({ ], }); -const cacheUpdateEmbed = (action: string, fields: any, color: number) => +const cacheUpdateEmbed = (action: string, fields: APIEmbedField[], color: number) => makeEmbed({ title: `Cache Update - ${action}`, fields, @@ -131,7 +138,7 @@ export default slashCommand(data, async ({ interaction }) => { ), ], }); - } catch (error) { + } catch { await interaction.followUp({ embeds: [noChannelEmbed(interaction.options.getSubcommand(), 'mod-log')] }); } } From fc3831f1409e7f4fa05688ac9e2b3a0e2f5f32e4 Mon Sep 17 00:00:00 2001 From: ExampleWasTaken <58574351+ExampleWasTaken@users.noreply.github.com> Date: Sat, 26 Oct 2024 16:48:52 +0200 Subject: [PATCH 68/82] fix user info context menu --- src/commands/context/user/userInfo.ts | 76 +++++++++++++++------------ 1 file changed, 43 insertions(+), 33 deletions(-) diff --git a/src/commands/context/user/userInfo.ts b/src/commands/context/user/userInfo.ts index 1f87554d..d2bd4a49 100644 --- a/src/commands/context/user/userInfo.ts +++ b/src/commands/context/user/userInfo.ts @@ -1,42 +1,14 @@ -import { ApplicationCommandType } from 'discord.js'; +import { ApplicationCommandType, Colors, GuildMember, RoleMention } from 'discord.js'; import moment from 'moment/moment'; import { constantsConfig, contextMenuCommand, contextMenuCommandStructure, makeEmbed } from '../../../lib'; -const data = contextMenuCommandStructure({ - name: 'User Info', - type: ApplicationCommandType.User, - default_member_permissions: constantsConfig.commandPermission.MANAGE_SERVER, - dm_permission: false, -}); - -const beautifiedStatus: { [key: string]: string } = { - ONLINE: 'Online', - IDLE: 'Idle', - DND: 'Do Not Disturb', - OFFLINE: 'Offline', -}; - -export default contextMenuCommand(data, async ({ interaction }) => { - const targetMember = interaction.guild?.members.cache.get(interaction.targetId)!; - - const filteredRoles = targetMember.roles.cache.filter((role) => role.id !== interaction.guild.id); - const listedRoles = filteredRoles.sort((a, b) => b.position - a.position).map((role) => role.toString()); - - const onlineStatus = beautifiedStatus[targetMember.presence?.status?.toUpperCase() ?? 'OFFLINE']; - - let status; - if (targetMember.presence == null) { - status = 'Offline'; - } else { - status = onlineStatus; - } - - const whoisEmbed = makeEmbed({ +const whoisEmbed = (targetMember: GuildMember, status: string, listedRoles: RoleMention[]) => + makeEmbed({ author: { name: targetMember.user.username, iconURL: targetMember.user.avatarURL()!, }, - description: `${targetMember}`, + description: `${targetMember.toString()}`, thumbnail: { url: targetMember.user.avatarURL()! }, fields: [ { @@ -76,5 +48,43 @@ export default contextMenuCommand(data, async ({ interaction }) => { footer: { text: `User ID: ${targetMember.id}` }, }); - return interaction.reply({ embeds: [whoisEmbed] }); +const memberNotFoundEmbed = makeEmbed({ + description: 'Could not find the requested member.', + color: Colors.Red, +}); + +const beautifiedStatus: { [key: string]: string } = { + ONLINE: 'Online', + IDLE: 'Idle', + DND: 'Do Not Disturb', + OFFLINE: 'Offline', +}; + +const data = contextMenuCommandStructure({ + name: 'User Info', + type: ApplicationCommandType.User, + default_member_permissions: constantsConfig.commandPermission.MANAGE_SERVER, + dm_permission: false, +}); + +export default contextMenuCommand(data, async ({ interaction }) => { + const targetMember = interaction.guild.members.cache.get(interaction.targetId); + + if (!targetMember) { + return interaction.reply({ embeds: [memberNotFoundEmbed], ephemeral: true }); + } + + const filteredRoles = targetMember.roles.cache.filter((role) => role.id !== interaction.guild.id); + const listedRoles = filteredRoles.sort((a, b) => b.position - a.position).map((role) => role.toString()); + + const onlineStatus = beautifiedStatus[targetMember.presence?.status?.toUpperCase() ?? 'OFFLINE']; + + let status: string; + if (targetMember.presence == null) { + status = 'Offline'; + } else { + status = onlineStatus; + } + + return interaction.reply({ embeds: [whoisEmbed(targetMember, status, listedRoles)] }); }); From 639c3ca886169af654b17664f81b0900e722eb23 Mon Sep 17 00:00:00 2001 From: ExampleWasTaken <58574351+ExampleWasTaken@users.noreply.github.com> Date: Sun, 27 Oct 2024 15:51:04 +0100 Subject: [PATCH 69/82] fix report message context menu --- src/commands/context/message/reportMessage.ts | 20 ++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/src/commands/context/message/reportMessage.ts b/src/commands/context/message/reportMessage.ts index e653cfb0..116e001b 100644 --- a/src/commands/context/message/reportMessage.ts +++ b/src/commands/context/message/reportMessage.ts @@ -7,6 +7,8 @@ import { TextInputBuilder, TextInputStyle, Colors, + Message, + ModalSubmitInteraction, } from 'discord.js'; import moment from 'moment/moment'; import { constantsConfig, contextMenuCommand, contextMenuCommandStructure, Logger, makeEmbed } from '../../../lib'; @@ -17,7 +19,7 @@ const data = contextMenuCommandStructure({ }); const reportedMessageEmbed = ( - targetMessage: any, + targetMessage: Message, interaction: ContextMenuCommandInteraction<'cached'>, messageContent: string, commentContent: string, @@ -132,8 +134,8 @@ export default contextMenuCommand(data, async ({ interaction }) => { //Modal sent - const filter = (interaction: { customId: string; user: { id: any } }) => - interaction.customId === 'reportMessageModal' && interaction.user.id; + const filter = (interaction: ModalSubmitInteraction) => + !!interaction.user.id && interaction.customId === 'reportMessageModal'; let commentContent = 'No additional comments provided.'; @@ -245,7 +247,7 @@ export default contextMenuCommand(data, async ({ interaction }) => { } await interaction.followUp({ - content: `Would you like to share this report in ${modAlertsChannel}? If you do not respond in 15 seconds, I will assume you do not want to share this report.`, + content: `Would you like to share this report in ${modAlertsChannel.toString()}? If you do not respond in 15 seconds, I will assume you do not want to share this report.`, components: [ { type: 1, @@ -276,7 +278,7 @@ export default contextMenuCommand(data, async ({ interaction }) => { const sharedReportEmbed = makeEmbed({ title: '[REPORTED MESSAGE]', - description: `A message has been reported in ${interaction.channel}.`, + description: `A message has been reported in ${interaction.channel.toString()}.`, fields: [ { name: 'Link to Message', @@ -292,24 +294,24 @@ export default contextMenuCommand(data, async ({ interaction }) => { if (shareReportButtonInteraction.customId === 'shareReportYes') { await modAlertsChannel.send({ embeds: [sharedReportEmbed] }); await shareReportButtonInteraction.reply({ - content: `Your report has been submitted and shared in ${modAlertsChannel}.`, + content: `Your report has been submitted and shared in ${modAlertsChannel.toString()}.`, ephemeral: true, }); await scamReportLogs.send({ - content: `Reported message from ${interaction.user.toString()} has been shared in ${modAlertsChannel}.`, + content: `Reported message from ${interaction.user.toString()} has been shared in ${modAlertsChannel.toString()}.`, }); } if (shareReportButtonInteraction.customId === 'shareReportNo') { await shareReportButtonInteraction.reply({ - content: `Your report has been submitted without sharing in ${modAlertsChannel}.`, + content: `Your report has been submitted without sharing in ${modAlertsChannel.toString()}.`, ephemeral: true, }); } } catch (error) { Logger.error(error); await interaction.followUp({ - content: `Your report has been submitted without sharing in ${modAlertsChannel}.`, + content: `Your report has been submitted without sharing in ${modAlertsChannel.toString()}.`, ephemeral: true, }); } From 7364a094d604d2b10e34f334248132ec32cb9584 Mon Sep 17 00:00:00 2001 From: ExampleWasTaken <58574351+ExampleWasTaken@users.noreply.github.com> Date: Sun, 27 Oct 2024 20:28:12 +0100 Subject: [PATCH 70/82] ignore lint error in client.ts * disable eslint that exposes bug in shutdown logic --- src/client.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/client.ts b/src/client.ts index 15ae8985..eb5bd449 100644 --- a/src/client.ts +++ b/src/client.ts @@ -45,5 +45,9 @@ const handleTermination = async () => { } }; +// FIXME: this entire behavior seems to be not working as expected. "Cleanup complete. Exiting..." is not logged to the console. The process seems to exit prematurely. +// This is probably caused by the process not waiting for the promises but it requires a deeper investigation. +/* eslint-disable @typescript-eslint/no-misused-promises */ process.on('SIGINT', handleTermination); process.on('SIGTERM', handleTermination); +/* eslint-enable @typescript-eslint/no-misused-promises */ From 72e1cfc1dde2ef6c4b72ccce31a5b5fe1e30b0fa Mon Sep 17 00:00:00 2001 From: ExampleWasTaken <58574351+ExampleWasTaken@users.noreply.github.com> Date: Sun, 27 Oct 2024 20:52:11 +0100 Subject: [PATCH 71/82] fix npm scripts --- package.json | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/package.json b/package.json index 4752736c..e8e987ec 100644 --- a/package.json +++ b/package.json @@ -9,12 +9,10 @@ "dev": "nodemon --config nodemon.json src/index.ts", "build": "tsc", "build:digitalocean": "npm ci --include=dev && npm run build", - "lint": "eslint --quiet", + "lint": "eslint", "lint-fix": "eslint --fix", "prettier:check": "prettier . --check", - "prettier:write": "prettier . --write", - "dtest": "tsc --noEmit && eslint & npm run prettier:check", - "test": "tsc --noEmit" + "prettier:write": "prettier . --write" }, "author": "FlyByWire Simulations", "license": "AGPL-3.0", From 0a1a2565a93245cdadca0247535ef5460f0f8a15 Mon Sep 17 00:00:00 2001 From: ExampleWasTaken <58574351+ExampleWasTaken@users.noreply.github.com> Date: Sun, 27 Oct 2024 21:01:02 +0100 Subject: [PATCH 72/82] add prettier workflow job --- .github/workflows/pr.yaml | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/.github/workflows/pr.yaml b/.github/workflows/pr.yaml index 66036793..6fc283f2 100644 --- a/.github/workflows/pr.yaml +++ b/.github/workflows/pr.yaml @@ -10,19 +10,34 @@ on: jobs: lint: + name: Lint runs-on: ubuntu-latest if: github.event.pull_request.draft == false steps: - name: Checkout source - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: install - run: npm install --no-optional + run: npm ci - name: Check Lint run: npm run lint + + prettier: + name: Prettier + runs-on: ubuntu-latest + if: github.event.pull_request.draft == false + steps: + - name: Checkout source + uses: actions/checkout@v4 + - name: Install dependencies + run: npm ci + - name: Run Prettier + run: npm run prettier:check + build: + name: Build runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Use Node.js 18.x uses: actions/setup-node@v3 with: From 460c1b1668e0020131f57b2ba91de97fcd76d128 Mon Sep 17 00:00:00 2001 From: ExampleWasTaken <58574351+ExampleWasTaken@users.noreply.github.com> Date: Tue, 29 Oct 2024 14:41:49 +0100 Subject: [PATCH 73/82] bump linting packages to latest version --- package-lock.json | 6 +++--- package.json | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/package-lock.json b/package-lock.json index b79677e7..04f8c9bb 100644 --- a/package-lock.json +++ b/package-lock.json @@ -24,7 +24,7 @@ "winston": "^3.3.4" }, "devDependencies": { - "@eslint/js": "^9.8.0", + "@eslint/js": "^9.13.0", "@types/bad-words": "^3.0.3", "@types/config": "^3.3.1", "@types/eslint__js": "^8.42.3", @@ -32,14 +32,14 @@ "@types/node": "^18.0.0", "@types/node-fetch": "^2.6.10", "dotenv": "^16.0.0", - "eslint": "^9.8.0", + "eslint": "^9.13.0", "eslint-config-prettier": "^9.1.0", "eslint-plugin-prettier": "^5.1.3", "nodemon": "^3.0.2", "prettier": "^3.3.2", "ts-node": "^10.4.0", "typescript": "~5.4.5", - "typescript-eslint": "^8.0.1" + "typescript-eslint": "^8.12.1" }, "engines": { "node": "18.x" diff --git a/package.json b/package.json index 1488a892..31335359 100644 --- a/package.json +++ b/package.json @@ -32,7 +32,7 @@ "winston": "^3.3.4" }, "devDependencies": { - "@eslint/js": "^9.8.0", + "@eslint/js": "^9.13.0", "@types/bad-words": "^3.0.3", "@types/config": "^3.3.1", "@types/eslint__js": "^8.42.3", @@ -40,14 +40,14 @@ "@types/node": "^18.0.0", "@types/node-fetch": "^2.6.10", "dotenv": "^16.0.0", - "eslint": "^9.8.0", + "eslint": "^9.13.0", "eslint-config-prettier": "^9.1.0", "eslint-plugin-prettier": "^5.1.3", "nodemon": "^3.0.2", "prettier": "^3.3.2", "ts-node": "^10.4.0", "typescript": "~5.4.5", - "typescript-eslint": "^8.0.1" + "typescript-eslint": "^8.12.1" }, "engines": { "node": "18.x" From e263d965a4e09a4c5712bcfe051acd08aff50a3d Mon Sep 17 00:00:00 2001 From: ExampleWasTaken <58574351+ExampleWasTaken@users.noreply.github.com> Date: Tue, 29 Oct 2024 14:46:33 +0100 Subject: [PATCH 74/82] bump prettier to latest version --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 04f8c9bb..10b5b1aa 100644 --- a/package-lock.json +++ b/package-lock.json @@ -36,7 +36,7 @@ "eslint-config-prettier": "^9.1.0", "eslint-plugin-prettier": "^5.1.3", "nodemon": "^3.0.2", - "prettier": "^3.3.2", + "prettier": "^3.3.3", "ts-node": "^10.4.0", "typescript": "~5.4.5", "typescript-eslint": "^8.12.1" diff --git a/package.json b/package.json index 31335359..58f1cee7 100644 --- a/package.json +++ b/package.json @@ -44,7 +44,7 @@ "eslint-config-prettier": "^9.1.0", "eslint-plugin-prettier": "^5.1.3", "nodemon": "^3.0.2", - "prettier": "^3.3.2", + "prettier": "^3.3.3", "ts-node": "^10.4.0", "typescript": "~5.4.5", "typescript-eslint": "^8.12.1" From 8589245b834e57283405aa69adc1e27df65a5c42 Mon Sep 17 00:00:00 2001 From: ExampleWasTaken <58574351+ExampleWasTaken@users.noreply.github.com> Date: Tue, 29 Oct 2024 14:50:05 +0100 Subject: [PATCH 75/82] bump eslint prettier config and plugin to latest version --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 10b5b1aa..76678cb8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -34,7 +34,7 @@ "dotenv": "^16.0.0", "eslint": "^9.13.0", "eslint-config-prettier": "^9.1.0", - "eslint-plugin-prettier": "^5.1.3", + "eslint-plugin-prettier": "^5.2.1", "nodemon": "^3.0.2", "prettier": "^3.3.3", "ts-node": "^10.4.0", diff --git a/package.json b/package.json index 58f1cee7..2ebee6da 100644 --- a/package.json +++ b/package.json @@ -42,7 +42,7 @@ "dotenv": "^16.0.0", "eslint": "^9.13.0", "eslint-config-prettier": "^9.1.0", - "eslint-plugin-prettier": "^5.1.3", + "eslint-plugin-prettier": "^5.2.1", "nodemon": "^3.0.2", "prettier": "^3.3.3", "ts-node": "^10.4.0", From 4dff2880e70a62c111b669660c58985927964558 Mon Sep 17 00:00:00 2001 From: ExampleWasTaken <58574351+ExampleWasTaken@users.noreply.github.com> Date: Tue, 29 Oct 2024 14:54:40 +0100 Subject: [PATCH 76/82] fix prettier errors introduced in #85 (expected) --- docs/prefix-commands.md | 103 +- src/commands/index.ts | 72 +- .../prefixCommands/functions/addCategory.ts | 135 +- .../functions/addChannelPermission.ts | 160 +-- .../prefixCommands/functions/addCommand.ts | 315 ++--- .../functions/addRolePermission.ts | 160 +-- .../prefixCommands/functions/addVersion.ts | 226 ++-- .../functions/deleteCategory.ts | 127 +- .../functions/deleteChannelDefaultVersion.ts | 123 +- .../prefixCommands/functions/deleteCommand.ts | 163 ++- .../prefixCommands/functions/deleteContent.ts | 227 ++-- .../prefixCommands/functions/deleteVersion.ts | 246 ++-- .../functions/listCategories.ts | 77 +- .../prefixCommands/functions/listCommands.ts | 77 +- .../prefixCommands/functions/listVersions.ts | 77 +- .../functions/modifyCategory.ts | 139 +- .../prefixCommands/functions/modifyCommand.ts | 359 +++--- .../prefixCommands/functions/modifyVersion.ts | 265 ++-- .../functions/removeChannelPermission.ts | 154 +-- .../functions/removeRolePermission.ts | 154 +-- .../functions/setChannelDefaultVersion.ts | 163 +-- .../functions/setCommandPermissionSettings.ts | 197 +-- .../prefixCommands/functions/setContent.ts | 403 +++--- .../functions/showChannelDefaultVersion.ts | 103 +- .../functions/showCommandPermissions.ts | 178 +-- .../prefixCommands/functions/showContent.ts | 160 ++- .../prefixCommandCacheUpdate.ts | 115 +- .../prefixCommandPermissions.ts | 383 +++--- .../prefixCommands/prefixCommands.ts | 1125 +++++++++-------- src/commands/utils/prefixHelp.ts | 240 ++-- src/events/index.ts | 20 +- src/events/messageCreateHandler.ts | 644 ++++++---- src/events/ready.ts | 76 +- src/lib/cache/cacheManager.ts | 469 +++---- src/lib/schedulerJobs/refreshInMemoryCache.ts | 70 +- src/lib/schemas/prefixCommandSchemas.ts | 183 +-- 36 files changed, 4276 insertions(+), 3612 deletions(-) diff --git a/docs/prefix-commands.md b/docs/prefix-commands.md index c44ca048..221daf37 100644 --- a/docs/prefix-commands.md +++ b/docs/prefix-commands.md @@ -68,19 +68,19 @@ These commands are not hard coded in the bot, and instead they are configured th Additionally, there's a set of features that make these commands very flexible in use: - **Categories** - Commands are categorized for identifying the purpose or use of the command. Categories are manage dynamically through `/`-commands and stored in MongoDB. + Commands are categorized for identifying the purpose or use of the command. Categories are manage dynamically through `/`-commands and stored in MongoDB. - **Versions** - The content of commands are defined per Version. A version can be used to provide different content based on the context in which the command is executed. By default, there is a hard-coded `GENERIC` version available, more can be added and managed dynamically through `/`-commands and stored in MongoDB. If multiple versions exist, and no version is specified during the execution, the `GENERIC` version is shown, with buttons to select the version to be shown. + The content of commands are defined per Version. A version can be used to provide different content based on the context in which the command is executed. By default, there is a hard-coded `GENERIC` version available, more can be added and managed dynamically through `/`-commands and stored in MongoDB. If multiple versions exist, and no version is specified during the execution, the `GENERIC` version is shown, with buttons to select the version to be shown. - **Content** - For each version, it is possible (but not a must) to set the content of a command. The content is static information that is managed with `/`-commands and stored in MongoDB. Depending on the version requested, the content is loaded and shown. Content contains a Title, Body and Image. + For each version, it is possible (but not a must) to set the content of a command. The content is static information that is managed with `/`-commands and stored in MongoDB. Depending on the version requested, the content is loaded and shown. Content contains a Title, Body and Image. - **Permissions** - Two types of permissions exist: Channel permissions and Role permissions. Using permissions it is possible to block or allow the use of a command in certain channels or by certain roles. + Two types of permissions exist: Channel permissions and Role permissions. Using permissions it is possible to block or allow the use of a command in certain channels or by certain roles. - **Channel Default Versions** - For every channel, a specific version can be set as the default. In this case, even if there are multiple versions, if the command is executed without a version specified, the version set as the default for that channel is shown. + For every channel, a specific version can be set as the default. In this case, even if there are multiple versions, if the command is executed without a version specified, the version set as the default for that channel is shown. ### Detailed Concepts @@ -89,17 +89,17 @@ Additionally, there's a set of features that make these commands very flexible i Commands only contain the basic information that is needed to use them: - `name` - A command has a name, this is the main way to execute the command, in combination with the configured prefix. This is a required attribute. + A command has a name, this is the main way to execute the command, in combination with the configured prefix. This is a required attribute. - `category` - The category a command belongs to, a command can only belong to a single category. This is a required attribute. + The category a command belongs to, a command can only belong to a single category. This is a required attribute. - `description` - The description of commands gives a short and brief overview of what the command is used for. This is a required attribute. + The description of commands gives a short and brief overview of what the command is used for. This is a required attribute. - `aliases` - A comma separated list for aliases for this command, each alias can be used to call the command instead of the name of the command. This is an optional attribute. Default value is empty. + A comma separated list for aliases for this command, each alias can be used to call the command instead of the name of the command. This is an optional attribute. Default value is empty. - `is_embed` - A boolean attribute that identifies if the output should be posted as an Embed. If set to `False`, it will be shown as a regular text output, which is useful for simple image commands, or for simple links. This is an optional attribute. Default value is `False`. + A boolean attribute that identifies if the output should be posted as an Embed. If set to `False`, it will be shown as a regular text output, which is useful for simple image commands, or for simple links. This is an optional attribute. Default value is `False`. - `embed_color` - Embeds in Discord have a color to the left, which can be used to give it a special look. By setting this value, you can change the default `FBW_CYAN` to other special colors. Colors are defined in the Config JSON file. This is an optional attribute. Default value is `FBW_CYAN` (only value currently in the `production.json` config file). + Embeds in Discord have a color to the left, which can be used to give it a special look. By setting this value, you can change the default `FBW_CYAN` to other special colors. Colors are defined in the Config JSON file. This is an optional attribute. Default value is `FBW_CYAN` (only value currently in the `production.json` config file). Note that a Command does not contain any information about the content itself. This is because the content is specific per version and is described below. @@ -108,13 +108,13 @@ Note that a Command does not contain any information about the content itself. T Content contains the actual information that is shown to the user when executing the command. Depending on the configuration of the command itself, this content will be displayed as an Embed or as standard text. The following attributes are available: - `version` - The version this content applies to, this is a reference to one of the existing versions in the bot. This is a required attribute. + The version this content applies to, this is a reference to one of the existing versions in the bot. This is a required attribute. - `title` - The title of the content, this will be shown as the title of the Embed, or as the first bold line of the text output in case the command is not an embed. This is a required attribute. + The title of the content, this will be shown as the title of the Embed, or as the first bold line of the text output in case the command is not an embed. This is a required attribute. - `content` - A markdown capable string that identifies the actual content of the specified version. It can be up to 2048 Unicode characters, including emojis. This is an optional attribute. The default value is an empty (`null`), in which case it will not be shown as part of the output. + A markdown capable string that identifies the actual content of the specified version. It can be up to 2048 Unicode characters, including emojis. This is an optional attribute. The default value is an empty (`null`), in which case it will not be shown as part of the output. - `image` - A URL that refers to an image that should be shown as part of the content if the command is an Embed. For text-style commands, the URL should be part of the content itself so Discord automatically loads it as a preview. This is an optional attribute. The default value is empty (`null`). + A URL that refers to an image that should be shown as part of the content if the command is an Embed. For text-style commands, the URL should be part of the content itself so Discord automatically loads it as a preview. This is an optional attribute. The default value is empty (`null`). The `image` behavior can be surprising, but is chosen because it is not possible to just 'add' a message to a text-style response, unless if it is uploaded, and the decision was made to not upload an image very time the command is executed. What can be done is use markdown to load the image using the link syntax. Discord will then automatically load it as a preview. @@ -123,96 +123,96 @@ The `image` behavior can be surprising, but is chosen because it is not possible Categories are used to group commands together. This is mostly useful for when the help command is called to get the list of available commands for a specific category. It groups them together and makes it easy to identify. Categories have the following attributes: - `name` - The name as how it should be shown to the users and in any output. This is a required attribute. + The name as how it should be shown to the users and in any output. This is a required attribute. - `emoji` - An emoji to identify the category, this will be shown next to the category whenever shown. This is an optional attribute. The default value is empty (`null`), in which case it isn't shown. + An emoji to identify the category, this will be shown next to the category whenever shown. This is an optional attribute. The default value is empty (`null`), in which case it isn't shown. #### Version Versions are useful if you want the same command to have different contents based on the context in which it is executed. An example use for FlyByWire Simulations is to use it to have a single command that gives different output based on the product for which it is requested. Later the impact of Versions will be described more. Versions have the following attributes: - `name` - A name for the version, this is how the version is identified in the different commands on how to manage the content of commands. This is a required attribute. + A name for the version, this is how the version is identified in the different commands on how to manage the content of commands. This is a required attribute. - `emoji` - The emoji associated with the version. When a command is executed without any version context, a GENERIC content will be displayed that offers the user the choice to get the details for a specific version. It does so by showing the emojis as buttons for the user to select. This is a required attribute. + The emoji associated with the version. When a command is executed without any version context, a GENERIC content will be displayed that offers the user the choice to get the details for a specific version. It does so by showing the emojis as buttons for the user to select. This is a required attribute. - `alias` - This is a command alias for the version. By executing ` `, the user can get the content for a specific version directly, instead of going through the GENERIC content. This is a required attribute. + This is a command alias for the version. By executing ` `, the user can get the content for a specific version directly, instead of going through the GENERIC content. This is a required attribute. - `is_enabled` - A boolean attribute that can enable or disable a version. When this is set to `False`, the version will not be exposed to users. It will not show up in the selection of versions for the GENERIC content, and the alias will not work. This allows for versions and the content for those versions to be created ahead of enabling them. This is an optional attribute. The default value is `False`. + A boolean attribute that can enable or disable a version. When this is set to `False`, the version will not be exposed to users. It will not show up in the selection of versions for the GENERIC content, and the alias will not work. This allows for versions and the content for those versions to be created ahead of enabling them. This is an optional attribute. The default value is `False`. #### Version Behavior Users can execute commands in two different ways, and they each result in different behavior. Any time a non-GENERIC version is mentioned, it must be enabled. Disable versions will never show up: - `` - This is the direct way of executing a command, depending on the available content, several things might happen: + This is the direct way of executing a command, depending on the available content, several things might happen: - If no Channel Default Version is configured for the channel in which the command is executed: - GENERIC version and one or more other versions have content: - The GENERIC content is shown and the user is given a choice underneath it with buttons containing the emjois of the other versions with content. When the user clicks on one of the buttons, the GENERIC content is removed and a new message is send with the content of the selected version. + The GENERIC content is shown and the user is given a choice underneath it with buttons containing the emjois of the other versions with content. When the user clicks on one of the buttons, the GENERIC content is removed and a new message is send with the content of the selected version. - Only GENERIC version has content: - The GENERIC content is shown, and the user is not given a choice of other versions, as there is no choice available. + The GENERIC content is shown, and the user is not given a choice of other versions, as there is no choice available. - No GENERIC content is set: - No response is given to the user: + No response is given to the user: - No content is set at all: - No response is given to the user. + No response is given to the user. - If a Channel Default Version is configured for the channel in which the command is executed: - Content is set for the Channel Default Version: - The content for that version is shown to the user directly. + The content for that version is shown to the user directly. - No content is set for the Channel Default Version, but it does exist for the GENERIC version: - The content for the GENERIC version is shown, but no selection buttons are shown. + The content for the GENERIC version is shown, but no selection buttons are shown. - No content is set for the Channel Default version, and no content exists for the GENERIC version: - No response is given to the user. + No response is given to the user. - No content is set at all: - No response is given to the user. + No response is given to the user. - ` ` - This directly requests the content for the specified version: + This directly requests the content for the specified version: - Content is set for the specified version: - The content for the specified version is shown to the user directly. + The content for the specified version is shown to the user directly. - No content is set for the specified version, GENERIC version and one or more other versions have content: - The GENERIC content is shown and the user is given a choice underneath it with buttons containing the emjois of the other versions with content. When the user clicks on one of the buttons, the GENERIC content is removed and a new message is send with the content of the selected version. + The GENERIC content is shown and the user is given a choice underneath it with buttons containing the emjois of the other versions with content. When the user clicks on one of the buttons, the GENERIC content is removed and a new message is send with the content of the selected version. - Content is not set for the specified version and only GENERIC version has content: - The GENERIC content is shown, and the user is not given a choice of other versions, as there is no choice available. + The GENERIC content is shown, and the user is not given a choice of other versions, as there is no choice available. - No content is set for the specified version and no GENERIC content is set: - No response is given to the user. + No response is given to the user. - No content is set at all: - No response is given to the user. + No response is given to the user. #### Channel Default Version It is possible to set a version as the default for a specific channel. By doing so, whenever someone executes the command directly (`` in that channel, it will automatically default to that version and not first post the GENERIC version with choices. This bypasses the choice menu and allows for an optimized experience for users. Two attributes need to be provided during configuration: - `channel` - The Discord channel to which the version should be defaulted to. This is a required attribute. + The Discord channel to which the version should be defaulted to. This is a required attribute. - `version` - The version that should be the default for this channel. It is possible to select a disabled version for this, but if you do so and the command is executed in the channel, no output will be shown. This is a required attribute. + The version that should be the default for this channel. It is possible to select a disabled version for this, but if you do so and the command is executed in the channel, no output will be shown. This is a required attribute. #### Permission Permissions can be set on commands so there are limitations to who can use the command and/or in which channels they can be used. The permission behavior is described below. Permissions have the following attributes: - `roles` - A list of Discord roles that either have access or do not have access to the command. This is an optional attribute. The default is an empty list, which results in the roles of the user not being checked. + A list of Discord roles that either have access or do not have access to the command. This is an optional attribute. The default is an empty list, which results in the roles of the user not being checked. - `role-blocklist` - A boolean attribute that identifies if the list of roles is blocked from using the command (`True`) or allowed to use the command (`False`). This is an optional attribute. The default value is `False`, meaning that if a `roles` list is set, only users with at least one of those roles can execute the command. + A boolean attribute that identifies if the list of roles is blocked from using the command (`True`) or allowed to use the command (`False`). This is an optional attribute. The default value is `False`, meaning that if a `roles` list is set, only users with at least one of those roles can execute the command. - `channels` - A list of Disord channels in which the command can either be executed or not executed. This is an optional attirubute. The default is an empty list, which results in the channel not being checked. + A list of Disord channels in which the command can either be executed or not executed. This is an optional attirubute. The default is an empty list, which results in the channel not being checked. - `channel-blocklist` - A boolean attribute that identifies if the list of channels is blocked from command execution (`True`) or allowed to execute the command in (`False`). This is an optional attribute. The default value is `False`, meaning that if a `channels` list is set, the command is only allowed to be executed in one of those channels. + A boolean attribute that identifies if the list of channels is blocked from command execution (`True`) or allowed to execute the command in (`False`). This is an optional attribute. The default value is `False`, meaning that if a `channels` list is set, the command is only allowed to be executed in one of those channels. - `quiet-errors` - A boolean attribute, which if set to `True` will not display any warning to the user and will quietly fail the command execution if the permissions do not allow the execution of the command. This is an optional attribute. The default value is `False`. + A boolean attribute, which if set to `True` will not display any warning to the user and will quietly fail the command execution if the permissions do not allow the execution of the command. This is an optional attribute. The default value is `False`. - `verbose-errors` - A boolean attribute, which if set to `True` will show detailed output about the permission violated and who (role violation) or where (channel violation) the command can be executed. This is an optional attribute. The default value is `False`. + A boolean attribute, which if set to `True` will show detailed output about the permission violated and who (role violation) or where (channel violation) the command can be executed. This is an optional attribute. The default value is `False`. ##### Permission Behavior Permissions are checked in the following flow: - If there is a list of `roles` defined, the user is checked if they have any of the roles. - - If `role-blocklist` is `False` and the user *does not* have any of the roles, the execution of the command is blocked. - - If `role-blocklist` is `True` and the user *does* have any of the roles, the execution of the command is blocked. + - If `role-blocklist` is `False` and the user _does not_ have any of the roles, the execution of the command is blocked. + - If `role-blocklist` is `True` and the user _does_ have any of the roles, the execution of the command is blocked. - If there is a list of `channels` defined, the list is checked to see if the channel in which the command is executed, is part of the list. - - If `channel-blocklist` is `False` and the command *is not* executed in any of the channels, the execution of the command is blocked. - - If `channel-blocklist` is `True` and the command *is* executed in any of the channels, the execution of the command is blocked. + - If `channel-blocklist` is `False` and the command _is not_ executed in any of the channels, the execution of the command is blocked. + - If `channel-blocklist` is `True` and the command _is_ executed in any of the channels, the execution of the command is blocked. ##### Errors @@ -231,14 +231,15 @@ If both are set to `True`, `quiet-errors` takes precedence. The bot will require a MongoDB environment set up. There are a few settings to configure: - **Config JSON**: + - `prefixCommandPrefix` - A String that will be the prefix for command that will be used by the user to execute commands. For example `.` to execute commands like `.help` + A String that will be the prefix for command that will be used by the user to execute commands. For example `.` to execute commands like `.help` - `prefixCommandPermissionDelay` - A number in milliseconds that identifies the delay before the message about invalid permissions is deleted. + A number in milliseconds that identifies the delay before the message about invalid permissions is deleted. - **Environment Variable**: - `CACHE_REFRESH_INTERVAL` - A number in milliseconds that is used to automatically refresh the cache from the database, to make sure the cache remains up to date. + A number in milliseconds that is used to automatically refresh the cache from the database, to make sure the cache remains up to date. ### Management Capabilities diff --git a/src/commands/index.ts b/src/commands/index.ts index 244171fe..572a6e32 100644 --- a/src/commands/index.ts +++ b/src/commands/index.ts @@ -37,42 +37,42 @@ import prefixCommandCacheUpdate from './moderation/prefixCommands/prefixCommandC import prefixHelp from './utils/prefixHelp'; const commandArray: SlashCommand[] = [ - ping, - deployCommands, - avatar, - liveFlights, - memberCount, - metar, - github, - roleInfo, - simbriefData, - station, - taf, - wolframAlpha, - zulu, - cacheUpdate, - infractions, - slowmode, - whois, - faq, - rules, - welcome, - searchFaq, - roleAssignment, - birthday, - count, - vatsim, - help, - docSearch, - reportedIssues, - commandTable, - listRoleUsers, - clearMessages, - locate, - prefixCommands, - prefixCommandPermissions, - prefixCommandCacheUpdate, - prefixHelp, + ping, + deployCommands, + avatar, + liveFlights, + memberCount, + metar, + github, + roleInfo, + simbriefData, + station, + taf, + wolframAlpha, + zulu, + cacheUpdate, + infractions, + slowmode, + whois, + faq, + rules, + welcome, + searchFaq, + roleAssignment, + birthday, + count, + vatsim, + help, + docSearch, + reportedIssues, + commandTable, + listRoleUsers, + clearMessages, + locate, + prefixCommands, + prefixCommandPermissions, + prefixCommandCacheUpdate, + prefixHelp, ]; export default commandArray; diff --git a/src/commands/moderation/prefixCommands/functions/addCategory.ts b/src/commands/moderation/prefixCommands/functions/addCategory.ts index 96104d1a..03d84fd2 100644 --- a/src/commands/moderation/prefixCommands/functions/addCategory.ts +++ b/src/commands/moderation/prefixCommands/functions/addCategory.ts @@ -1,98 +1,109 @@ import { ChatInputCommandInteraction, Colors, User } from 'discord.js'; -import { constantsConfig, getConn, PrefixCommandCategory, Logger, makeEmbed, loadSinglePrefixCommandCategoryToCache } from '../../../../lib'; +import { + constantsConfig, + getConn, + PrefixCommandCategory, + Logger, + makeEmbed, + loadSinglePrefixCommandCategoryToCache, +} from '../../../../lib'; const noConnEmbed = makeEmbed({ - title: 'Prefix Commands - Add Category - No Connection', - description: 'Could not connect to the database. Unable to add the prefix command category.', - color: Colors.Red, + title: 'Prefix Commands - Add Category - No Connection', + description: 'Could not connect to the database. Unable to add the prefix command category.', + color: Colors.Red, }); -const failedEmbed = (category: string) => makeEmbed({ +const failedEmbed = (category: string) => + makeEmbed({ title: 'Prefix Commands - Add Category - Failed', description: `Failed to add the prefix command category ${category}.`, color: Colors.Red, -}); + }); -const alreadyExistsEmbed = (category: string) => makeEmbed({ +const alreadyExistsEmbed = (category: string) => + makeEmbed({ title: 'Prefix Commands - Add Category - Already exists', description: `The prefix command category ${category} already exists. Not adding again.`, color: Colors.Red, -}); + }); -const successEmbed = (category: string) => makeEmbed({ +const successEmbed = (category: string) => + makeEmbed({ title: `Prefix command category ${category} was added successfully.`, color: Colors.Green, -}); + }); -const modLogEmbed = (moderator: User, category: string, emoji: string, categoryId: string) => makeEmbed({ +const modLogEmbed = (moderator: User, category: string, emoji: string, categoryId: string) => + makeEmbed({ title: 'Prefix command category added', fields: [ - { - name: 'Category', - value: category, - }, - { - name: 'Moderator', - value: `${moderator}`, - }, - { - name: 'Emoji', - value: emoji, - }, + { + name: 'Category', + value: category, + }, + { + name: 'Moderator', + value: `${moderator}`, + }, + { + name: 'Emoji', + value: emoji, + }, ], footer: { text: `Category ID: ${categoryId}` }, color: Colors.Green, -}); + }); const noModLogs = makeEmbed({ - title: 'Prefix Commands - Add Category - No Mod Log', - description: 'I can\'t find the mod logs channel. Please check the channel still exists.', - color: Colors.Red, + title: 'Prefix Commands - Add Category - No Mod Log', + description: "I can't find the mod logs channel. Please check the channel still exists.", + color: Colors.Red, }); export async function handleAddPrefixCommandCategory(interaction: ChatInputCommandInteraction<'cached'>) { - await interaction.deferReply({ ephemeral: true }); + await interaction.deferReply({ ephemeral: true }); - const conn = getConn(); - if (!conn) { - await interaction.followUp({ embeds: [noConnEmbed], ephemeral: true }); - return; - } + const conn = getConn(); + if (!conn) { + await interaction.followUp({ embeds: [noConnEmbed], ephemeral: true }); + return; + } - const name = interaction.options.getString('name')!; - const emoji = interaction.options.getString('emoji') || ''; - const moderator = interaction.user; + const name = interaction.options.getString('name')!; + const emoji = interaction.options.getString('emoji') || ''; + const moderator = interaction.user; - //Check if the mod logs channel exists - let modLogsChannel = interaction.guild.channels.resolve(constantsConfig.channels.MOD_LOGS); - if (!modLogsChannel || !modLogsChannel.isTextBased()) { - modLogsChannel = null; - await interaction.followUp({ embeds: [noModLogs], ephemeral: true }); - } + //Check if the mod logs channel exists + let modLogsChannel = interaction.guild.channels.resolve(constantsConfig.channels.MOD_LOGS); + if (!modLogsChannel || !modLogsChannel.isTextBased()) { + modLogsChannel = null; + await interaction.followUp({ embeds: [noModLogs], ephemeral: true }); + } - const existingCategory = await PrefixCommandCategory.findOne({ name }); + const existingCategory = await PrefixCommandCategory.findOne({ name }); - if (!existingCategory) { - const prefixCommandCategory = new PrefixCommandCategory({ - name, - emoji, - }); + if (!existingCategory) { + const prefixCommandCategory = new PrefixCommandCategory({ + name, + emoji, + }); + try { + await prefixCommandCategory.save(); + await loadSinglePrefixCommandCategoryToCache(prefixCommandCategory); + await interaction.followUp({ embeds: [successEmbed(name)], ephemeral: true }); + if (modLogsChannel) { try { - await prefixCommandCategory.save(); - await loadSinglePrefixCommandCategoryToCache(prefixCommandCategory); - await interaction.followUp({ embeds: [successEmbed(name)], ephemeral: true }); - if (modLogsChannel) { - try { - await modLogsChannel.send({ embeds: [modLogEmbed(moderator, name, emoji, prefixCommandCategory.id)] }); - } catch (error) { - Logger.error(`Failed to post a message to the mod logs channel: ${error}`); - } - } + await modLogsChannel.send({ embeds: [modLogEmbed(moderator, name, emoji, prefixCommandCategory.id)] }); } catch (error) { - Logger.error(`Failed to add a prefix command category ${name}: ${error}`); - await interaction.followUp({ embeds: [failedEmbed(name)], ephemeral: true }); + Logger.error(`Failed to post a message to the mod logs channel: ${error}`); } - } else { - await interaction.followUp({ embeds: [alreadyExistsEmbed(name)], ephemeral: true }); + } + } catch (error) { + Logger.error(`Failed to add a prefix command category ${name}: ${error}`); + await interaction.followUp({ embeds: [failedEmbed(name)], ephemeral: true }); } + } else { + await interaction.followUp({ embeds: [alreadyExistsEmbed(name)], ephemeral: true }); + } } diff --git a/src/commands/moderation/prefixCommands/functions/addChannelPermission.ts b/src/commands/moderation/prefixCommands/functions/addChannelPermission.ts index 11981a0d..6d388787 100644 --- a/src/commands/moderation/prefixCommands/functions/addChannelPermission.ts +++ b/src/commands/moderation/prefixCommands/functions/addChannelPermission.ts @@ -1,113 +1,125 @@ import { ChatInputCommandInteraction, Colors, User } from 'discord.js'; -import { constantsConfig, getConn, PrefixCommand, Logger, makeEmbed, refreshSinglePrefixCommandCache } from '../../../../lib'; +import { + constantsConfig, + getConn, + PrefixCommand, + Logger, + makeEmbed, + refreshSinglePrefixCommandCache, +} from '../../../../lib'; const noConnEmbed = makeEmbed({ - title: 'Prefix Commands - Add Channel - No Connection', - description: 'Could not connect to the database. Unable to add the prefix command channel.', - color: Colors.Red, + title: 'Prefix Commands - Add Channel - No Connection', + description: 'Could not connect to the database. Unable to add the prefix command channel.', + color: Colors.Red, }); -const noCommandEmbed = (command: string) => makeEmbed({ +const noCommandEmbed = (command: string) => + makeEmbed({ title: 'Prefix Commands - Add Channel - No Command', description: `Failed to add the prefix command channel for command ${command} as the command does not exist or there are more than one matching.`, color: Colors.Red, -}); + }); -const failedEmbed = (command: string, channel: string) => makeEmbed({ +const failedEmbed = (command: string, channel: string) => + makeEmbed({ title: 'Prefix Commands - Add Channel - Failed', description: `Failed to add the prefix command channel <#${channel}> for command ${command}.`, color: Colors.Red, -}); + }); -const alreadyExistsEmbed = (command: string, channel: string) => makeEmbed({ +const alreadyExistsEmbed = (command: string, channel: string) => + makeEmbed({ title: 'Prefix Commands - Add Channel - Already exists', description: `A prefix command channel <#${channel}> for command ${command} already exists. Not adding again.`, color: Colors.Red, -}); + }); -const successEmbed = (command: string, channel: string) => makeEmbed({ +const successEmbed = (command: string, channel: string) => + makeEmbed({ title: `Prefix command channel <#${channel}> added for command ${command}.`, color: Colors.Green, -}); + }); -const modLogEmbed = (moderator: User, command: string, channel: string) => makeEmbed({ +const modLogEmbed = (moderator: User, command: string, channel: string) => + makeEmbed({ title: 'Add prefix command channel permission', fields: [ - { - name: 'Command', - value: command, - }, - { - name: 'Channel', - value: `<#${channel}>`, - }, - { - name: 'Moderator', - value: `${moderator}`, - }, + { + name: 'Command', + value: command, + }, + { + name: 'Channel', + value: `<#${channel}>`, + }, + { + name: 'Moderator', + value: `${moderator}`, + }, ], color: Colors.Green, -}); + }); const noModLogs = makeEmbed({ - title: 'Prefix Commands - Add Channel - No Mod Log', - description: 'I can\'t find the mod logs channel. Please check the channel still exists.', - color: Colors.Red, + title: 'Prefix Commands - Add Channel - No Mod Log', + description: "I can't find the mod logs channel. Please check the channel still exists.", + color: Colors.Red, }); export async function handleAddPrefixCommandChannelPermission(interaction: ChatInputCommandInteraction<'cached'>) { - await interaction.deferReply({ ephemeral: true }); + await interaction.deferReply({ ephemeral: true }); - const conn = getConn(); - if (!conn) { - await interaction.followUp({ embeds: [noConnEmbed], ephemeral: true }); - return; - } + const conn = getConn(); + if (!conn) { + await interaction.followUp({ embeds: [noConnEmbed], ephemeral: true }); + return; + } - const command = interaction.options.getString('command')!; - const channel = interaction.options.getChannel('channel')!; - const moderator = interaction.user; + const command = interaction.options.getString('command')!; + const channel = interaction.options.getChannel('channel')!; + const moderator = interaction.user; - //Check if the mod logs channel exists - let modLogsChannel = interaction.guild.channels.resolve(constantsConfig.channels.MOD_LOGS); - if (!modLogsChannel || !modLogsChannel.isTextBased()) { - modLogsChannel = null; - await interaction.followUp({ embeds: [noModLogs], ephemeral: true }); - } + //Check if the mod logs channel exists + let modLogsChannel = interaction.guild.channels.resolve(constantsConfig.channels.MOD_LOGS); + if (!modLogsChannel || !modLogsChannel.isTextBased()) { + modLogsChannel = null; + await interaction.followUp({ embeds: [noModLogs], ephemeral: true }); + } - let foundCommands = await PrefixCommand.find({ name: command }); - if (!foundCommands || foundCommands.length > 1) { - foundCommands = await PrefixCommand.find({ aliases: { $in: [command] } }); - } - if (!foundCommands || foundCommands.length > 1) { - await interaction.followUp({ embeds: [noCommandEmbed(command)], ephemeral: true }); - return; - } - const [foundCommand] = foundCommands; - const { id: channelId } = channel; + let foundCommands = await PrefixCommand.find({ name: command }); + if (!foundCommands || foundCommands.length > 1) { + foundCommands = await PrefixCommand.find({ aliases: { $in: [command] } }); + } + if (!foundCommands || foundCommands.length > 1) { + await interaction.followUp({ embeds: [noCommandEmbed(command)], ephemeral: true }); + return; + } + const [foundCommand] = foundCommands; + const { id: channelId } = channel; - const existingChannelPermission = foundCommand.permissions.channels?.includes(channelId); - if (!existingChannelPermission) { - if (!foundCommand.permissions.channels) { - foundCommand.permissions.channels = []; - } - foundCommand.permissions.channels.push(channelId); + const existingChannelPermission = foundCommand.permissions.channels?.includes(channelId); + if (!existingChannelPermission) { + if (!foundCommand.permissions.channels) { + foundCommand.permissions.channels = []; + } + foundCommand.permissions.channels.push(channelId); + try { + await foundCommand.save(); + await refreshSinglePrefixCommandCache(foundCommand, foundCommand); + await interaction.followUp({ embeds: [successEmbed(command, channelId)], ephemeral: true }); + if (modLogsChannel) { try { - await foundCommand.save(); - await refreshSinglePrefixCommandCache(foundCommand, foundCommand); - await interaction.followUp({ embeds: [successEmbed(command, channelId)], ephemeral: true }); - if (modLogsChannel) { - try { - await modLogsChannel.send({ embeds: [modLogEmbed(moderator, command, channelId)] }); - } catch (error) { - Logger.error(`Failed to post a message to the mod logs channel: ${error}`); - } - } + await modLogsChannel.send({ embeds: [modLogEmbed(moderator, command, channelId)] }); } catch (error) { - Logger.error(`Failed to add prefix command channel <#${channel}> for command ${command}: ${error}`); - await interaction.followUp({ embeds: [failedEmbed(command, channelId)], ephemeral: true }); + Logger.error(`Failed to post a message to the mod logs channel: ${error}`); } - } else { - await interaction.followUp({ embeds: [alreadyExistsEmbed(command, channelId)], ephemeral: true }); + } + } catch (error) { + Logger.error(`Failed to add prefix command channel <#${channel}> for command ${command}: ${error}`); + await interaction.followUp({ embeds: [failedEmbed(command, channelId)], ephemeral: true }); } + } else { + await interaction.followUp({ embeds: [alreadyExistsEmbed(command, channelId)], ephemeral: true }); + } } diff --git a/src/commands/moderation/prefixCommands/functions/addCommand.ts b/src/commands/moderation/prefixCommands/functions/addCommand.ts index 6152db80..ddd33a68 100644 --- a/src/commands/moderation/prefixCommands/functions/addCommand.ts +++ b/src/commands/moderation/prefixCommands/functions/addCommand.ts @@ -1,179 +1,212 @@ import { ChatInputCommandInteraction, Colors, User } from 'discord.js'; -import { constantsConfig, getConn, PrefixCommand, Logger, makeEmbed, PrefixCommandCategory, loadSinglePrefixCommandToCache, PrefixCommandVersion } from '../../../../lib'; +import { + constantsConfig, + getConn, + PrefixCommand, + Logger, + makeEmbed, + PrefixCommandCategory, + loadSinglePrefixCommandToCache, + PrefixCommandVersion, +} from '../../../../lib'; const noConnEmbed = makeEmbed({ - title: 'Prefix Commands - Add Command - No Connection', - description: 'Could not connect to the database. Unable to add the prefix command.', - color: Colors.Red, + title: 'Prefix Commands - Add Command - No Connection', + description: 'Could not connect to the database. Unable to add the prefix command.', + color: Colors.Red, }); -const failedEmbed = (command: string) => makeEmbed({ +const failedEmbed = (command: string) => + makeEmbed({ title: 'Prefix Commands - Add Command - Failed', description: `Failed to add the prefix command ${command}.`, color: Colors.Red, -}); + }); -const wrongFormatEmbed = (invalidString: string) => makeEmbed({ +const wrongFormatEmbed = (invalidString: string) => + makeEmbed({ title: 'Prefix Commands - Add Command - Wrong format', description: `The name and aliases of a command can only contain alphanumerical characters, underscores and dashes. ${invalidString} is invalid.`, color: Colors.Red, -}); + }); -const categoryNotFoundEmbed = (category: string) => makeEmbed({ +const categoryNotFoundEmbed = (category: string) => + makeEmbed({ title: 'Prefix Commands - Add Command - Category not found', description: `The prefix command category ${category} does not exist. Please create it first.`, color: Colors.Red, -}); + }); -const alreadyExistsEmbed = (command: string, reason: string) => makeEmbed({ +const alreadyExistsEmbed = (command: string, reason: string) => + makeEmbed({ title: 'Prefix Commands - Add Command - Already exists', description: `The prefix command ${command} can not be added: ${reason}`, color: Colors.Red, -}); + }); -const successEmbed = (command: string) => makeEmbed({ +const successEmbed = (command: string) => + makeEmbed({ title: `Prefix command ${command} was added successfully.`, color: Colors.Green, -}); - -const modLogEmbed = (moderator: User, command: string, aliases: string[], description: string, isEmbed: boolean, embedColor: string, commandId: string) => makeEmbed({ + }); + +const modLogEmbed = ( + moderator: User, + command: string, + aliases: string[], + description: string, + isEmbed: boolean, + embedColor: string, + commandId: string, +) => + makeEmbed({ title: 'Prefix command added', fields: [ - { - name: 'Command', - value: command, - }, - { - name: 'Moderator', - value: `${moderator}`, - }, - { - name: 'Aliases', - value: aliases.join(','), - }, - { - name: 'Description', - value: description, - }, - { - name: 'Is Embed', - value: isEmbed ? 'Yes' : 'No', - }, - { - name: 'Embed Color', - value: embedColor || '', - }, + { + name: 'Command', + value: command, + }, + { + name: 'Moderator', + value: `${moderator}`, + }, + { + name: 'Aliases', + value: aliases.join(','), + }, + { + name: 'Description', + value: description, + }, + { + name: 'Is Embed', + value: isEmbed ? 'Yes' : 'No', + }, + { + name: 'Embed Color', + value: embedColor || '', + }, ], footer: { text: `Command ID: ${commandId}` }, color: Colors.Green, -}); + }); const noModLogs = makeEmbed({ - title: 'Prefix Commands - Add Command - No Mod Log', - description: 'I can\'t find the mod logs channel. Please check the channel still exists.', - color: Colors.Red, + title: 'Prefix Commands - Add Command - No Mod Log', + description: "I can't find the mod logs channel. Please check the channel still exists.", + color: Colors.Red, }); export async function handleAddPrefixCommand(interaction: ChatInputCommandInteraction<'cached'>) { - await interaction.deferReply({ ephemeral: true }); - - const conn = getConn(); - if (!conn) { - await interaction.followUp({ embeds: [noConnEmbed], ephemeral: true }); - return; + await interaction.deferReply({ ephemeral: true }); + + const conn = getConn(); + if (!conn) { + await interaction.followUp({ embeds: [noConnEmbed], ephemeral: true }); + return; + } + + const name = interaction.options.getString('name')?.toLowerCase().trim()!; + const category = interaction.options.getString('category')!; + const description = interaction.options.getString('description')!; + const aliasesString = interaction.options.getString('aliases')?.toLowerCase().trim() || ''; + const aliases = aliasesString !== '' ? aliasesString.split(',') : []; + const isEmbed = interaction.options.getBoolean('is_embed') || false; + const embedColor = interaction.options.getString('embed_color') || ''; + const moderator = interaction.user; + + const nameRegex = /^[\w-]+$/; + if (!nameRegex.test(name)) { + await interaction.followUp({ embeds: [wrongFormatEmbed(name)], ephemeral: true }); + return; + } + for (const alias of aliases) { + if (!nameRegex.test(alias)) { + // eslint-disable-next-line no-await-in-loop + await interaction.followUp({ embeds: [wrongFormatEmbed(alias)], ephemeral: true }); + return; } - - const name = interaction.options.getString('name')?.toLowerCase().trim()!; - const category = interaction.options.getString('category')!; - const description = interaction.options.getString('description')!; - const aliasesString = interaction.options.getString('aliases')?.toLowerCase().trim() || ''; - const aliases = aliasesString !== '' ? aliasesString.split(',') : []; - const isEmbed = interaction.options.getBoolean('is_embed') || false; - const embedColor = interaction.options.getString('embed_color') || ''; - const moderator = interaction.user; - - const nameRegex = /^[\w-]+$/; - if (!nameRegex.test(name)) { - await interaction.followUp({ embeds: [wrongFormatEmbed(name)], ephemeral: true }); - return; - } - for (const alias of aliases) { - if (!nameRegex.test(alias)) { - // eslint-disable-next-line no-await-in-loop - await interaction.followUp({ embeds: [wrongFormatEmbed(alias)], ephemeral: true }); - return; - } - } - - // Check if command name and alias are unique, additionally check if they do not exist as a version alias. - const foundCommandName = await PrefixCommand.findOne({ - $or: [ - { name }, - { name: { $in: aliases } }, - { aliases: name }, - { aliases: { $in: aliases } }, - ], - }); - if (foundCommandName) { - await interaction.followUp({ embeds: [alreadyExistsEmbed(name, `${name} already exists as a command or alias, or one of the aliases already exists as a command or alias.`)], ephemeral: true }); - return; - } - const foundVersion = await PrefixCommandVersion.findOne({ - $or: [ - { alias: name }, - { alias: { $in: aliases } }, - ], + } + + // Check if command name and alias are unique, additionally check if they do not exist as a version alias. + const foundCommandName = await PrefixCommand.findOne({ + $or: [{ name }, { name: { $in: aliases } }, { aliases: name }, { aliases: { $in: aliases } }], + }); + if (foundCommandName) { + await interaction.followUp({ + embeds: [ + alreadyExistsEmbed( + name, + `${name} already exists as a command or alias, or one of the aliases already exists as a command or alias.`, + ), + ], + ephemeral: true, }); - if (foundVersion || name.toLowerCase() === 'generic' || aliases.includes('generic')) { - await interaction.followUp({ embeds: [alreadyExistsEmbed(name, `${name} already exists as a version alias, or one of the aliases already exists as a version alias.`)], ephemeral: true }); - return; - } - - //Check if the mod logs channel exists - let modLogsChannel = interaction.guild.channels.resolve(constantsConfig.channels.MOD_LOGS); - if (!modLogsChannel || !modLogsChannel.isTextBased()) { - modLogsChannel = null; - await interaction.followUp({ embeds: [noModLogs], ephemeral: true }); - } - - const foundCategory = await PrefixCommandCategory.findOne({ name: category }); - if (!foundCategory) { - await interaction.followUp({ embeds: [categoryNotFoundEmbed(category)], ephemeral: true }); - return; - } - const { id: categoryId } = foundCategory; - Logger.info(`categoryId: ${categoryId}`); - - const prefixCommand = new PrefixCommand({ - name, - categoryId, - aliases, - description, - isEmbed, - embedColor, - contents: [], - permissions: { - roles: [], - rolesBlocklist: false, - channels: [], - channelsBlocklist: false, - quietErrors: false, - verboseErrors: false, - }, + return; + } + const foundVersion = await PrefixCommandVersion.findOne({ + $or: [{ alias: name }, { alias: { $in: aliases } }], + }); + if (foundVersion || name.toLowerCase() === 'generic' || aliases.includes('generic')) { + await interaction.followUp({ + embeds: [ + alreadyExistsEmbed( + name, + `${name} already exists as a version alias, or one of the aliases already exists as a version alias.`, + ), + ], + ephemeral: true, }); - try { - await prefixCommand.save(); - await loadSinglePrefixCommandToCache(prefixCommand); - await interaction.followUp({ embeds: [successEmbed(name)], ephemeral: true }); - if (modLogsChannel) { - try { - await modLogsChannel.send({ embeds: [modLogEmbed(moderator, name, aliases, description, isEmbed, embedColor, prefixCommand.id)] }); - } catch (error) { - Logger.error(`Failed to post a message to the mod logs channel: ${error}`); - } - } - } catch (error) { - Logger.error(`Failed to add a prefix command ${name}: ${error}`); - await interaction.followUp({ embeds: [failedEmbed(name)], ephemeral: true }); + return; + } + + //Check if the mod logs channel exists + let modLogsChannel = interaction.guild.channels.resolve(constantsConfig.channels.MOD_LOGS); + if (!modLogsChannel || !modLogsChannel.isTextBased()) { + modLogsChannel = null; + await interaction.followUp({ embeds: [noModLogs], ephemeral: true }); + } + + const foundCategory = await PrefixCommandCategory.findOne({ name: category }); + if (!foundCategory) { + await interaction.followUp({ embeds: [categoryNotFoundEmbed(category)], ephemeral: true }); + return; + } + const { id: categoryId } = foundCategory; + Logger.info(`categoryId: ${categoryId}`); + + const prefixCommand = new PrefixCommand({ + name, + categoryId, + aliases, + description, + isEmbed, + embedColor, + contents: [], + permissions: { + roles: [], + rolesBlocklist: false, + channels: [], + channelsBlocklist: false, + quietErrors: false, + verboseErrors: false, + }, + }); + try { + await prefixCommand.save(); + await loadSinglePrefixCommandToCache(prefixCommand); + await interaction.followUp({ embeds: [successEmbed(name)], ephemeral: true }); + if (modLogsChannel) { + try { + await modLogsChannel.send({ + embeds: [modLogEmbed(moderator, name, aliases, description, isEmbed, embedColor, prefixCommand.id)], + }); + } catch (error) { + Logger.error(`Failed to post a message to the mod logs channel: ${error}`); + } } + } catch (error) { + Logger.error(`Failed to add a prefix command ${name}: ${error}`); + await interaction.followUp({ embeds: [failedEmbed(name)], ephemeral: true }); + } } diff --git a/src/commands/moderation/prefixCommands/functions/addRolePermission.ts b/src/commands/moderation/prefixCommands/functions/addRolePermission.ts index a0c2b48f..a40682c0 100644 --- a/src/commands/moderation/prefixCommands/functions/addRolePermission.ts +++ b/src/commands/moderation/prefixCommands/functions/addRolePermission.ts @@ -1,113 +1,125 @@ import { ChatInputCommandInteraction, Colors, User } from 'discord.js'; -import { constantsConfig, getConn, PrefixCommand, Logger, makeEmbed, refreshSinglePrefixCommandCache } from '../../../../lib'; +import { + constantsConfig, + getConn, + PrefixCommand, + Logger, + makeEmbed, + refreshSinglePrefixCommandCache, +} from '../../../../lib'; const noConnEmbed = makeEmbed({ - title: 'Prefix Commands - Add Role - No Connection', - description: 'Could not connect to the database. Unable to add the prefix command role.', - color: Colors.Red, + title: 'Prefix Commands - Add Role - No Connection', + description: 'Could not connect to the database. Unable to add the prefix command role.', + color: Colors.Red, }); -const noCommandEmbed = (command: string) => makeEmbed({ +const noCommandEmbed = (command: string) => + makeEmbed({ title: 'Prefix Commands - Add Role - No Command', description: `Failed to add the prefix command role for command ${command} as the command does not exist or there are more than one matching.`, color: Colors.Red, -}); + }); -const failedEmbed = (command: string, roleName: string) => makeEmbed({ +const failedEmbed = (command: string, roleName: string) => + makeEmbed({ title: 'Prefix Commands - Add Role - Failed', description: `Failed to add the prefix command role ${roleName} for command ${command}.`, color: Colors.Red, -}); + }); -const alreadyExistsEmbed = (command: string, roleName: string) => makeEmbed({ +const alreadyExistsEmbed = (command: string, roleName: string) => + makeEmbed({ title: 'Prefix Commands - Add Role - Already exists', description: `A prefix command role ${roleName} for command ${command} already exists. Not adding again.`, color: Colors.Red, -}); + }); -const successEmbed = (command: string, roleName: string) => makeEmbed({ +const successEmbed = (command: string, roleName: string) => + makeEmbed({ title: `Prefix command role ${roleName} added for command ${command}.`, color: Colors.Green, -}); + }); -const modLogEmbed = (moderator: User, command: string, roleName: string) => makeEmbed({ +const modLogEmbed = (moderator: User, command: string, roleName: string) => + makeEmbed({ title: 'Add prefix command role permission', fields: [ - { - name: 'Command', - value: command, - }, - { - name: 'Role', - value: roleName, - }, - { - name: 'Moderator', - value: `${moderator}`, - }, + { + name: 'Command', + value: command, + }, + { + name: 'Role', + value: roleName, + }, + { + name: 'Moderator', + value: `${moderator}`, + }, ], color: Colors.Green, -}); + }); const noModLogs = makeEmbed({ - title: 'Prefix Commands - Add Role - No Mod Log', - description: 'I can\'t find the mod logs role. Please check the role still exists.', - color: Colors.Red, + title: 'Prefix Commands - Add Role - No Mod Log', + description: "I can't find the mod logs role. Please check the role still exists.", + color: Colors.Red, }); export async function handleAddPrefixCommandRolePermission(interaction: ChatInputCommandInteraction<'cached'>) { - await interaction.deferReply({ ephemeral: true }); + await interaction.deferReply({ ephemeral: true }); - const conn = getConn(); - if (!conn) { - await interaction.followUp({ embeds: [noConnEmbed], ephemeral: true }); - return; - } + const conn = getConn(); + if (!conn) { + await interaction.followUp({ embeds: [noConnEmbed], ephemeral: true }); + return; + } - const command = interaction.options.getString('command')!; - const role = interaction.options.getRole('role')!; - const moderator = interaction.user; + const command = interaction.options.getString('command')!; + const role = interaction.options.getRole('role')!; + const moderator = interaction.user; - //Check if the mod logs role exists - let modLogsChannel = interaction.guild.channels.resolve(constantsConfig.channels.MOD_LOGS); - if (!modLogsChannel || !modLogsChannel.isTextBased()) { - modLogsChannel = null; - await interaction.followUp({ embeds: [noModLogs], ephemeral: true }); - } + //Check if the mod logs role exists + let modLogsChannel = interaction.guild.channels.resolve(constantsConfig.channels.MOD_LOGS); + if (!modLogsChannel || !modLogsChannel.isTextBased()) { + modLogsChannel = null; + await interaction.followUp({ embeds: [noModLogs], ephemeral: true }); + } - let foundCommands = await PrefixCommand.find({ name: command }); - if (!foundCommands || foundCommands.length > 1) { - foundCommands = await PrefixCommand.find({ aliases: { $in: [command] } }); - } - if (!foundCommands || foundCommands.length > 1) { - await interaction.followUp({ embeds: [noCommandEmbed(command)], ephemeral: true }); - return; - } - const [foundCommand] = foundCommands; - const { id: roleId, name: roleName } = role; + let foundCommands = await PrefixCommand.find({ name: command }); + if (!foundCommands || foundCommands.length > 1) { + foundCommands = await PrefixCommand.find({ aliases: { $in: [command] } }); + } + if (!foundCommands || foundCommands.length > 1) { + await interaction.followUp({ embeds: [noCommandEmbed(command)], ephemeral: true }); + return; + } + const [foundCommand] = foundCommands; + const { id: roleId, name: roleName } = role; - const existingRolePermission = foundCommand.permissions.roles?.includes(roleId); - if (!existingRolePermission) { - if (!foundCommand.permissions.roles) { - foundCommand.permissions.roles = []; - } - foundCommand.permissions.roles.push(roleId); + const existingRolePermission = foundCommand.permissions.roles?.includes(roleId); + if (!existingRolePermission) { + if (!foundCommand.permissions.roles) { + foundCommand.permissions.roles = []; + } + foundCommand.permissions.roles.push(roleId); + try { + await foundCommand.save(); + await refreshSinglePrefixCommandCache(foundCommand, foundCommand); + await interaction.followUp({ embeds: [successEmbed(command, roleName)], ephemeral: true }); + if (modLogsChannel) { try { - await foundCommand.save(); - await refreshSinglePrefixCommandCache(foundCommand, foundCommand); - await interaction.followUp({ embeds: [successEmbed(command, roleName)], ephemeral: true }); - if (modLogsChannel) { - try { - await modLogsChannel.send({ embeds: [modLogEmbed(moderator, command, roleName)] }); - } catch (error) { - Logger.error(`Failed to post a message to the mod logs role: ${error}`); - } - } + await modLogsChannel.send({ embeds: [modLogEmbed(moderator, command, roleName)] }); } catch (error) { - Logger.error(`Failed to add prefix command role ${roleName} for command ${command}: ${error}`); - await interaction.followUp({ embeds: [failedEmbed(command, roleName)], ephemeral: true }); + Logger.error(`Failed to post a message to the mod logs role: ${error}`); } - } else { - await interaction.followUp({ embeds: [alreadyExistsEmbed(command, roleName)], ephemeral: true }); + } + } catch (error) { + Logger.error(`Failed to add prefix command role ${roleName} for command ${command}: ${error}`); + await interaction.followUp({ embeds: [failedEmbed(command, roleName)], ephemeral: true }); } + } else { + await interaction.followUp({ embeds: [alreadyExistsEmbed(command, roleName)], ephemeral: true }); + } } diff --git a/src/commands/moderation/prefixCommands/functions/addVersion.ts b/src/commands/moderation/prefixCommands/functions/addVersion.ts index 032232e0..85dd623b 100644 --- a/src/commands/moderation/prefixCommands/functions/addVersion.ts +++ b/src/commands/moderation/prefixCommands/functions/addVersion.ts @@ -1,142 +1,164 @@ import { ChatInputCommandInteraction, Colors, User } from 'discord.js'; -import { constantsConfig, getConn, PrefixCommandVersion, Logger, makeEmbed, loadSinglePrefixCommandVersionToCache, PrefixCommand } from '../../../../lib'; +import { + constantsConfig, + getConn, + PrefixCommandVersion, + Logger, + makeEmbed, + loadSinglePrefixCommandVersionToCache, + PrefixCommand, +} from '../../../../lib'; const noConnEmbed = makeEmbed({ - title: 'Prefix Commands - Add Version - No Connection', - description: 'Could not connect to the database. Unable to add the prefix command version.', - color: Colors.Red, + title: 'Prefix Commands - Add Version - No Connection', + description: 'Could not connect to the database. Unable to add the prefix command version.', + color: Colors.Red, }); -const failedEmbed = (version: string) => makeEmbed({ +const failedEmbed = (version: string) => + makeEmbed({ title: 'Prefix Commands - Add Version - Failed', description: `Failed to add the prefix command version ${version}.`, color: Colors.Red, -}); + }); -const wrongFormatEmbed = (invalidString: string) => makeEmbed({ +const wrongFormatEmbed = (invalidString: string) => + makeEmbed({ title: 'Prefix Commands - Add Version - Wrong format', description: `The name and alias of a version can only contain alphanumerical characters, underscores and dashes. "${invalidString}" is invalid.`, color: Colors.Red, -}); + }); -const alreadyExistsEmbed = (version: string, reason: string) => makeEmbed({ +const alreadyExistsEmbed = (version: string, reason: string) => + makeEmbed({ title: 'Prefix Commands - Add Version - Already exists', description: `The prefix command version ${version} already exists: ${reason}`, color: Colors.Red, -}); + }); -const successEmbed = (version: string) => makeEmbed({ +const successEmbed = (version: string) => + makeEmbed({ title: `Prefix command version ${version} was added successfully.`, color: Colors.Green, -}); + }); -const modLogEmbed = (moderator: User, version: string, emoji: string, alias: string, enabled: boolean, versionId: string) => makeEmbed({ +const modLogEmbed = ( + moderator: User, + version: string, + emoji: string, + alias: string, + enabled: boolean, + versionId: string, +) => + makeEmbed({ title: 'Prefix command version added', fields: [ - { - name: 'Version', - value: version, - }, - { - name: 'Moderator', - value: `${moderator}`, - }, - { - name: 'Emoji', - value: emoji, - }, - { - name: 'Alias', - value: alias, - }, - { - name: 'Enabled', - value: enabled ? 'Yes' : 'No', - }, + { + name: 'Version', + value: version, + }, + { + name: 'Moderator', + value: `${moderator}`, + }, + { + name: 'Emoji', + value: emoji, + }, + { + name: 'Alias', + value: alias, + }, + { + name: 'Enabled', + value: enabled ? 'Yes' : 'No', + }, ], footer: { text: `Version ID: ${versionId}` }, color: Colors.Green, -}); + }); const noModLogs = makeEmbed({ - title: 'Prefix Commands - Add Version - No Mod Log', - description: 'I can\'t find the mod logs channel. Please check the channel still exists.', - color: Colors.Red, + title: 'Prefix Commands - Add Version - No Mod Log', + description: "I can't find the mod logs channel. Please check the channel still exists.", + color: Colors.Red, }); export async function handleAddPrefixCommandVersion(interaction: ChatInputCommandInteraction<'cached'>) { - await interaction.deferReply({ ephemeral: true }); + await interaction.deferReply({ ephemeral: true }); - const conn = getConn(); - if (!conn) { - await interaction.followUp({ embeds: [noConnEmbed], ephemeral: true }); - return; - } + const conn = getConn(); + if (!conn) { + await interaction.followUp({ embeds: [noConnEmbed], ephemeral: true }); + return; + } - const name = interaction.options.getString('name')!; - const emoji = interaction.options.getString('emoji')!; - const alias = interaction.options.getString('alias')!.toLowerCase(); - const enabled = interaction.options.getBoolean('is_enabled') || false; - const moderator = interaction.user; + const name = interaction.options.getString('name')!; + const emoji = interaction.options.getString('emoji')!; + const alias = interaction.options.getString('alias')!.toLowerCase(); + const enabled = interaction.options.getBoolean('is_enabled') || false; + const moderator = interaction.user; - const nameRegex = /^[\w-]+$/; - if (!nameRegex.test(name)) { - await interaction.followUp({ embeds: [wrongFormatEmbed(name)], ephemeral: true }); - return; - } - if (!nameRegex.test(alias)) { - await interaction.followUp({ embeds: [wrongFormatEmbed(alias)], ephemeral: true }); - return; - } + const nameRegex = /^[\w-]+$/; + if (!nameRegex.test(name)) { + await interaction.followUp({ embeds: [wrongFormatEmbed(name)], ephemeral: true }); + return; + } + if (!nameRegex.test(alias)) { + await interaction.followUp({ embeds: [wrongFormatEmbed(alias)], ephemeral: true }); + return; + } - // Check if a command or version exists with the same name or alias - const foundCommandName = await PrefixCommand.findOne({ - $or: [ - { name: alias }, - { aliases: alias }, - ], + // Check if a command or version exists with the same name or alias + const foundCommandName = await PrefixCommand.findOne({ + $or: [{ name: alias }, { aliases: alias }], + }); + if (foundCommandName) { + await interaction.followUp({ + embeds: [alreadyExistsEmbed(name, `${alias} already exists as a command or alias.`)], + ephemeral: true, }); - if (foundCommandName) { - await interaction.followUp({ embeds: [alreadyExistsEmbed(name, `${alias} already exists as a command or alias.`)], ephemeral: true }); - return; - } - const foundVersion = await PrefixCommandVersion.findOne({ - $or: [ - { name }, - { alias }, - ], + return; + } + const foundVersion = await PrefixCommandVersion.findOne({ + $or: [{ name }, { alias }], + }); + if (foundVersion || name.toLowerCase() === 'generic' || alias === 'generic') { + await interaction.followUp({ + embeds: [alreadyExistsEmbed(name, `${alias} already exists as a version alias.`)], + ephemeral: true, }); - if (foundVersion || name.toLowerCase() === 'generic' || alias === 'generic') { - await interaction.followUp({ embeds: [alreadyExistsEmbed(name, `${alias} already exists as a version alias.`)], ephemeral: true }); - return; - } + return; + } - //Check if the mod logs channel exists - let modLogsChannel = interaction.guild.channels.resolve(constantsConfig.channels.MOD_LOGS); - if (!modLogsChannel || !modLogsChannel.isTextBased()) { - modLogsChannel = null; - await interaction.followUp({ embeds: [noModLogs], ephemeral: true }); - } + //Check if the mod logs channel exists + let modLogsChannel = interaction.guild.channels.resolve(constantsConfig.channels.MOD_LOGS); + if (!modLogsChannel || !modLogsChannel.isTextBased()) { + modLogsChannel = null; + await interaction.followUp({ embeds: [noModLogs], ephemeral: true }); + } - const prefixCommandVersion = new PrefixCommandVersion({ - name, - emoji, - enabled, - alias, - }); - try { - await prefixCommandVersion.save(); - await loadSinglePrefixCommandVersionToCache(prefixCommandVersion); - await interaction.followUp({ embeds: [successEmbed(name)], ephemeral: true }); - if (modLogsChannel) { - try { - await modLogsChannel.send({ embeds: [modLogEmbed(moderator, name, emoji, alias, enabled, prefixCommandVersion.id)] }); - } catch (error) { - Logger.error(`Failed to post a message to the mod logs channel: ${error}`); - } - } - } catch (error) { - Logger.error(`Failed to add a prefix command category ${name}: ${error}`); - await interaction.followUp({ embeds: [failedEmbed(name)], ephemeral: true }); + const prefixCommandVersion = new PrefixCommandVersion({ + name, + emoji, + enabled, + alias, + }); + try { + await prefixCommandVersion.save(); + await loadSinglePrefixCommandVersionToCache(prefixCommandVersion); + await interaction.followUp({ embeds: [successEmbed(name)], ephemeral: true }); + if (modLogsChannel) { + try { + await modLogsChannel.send({ + embeds: [modLogEmbed(moderator, name, emoji, alias, enabled, prefixCommandVersion.id)], + }); + } catch (error) { + Logger.error(`Failed to post a message to the mod logs channel: ${error}`); + } } + } catch (error) { + Logger.error(`Failed to add a prefix command category ${name}: ${error}`); + await interaction.followUp({ embeds: [failedEmbed(name)], ephemeral: true }); + } } diff --git a/src/commands/moderation/prefixCommands/functions/deleteCategory.ts b/src/commands/moderation/prefixCommands/functions/deleteCategory.ts index 93ed6a69..f564c7ce 100644 --- a/src/commands/moderation/prefixCommands/functions/deleteCategory.ts +++ b/src/commands/moderation/prefixCommands/functions/deleteCategory.ts @@ -1,94 +1,105 @@ import { ChatInputCommandInteraction, Colors, User } from 'discord.js'; -import { constantsConfig, getConn, PrefixCommandCategory, Logger, makeEmbed, clearSinglePrefixCommandCategoryCache } from '../../../../lib'; +import { + constantsConfig, + getConn, + PrefixCommandCategory, + Logger, + makeEmbed, + clearSinglePrefixCommandCategoryCache, +} from '../../../../lib'; const noConnEmbed = makeEmbed({ - title: 'Prefix Commands - Delete Category - No Connection', - description: 'Could not connect to the database. Unable to delete the prefix command category.', - color: Colors.Red, + title: 'Prefix Commands - Delete Category - No Connection', + description: 'Could not connect to the database. Unable to delete the prefix command category.', + color: Colors.Red, }); -const failedEmbed = (categoryId: string) => makeEmbed({ +const failedEmbed = (categoryId: string) => + makeEmbed({ title: 'Prefix Commands - Delete Category - Failed', description: `Failed to delete the prefix command category with id ${categoryId}.`, color: Colors.Red, -}); + }); -const doesNotExistsEmbed = (category: string) => makeEmbed({ +const doesNotExistsEmbed = (category: string) => + makeEmbed({ title: 'Prefix Commands - Delete Category - Does not exist', description: `The prefix command category ${category} does not exists. Cannot delete it.`, color: Colors.Red, -}); + }); -const successEmbed = (category: string, categoryId: string) => makeEmbed({ +const successEmbed = (category: string, categoryId: string) => + makeEmbed({ title: `Prefix command category ${category} (${categoryId}) was deleted successfully.`, color: Colors.Green, -}); + }); -const modLogEmbed = (moderator: User, category: string, emoji: string, categoryId: string) => makeEmbed({ +const modLogEmbed = (moderator: User, category: string, emoji: string, categoryId: string) => + makeEmbed({ title: 'Prefix command category deleted', fields: [ - { - name: 'Category', - value: category, - }, - { - name: 'Moderator', - value: `${moderator}`, - }, - { - name: 'Emoji', - value: emoji, - }, + { + name: 'Category', + value: category, + }, + { + name: 'Moderator', + value: `${moderator}`, + }, + { + name: 'Emoji', + value: emoji, + }, ], footer: { text: `Category ID: ${categoryId}` }, color: Colors.Red, -}); + }); const noModLogs = makeEmbed({ - title: 'Prefix Commands - Delete Category - No Mod Log', - description: 'I can\'t find the mod logs channel. Please check the channel still exists.', - color: Colors.Red, + title: 'Prefix Commands - Delete Category - No Mod Log', + description: "I can't find the mod logs channel. Please check the channel still exists.", + color: Colors.Red, }); export async function handleDeletePrefixCommandCategory(interaction: ChatInputCommandInteraction<'cached'>) { - await interaction.deferReply({ ephemeral: true }); + await interaction.deferReply({ ephemeral: true }); - const conn = getConn(); - if (!conn) { - await interaction.followUp({ embeds: [noConnEmbed], ephemeral: true }); - return; - } + const conn = getConn(); + if (!conn) { + await interaction.followUp({ embeds: [noConnEmbed], ephemeral: true }); + return; + } - const category = interaction.options.getString('category')!; - const moderator = interaction.user; + const category = interaction.options.getString('category')!; + const moderator = interaction.user; - //Check if the mod logs channel exists - let modLogsChannel = interaction.guild.channels.resolve(constantsConfig.channels.MOD_LOGS); - if (!modLogsChannel || !modLogsChannel.isTextBased()) { - modLogsChannel = null; - await interaction.followUp({ embeds: [noModLogs], ephemeral: true }); - } + //Check if the mod logs channel exists + let modLogsChannel = interaction.guild.channels.resolve(constantsConfig.channels.MOD_LOGS); + if (!modLogsChannel || !modLogsChannel.isTextBased()) { + modLogsChannel = null; + await interaction.followUp({ embeds: [noModLogs], ephemeral: true }); + } - const existingCategory = await PrefixCommandCategory.findOne({ name: category }); + const existingCategory = await PrefixCommandCategory.findOne({ name: category }); - if (existingCategory) { - const { id: categoryId, name, emoji } = existingCategory; + if (existingCategory) { + const { id: categoryId, name, emoji } = existingCategory; + try { + await clearSinglePrefixCommandCategoryCache(existingCategory); + await existingCategory.deleteOne(); + await interaction.followUp({ embeds: [successEmbed(name || '', categoryId)], ephemeral: true }); + if (modLogsChannel) { try { - await clearSinglePrefixCommandCategoryCache(existingCategory); - await existingCategory.deleteOne(); - await interaction.followUp({ embeds: [successEmbed(name || '', categoryId)], ephemeral: true }); - if (modLogsChannel) { - try { - await modLogsChannel.send({ embeds: [modLogEmbed(moderator, name || '', emoji || '', categoryId)] }); - } catch (error) { - Logger.error(`Failed to post a message to the mod logs channel: ${error}`); - } - } + await modLogsChannel.send({ embeds: [modLogEmbed(moderator, name || '', emoji || '', categoryId)] }); } catch (error) { - Logger.error(`Failed to delete a prefix command category with id ${categoryId}: ${error}`); - await interaction.followUp({ embeds: [failedEmbed(categoryId)], ephemeral: true }); + Logger.error(`Failed to post a message to the mod logs channel: ${error}`); } - } else { - await interaction.followUp({ embeds: [doesNotExistsEmbed(category)], ephemeral: true }); + } + } catch (error) { + Logger.error(`Failed to delete a prefix command category with id ${categoryId}: ${error}`); + await interaction.followUp({ embeds: [failedEmbed(categoryId)], ephemeral: true }); } + } else { + await interaction.followUp({ embeds: [doesNotExistsEmbed(category)], ephemeral: true }); + } } diff --git a/src/commands/moderation/prefixCommands/functions/deleteChannelDefaultVersion.ts b/src/commands/moderation/prefixCommands/functions/deleteChannelDefaultVersion.ts index 8f4c21b8..807eddb8 100644 --- a/src/commands/moderation/prefixCommands/functions/deleteChannelDefaultVersion.ts +++ b/src/commands/moderation/prefixCommands/functions/deleteChannelDefaultVersion.ts @@ -1,89 +1,102 @@ import { ChatInputCommandInteraction, Colors, User } from 'discord.js'; -import { constantsConfig, getConn, PrefixCommandChannelDefaultVersion, Logger, makeEmbed, clearSinglePrefixCommandChannelDefaultVersionCache } from '../../../../lib'; +import { + constantsConfig, + getConn, + PrefixCommandChannelDefaultVersion, + Logger, + makeEmbed, + clearSinglePrefixCommandChannelDefaultVersionCache, +} from '../../../../lib'; const noConnEmbed = makeEmbed({ - title: 'Prefix Commands - Unset Default Channel Version - No Connection', - description: 'Could not connect to the database. Unable to unset the default channel version.', - color: Colors.Red, + title: 'Prefix Commands - Unset Default Channel Version - No Connection', + description: 'Could not connect to the database. Unable to unset the default channel version.', + color: Colors.Red, }); -const failedEmbed = (channel: string) => makeEmbed({ +const failedEmbed = (channel: string) => + makeEmbed({ title: 'Prefix Commands - Unset Default Channel Version - Failed', description: `Failed to unset the default channel version with for ${channel}.`, color: Colors.Red, -}); + }); -const doesNotExistsEmbed = (channel: string) => makeEmbed({ +const doesNotExistsEmbed = (channel: string) => + makeEmbed({ title: 'Prefix Commands - Unset Default Channel Version - Does not exist', description: `The default channel version with for ${channel} does not exists. Can not unset it.`, color: Colors.Red, -}); + }); -const successEmbed = (channel: string) => makeEmbed({ +const successEmbed = (channel: string) => + makeEmbed({ title: `Default channel version for channel ${channel} was unset successfully.`, color: Colors.Green, -}); + }); -const modLogEmbed = (moderator: User, channel: string) => makeEmbed({ +const modLogEmbed = (moderator: User, channel: string) => + makeEmbed({ title: 'Prefix Commands - Default Channel Version unset', fields: [ - { - name: 'Channel', - value: channel, - }, - { - name: 'Moderator', - value: `${moderator}`, - }, + { + name: 'Channel', + value: channel, + }, + { + name: 'Moderator', + value: `${moderator}`, + }, ], color: Colors.Red, -}); + }); const noModLogs = makeEmbed({ - title: 'Prefix Commands - Unset Default Channel Version - No Mod Log', - description: 'I can\'t find the mod logs channel. Please check the channel still exists.', - color: Colors.Red, + title: 'Prefix Commands - Unset Default Channel Version - No Mod Log', + description: "I can't find the mod logs channel. Please check the channel still exists.", + color: Colors.Red, }); -export async function handleDeletePrefixCommandChannelDefaultVersion(interaction: ChatInputCommandInteraction<'cached'>) { - await interaction.deferReply({ ephemeral: true }); +export async function handleDeletePrefixCommandChannelDefaultVersion( + interaction: ChatInputCommandInteraction<'cached'>, +) { + await interaction.deferReply({ ephemeral: true }); - const conn = getConn(); - if (!conn) { - await interaction.followUp({ embeds: [noConnEmbed], ephemeral: true }); - return; - } + const conn = getConn(); + if (!conn) { + await interaction.followUp({ embeds: [noConnEmbed], ephemeral: true }); + return; + } - const channel = interaction.options.getChannel('channel')!; - const moderator = interaction.user; + const channel = interaction.options.getChannel('channel')!; + const moderator = interaction.user; - //Check if the mod logs channel exists - let modLogsChannel = interaction.guild.channels.resolve(constantsConfig.channels.MOD_LOGS); - if (!modLogsChannel || !modLogsChannel.isTextBased()) { - modLogsChannel = null; - await interaction.followUp({ embeds: [noModLogs], ephemeral: true }); - } + //Check if the mod logs channel exists + let modLogsChannel = interaction.guild.channels.resolve(constantsConfig.channels.MOD_LOGS); + if (!modLogsChannel || !modLogsChannel.isTextBased()) { + modLogsChannel = null; + await interaction.followUp({ embeds: [noModLogs], ephemeral: true }); + } - const { id: channelId, name: channelName } = channel; - const existingChannelDefaultVersion = await PrefixCommandChannelDefaultVersion.findOne({ channelId }); + const { id: channelId, name: channelName } = channel; + const existingChannelDefaultVersion = await PrefixCommandChannelDefaultVersion.findOne({ channelId }); - if (existingChannelDefaultVersion) { + if (existingChannelDefaultVersion) { + try { + await clearSinglePrefixCommandChannelDefaultVersionCache(existingChannelDefaultVersion); + await existingChannelDefaultVersion.deleteOne(); + await interaction.followUp({ embeds: [successEmbed(channelName)], ephemeral: true }); + if (modLogsChannel) { try { - await clearSinglePrefixCommandChannelDefaultVersionCache(existingChannelDefaultVersion); - await existingChannelDefaultVersion.deleteOne(); - await interaction.followUp({ embeds: [successEmbed(channelName)], ephemeral: true }); - if (modLogsChannel) { - try { - await modLogsChannel.send({ embeds: [modLogEmbed(moderator, channelName)] }); - } catch (error) { - Logger.error(`Failed to post a message to the mod logs channel: ${error}`); - } - } + await modLogsChannel.send({ embeds: [modLogEmbed(moderator, channelName)] }); } catch (error) { - Logger.error(`Failed to unset a default channel version for channel ${channelName}: ${error}`); - await interaction.followUp({ embeds: [failedEmbed(channelName)], ephemeral: true }); + Logger.error(`Failed to post a message to the mod logs channel: ${error}`); } - } else { - await interaction.followUp({ embeds: [doesNotExistsEmbed(channelName)], ephemeral: true }); + } + } catch (error) { + Logger.error(`Failed to unset a default channel version for channel ${channelName}: ${error}`); + await interaction.followUp({ embeds: [failedEmbed(channelName)], ephemeral: true }); } + } else { + await interaction.followUp({ embeds: [doesNotExistsEmbed(channelName)], ephemeral: true }); + } } diff --git a/src/commands/moderation/prefixCommands/functions/deleteCommand.ts b/src/commands/moderation/prefixCommands/functions/deleteCommand.ts index 97a8226b..31135bb4 100644 --- a/src/commands/moderation/prefixCommands/functions/deleteCommand.ts +++ b/src/commands/moderation/prefixCommands/functions/deleteCommand.ts @@ -1,106 +1,129 @@ import { ChatInputCommandInteraction, Colors, User } from 'discord.js'; -import { constantsConfig, getConn, PrefixCommand, Logger, makeEmbed, clearSinglePrefixCommandCache } from '../../../../lib'; +import { + constantsConfig, + getConn, + PrefixCommand, + Logger, + makeEmbed, + clearSinglePrefixCommandCache, +} from '../../../../lib'; const noConnEmbed = makeEmbed({ - title: 'Prefix Commands - Delete Command - No Connection', - description: 'Could not connect to the database. Unable to delete the prefix command.', - color: Colors.Red, + title: 'Prefix Commands - Delete Command - No Connection', + description: 'Could not connect to the database. Unable to delete the prefix command.', + color: Colors.Red, }); -const failedEmbed = (commandId: string) => makeEmbed({ +const failedEmbed = (commandId: string) => + makeEmbed({ title: 'Prefix Commands - Delete Command - Failed', description: `Failed to delete the prefix command with id ${commandId}.`, color: Colors.Red, -}); + }); -const doesNotExistsEmbed = (command: string) => makeEmbed({ +const doesNotExistsEmbed = (command: string) => + makeEmbed({ title: 'Prefix Commands - Delete Command - Does not exist', description: `The prefix command ${command} does not exists. Cannot delete it.`, color: Colors.Red, -}); + }); -const successEmbed = (command: string, commandId: string) => makeEmbed({ +const successEmbed = (command: string, commandId: string) => + makeEmbed({ title: `Prefix command ${command} (${commandId}) was deleted successfully.`, color: Colors.Green, -}); + }); -const modLogEmbed = (moderator: User, command: string, aliases: string[], description: string, isEmbed: boolean, embedColor: string, commandId: string) => makeEmbed({ +const modLogEmbed = ( + moderator: User, + command: string, + aliases: string[], + description: string, + isEmbed: boolean, + embedColor: string, + commandId: string, +) => + makeEmbed({ title: 'Prefix command deleted', fields: [ - { - name: 'Command', - value: command, - }, - { - name: 'Moderator', - value: `${moderator}`, - }, - { - name: 'Aliases', - value: aliases.join(','), - }, - { - name: 'Description', - value: description, - }, - { - name: 'Is Embed', - value: isEmbed ? 'Yes' : 'No', - }, - { - name: 'Embed Color', - value: embedColor || '', - }, + { + name: 'Command', + value: command, + }, + { + name: 'Moderator', + value: `${moderator}`, + }, + { + name: 'Aliases', + value: aliases.join(','), + }, + { + name: 'Description', + value: description, + }, + { + name: 'Is Embed', + value: isEmbed ? 'Yes' : 'No', + }, + { + name: 'Embed Color', + value: embedColor || '', + }, ], footer: { text: `Command ID: ${commandId}` }, color: Colors.Red, -}); + }); const noModLogs = makeEmbed({ - title: 'Prefix Commands - Delete Command - No Mod Log', - description: 'I can\'t find the mod logs channel. Please check the channel still exists.', - color: Colors.Red, + title: 'Prefix Commands - Delete Command - No Mod Log', + description: "I can't find the mod logs channel. Please check the channel still exists.", + color: Colors.Red, }); export async function handleDeletePrefixCommand(interaction: ChatInputCommandInteraction<'cached'>) { - await interaction.deferReply({ ephemeral: true }); + await interaction.deferReply({ ephemeral: true }); - const conn = getConn(); - if (!conn) { - await interaction.followUp({ embeds: [noConnEmbed], ephemeral: true }); - return; - } + const conn = getConn(); + if (!conn) { + await interaction.followUp({ embeds: [noConnEmbed], ephemeral: true }); + return; + } - const command = interaction.options.getString('command')!; - const moderator = interaction.user; + const command = interaction.options.getString('command')!; + const moderator = interaction.user; - //Check if the mod logs channel exists - let modLogsChannel = interaction.guild.channels.resolve(constantsConfig.channels.MOD_LOGS); - if (!modLogsChannel || !modLogsChannel.isTextBased()) { - modLogsChannel = null; - await interaction.followUp({ embeds: [noModLogs], ephemeral: true }); - } + //Check if the mod logs channel exists + let modLogsChannel = interaction.guild.channels.resolve(constantsConfig.channels.MOD_LOGS); + if (!modLogsChannel || !modLogsChannel.isTextBased()) { + modLogsChannel = null; + await interaction.followUp({ embeds: [noModLogs], ephemeral: true }); + } - const existingCommand = await PrefixCommand.findOne({ name: command }); + const existingCommand = await PrefixCommand.findOne({ name: command }); - if (existingCommand) { - const { id: commandId, name, description, aliases, isEmbed, embedColor } = existingCommand; + if (existingCommand) { + const { id: commandId, name, description, aliases, isEmbed, embedColor } = existingCommand; + try { + await clearSinglePrefixCommandCache(existingCommand); + await existingCommand.deleteOne(); + await interaction.followUp({ embeds: [successEmbed(name || '', commandId)], ephemeral: true }); + if (modLogsChannel) { try { - await clearSinglePrefixCommandCache(existingCommand); - await existingCommand.deleteOne(); - await interaction.followUp({ embeds: [successEmbed(name || '', commandId)], ephemeral: true }); - if (modLogsChannel) { - try { - await modLogsChannel.send({ embeds: [modLogEmbed(moderator, name || '', aliases, description, isEmbed || false, embedColor || '', commandId)] }); - } catch (error) { - Logger.error(`Failed to post a message to the mod logs channel: ${error}`); - } - } + await modLogsChannel.send({ + embeds: [ + modLogEmbed(moderator, name || '', aliases, description, isEmbed || false, embedColor || '', commandId), + ], + }); } catch (error) { - Logger.error(`Failed to delete a prefix command command with id ${commandId}: ${error}`); - await interaction.followUp({ embeds: [failedEmbed(commandId)], ephemeral: true }); + Logger.error(`Failed to post a message to the mod logs channel: ${error}`); } - } else { - await interaction.followUp({ embeds: [doesNotExistsEmbed(command)], ephemeral: true }); + } + } catch (error) { + Logger.error(`Failed to delete a prefix command command with id ${commandId}: ${error}`); + await interaction.followUp({ embeds: [failedEmbed(commandId)], ephemeral: true }); } + } else { + await interaction.followUp({ embeds: [doesNotExistsEmbed(command)], ephemeral: true }); + } } diff --git a/src/commands/moderation/prefixCommands/functions/deleteContent.ts b/src/commands/moderation/prefixCommands/functions/deleteContent.ts index 2b27df0c..c33f5a99 100644 --- a/src/commands/moderation/prefixCommands/functions/deleteContent.ts +++ b/src/commands/moderation/prefixCommands/functions/deleteContent.ts @@ -1,146 +1,171 @@ import { ChatInputCommandInteraction, Colors, User } from 'discord.js'; -import { constantsConfig, getConn, Logger, makeEmbed, PrefixCommand, PrefixCommandVersion, refreshSinglePrefixCommandCache } from '../../../../lib'; +import { + constantsConfig, + getConn, + Logger, + makeEmbed, + PrefixCommand, + PrefixCommandVersion, + refreshSinglePrefixCommandCache, +} from '../../../../lib'; const noConnEmbed = makeEmbed({ - title: 'Prefix Commands - Delete Content - No Connection', - description: 'Could not connect to the database. Unable to delete the prefix command content.', - color: Colors.Red, + title: 'Prefix Commands - Delete Content - No Connection', + description: 'Could not connect to the database. Unable to delete the prefix command content.', + color: Colors.Red, }); -const noContentEmbed = (command: string, version: string) => makeEmbed({ +const noContentEmbed = (command: string, version: string) => + makeEmbed({ title: 'Prefix Commands - Delete Content - No Content', description: `Failed to delete command content for command ${command} and version ${version} as the content does not exist.`, color: Colors.Red, -}); + }); -const noCommandEmbed = (command: string) => makeEmbed({ +const noCommandEmbed = (command: string) => + makeEmbed({ title: 'Prefix Commands - Delete Content - No Command', description: `Failed to delete command content for command ${command} as the command does not exist or there are more than one matching.`, color: Colors.Red, -}); + }); -const noVersionEmbed = (version: string) => makeEmbed({ +const noVersionEmbed = (version: string) => + makeEmbed({ title: 'Prefix Commands - Delete Content - No Version', description: `Failed to delete command content for version ${version} as the version does not exist or there are more than one matching.`, color: Colors.Red, -}); + }); -const failedEmbed = (version: string) => makeEmbed({ +const failedEmbed = (version: string) => + makeEmbed({ title: 'Prefix Commands - Delete Content - Failed', description: `Failed to delete the prefix command content with version ${version}.`, color: Colors.Red, -}); + }); -const successEmbed = (command: string, version: string) => makeEmbed({ +const successEmbed = (command: string, version: string) => + makeEmbed({ title: `Prefix command content for command ${command} and version ${version} was deleted successfully.`, color: Colors.Green, -}); + }); -const modLogEmbed = (moderator: User, commandName: string, versionName: string, title: string, content: string, image: string) => makeEmbed({ +const modLogEmbed = ( + moderator: User, + commandName: string, + versionName: string, + title: string, + content: string, + image: string, +) => + makeEmbed({ title: 'Prefix command content delete', fields: [ - { - name: 'Command', - value: commandName, - }, - { - name: 'Version', - value: versionName, - }, - { - name: 'Title', - value: title, - }, - { - name: 'Content', - value: content, - }, - { - name: 'Image', - value: image, - }, - { - name: 'Moderator', - value: `${moderator}`, - }, + { + name: 'Command', + value: commandName, + }, + { + name: 'Version', + value: versionName, + }, + { + name: 'Title', + value: title, + }, + { + name: 'Content', + value: content, + }, + { + name: 'Image', + value: image, + }, + { + name: 'Moderator', + value: `${moderator}`, + }, ], color: Colors.Red, -}); + }); const noModLogs = makeEmbed({ - title: 'Prefix Commands - Delete Content - No Mod Log', - description: 'I can\'t find the mod logs channel. Please check the channel still exists.', - color: Colors.Red, + title: 'Prefix Commands - Delete Content - No Mod Log', + description: "I can't find the mod logs channel. Please check the channel still exists.", + color: Colors.Red, }); export async function handleDeletePrefixCommandContent(interaction: ChatInputCommandInteraction<'cached'>) { - await interaction.deferReply({ ephemeral: true }); + await interaction.deferReply({ ephemeral: true }); - const conn = getConn(); - if (!conn) { - await interaction.followUp({ embeds: [noConnEmbed], ephemeral: true }); - return; - } + const conn = getConn(); + if (!conn) { + await interaction.followUp({ embeds: [noConnEmbed], ephemeral: true }); + return; + } - const command = interaction.options.getString('command')!; - const version = interaction.options.getString('version')!; - const moderator = interaction.user; + const command = interaction.options.getString('command')!; + const version = interaction.options.getString('version')!; + const moderator = interaction.user; - //Check if the mod logs channel exists - let modLogsChannel = interaction.guild.channels.resolve(constantsConfig.channels.MOD_LOGS); - if (!modLogsChannel || !modLogsChannel.isTextBased()) { - modLogsChannel = null; - await interaction.followUp({ embeds: [noModLogs], ephemeral: true }); - } + //Check if the mod logs channel exists + let modLogsChannel = interaction.guild.channels.resolve(constantsConfig.channels.MOD_LOGS); + if (!modLogsChannel || !modLogsChannel.isTextBased()) { + modLogsChannel = null; + await interaction.followUp({ embeds: [noModLogs], ephemeral: true }); + } - const foundCommand = await PrefixCommand.findOne({ name: command }); - if (!foundCommand) { - await interaction.followUp({ embeds: [noCommandEmbed(command)], ephemeral: true }); - return; - } - let versionId = ''; - let foundVersions = null; - if (version === 'GENERIC' || version === 'generic') { - versionId = 'GENERIC'; + const foundCommand = await PrefixCommand.findOne({ name: command }); + if (!foundCommand) { + await interaction.followUp({ embeds: [noCommandEmbed(command)], ephemeral: true }); + return; + } + let versionId = ''; + let foundVersions = null; + if (version === 'GENERIC' || version === 'generic') { + versionId = 'GENERIC'; + } else { + foundVersions = await PrefixCommandVersion.find({ name: version }); + if (foundVersions && foundVersions.length === 1) { + [{ _id: versionId }] = foundVersions; } else { - foundVersions = await PrefixCommandVersion.find({ name: version }); - if (foundVersions && foundVersions.length === 1) { - [{ _id: versionId }] = foundVersions; - } else { - await interaction.followUp({ embeds: [noVersionEmbed(version)], ephemeral: true }); - return; - } + await interaction.followUp({ embeds: [noVersionEmbed(version)], ephemeral: true }); + return; } - const existingContent = foundCommand.contents.find((content) => content.versionId.toString() === versionId.toString()); + } + const existingContent = foundCommand.contents.find( + (content) => content.versionId.toString() === versionId.toString(), + ); - if (foundCommand && existingContent) { - const { title, content, image } = existingContent; - const { name: commandName } = foundCommand; - let versionName = ''; - if (versionId !== 'GENERIC') { - const foundVersion = await PrefixCommandVersion.findById(versionId); - if (!foundVersion) { - return; - } - versionName = foundVersion.name || ''; - } + if (foundCommand && existingContent) { + const { title, content, image } = existingContent; + const { name: commandName } = foundCommand; + let versionName = ''; + if (versionId !== 'GENERIC') { + const foundVersion = await PrefixCommandVersion.findById(versionId); + if (!foundVersion) { + return; + } + versionName = foundVersion.name || ''; + } + try { + foundCommand.contents.find((con) => con.versionId.toString() === versionId.toString())?.deleteOne(); + await foundCommand.save(); + await refreshSinglePrefixCommandCache(foundCommand, foundCommand); + await interaction.followUp({ embeds: [successEmbed(`${commandName}`, `${versionName}`)], ephemeral: true }); + if (modLogsChannel) { try { - foundCommand.contents.find((con) => con.versionId.toString() === versionId.toString())?.deleteOne(); - await foundCommand.save(); - await refreshSinglePrefixCommandCache(foundCommand, foundCommand); - await interaction.followUp({ embeds: [successEmbed(`${commandName}`, `${versionName}`)], ephemeral: true }); - if (modLogsChannel) { - try { - await modLogsChannel.send({ embeds: [modLogEmbed(moderator, `${commandName}`, `${versionName}`, `${title}`, `${content}`, `${image}`)] }); - } catch (error) { - Logger.error(`Failed to post a message to the mod logs channel: ${error}`); - } - } + await modLogsChannel.send({ + embeds: [modLogEmbed(moderator, `${commandName}`, `${versionName}`, `${title}`, `${content}`, `${image}`)], + }); } catch (error) { - Logger.error(`Failed to delete a prefix command content with version ${version}: ${error}`); - await interaction.followUp({ embeds: [failedEmbed(version)], ephemeral: true }); + Logger.error(`Failed to post a message to the mod logs channel: ${error}`); } - } else { - await interaction.followUp({ embeds: [noContentEmbed(command, version)], ephemeral: true }); + } + } catch (error) { + Logger.error(`Failed to delete a prefix command content with version ${version}: ${error}`); + await interaction.followUp({ embeds: [failedEmbed(version)], ephemeral: true }); } + } else { + await interaction.followUp({ embeds: [noContentEmbed(command, version)], ephemeral: true }); + } } diff --git a/src/commands/moderation/prefixCommands/functions/deleteVersion.ts b/src/commands/moderation/prefixCommands/functions/deleteVersion.ts index d73cd26f..9e1eb26b 100644 --- a/src/commands/moderation/prefixCommands/functions/deleteVersion.ts +++ b/src/commands/moderation/prefixCommands/functions/deleteVersion.ts @@ -1,150 +1,180 @@ import { ChatInputCommandInteraction, Colors, User } from 'discord.js'; -import { constantsConfig, getConn, PrefixCommandVersion, Logger, makeEmbed, PrefixCommandChannelDefaultVersion, clearSinglePrefixCommandVersionCache, PrefixCommand, refreshSinglePrefixCommandCache, clearSinglePrefixCommandChannelDefaultVersionCache } from '../../../../lib'; +import { + constantsConfig, + getConn, + PrefixCommandVersion, + Logger, + makeEmbed, + PrefixCommandChannelDefaultVersion, + clearSinglePrefixCommandVersionCache, + PrefixCommand, + refreshSinglePrefixCommandCache, + clearSinglePrefixCommandChannelDefaultVersionCache, +} from '../../../../lib'; const noConnEmbed = makeEmbed({ - title: 'Prefix Commands - Delete Version - No Connection', - description: 'Could not connect to the database. Unable to delete the prefix command version.', - color: Colors.Red, + title: 'Prefix Commands - Delete Version - No Connection', + description: 'Could not connect to the database. Unable to delete the prefix command version.', + color: Colors.Red, }); const contentPresentEmbed = makeEmbed({ - title: 'Prefix Commands - Delete Version - Content Present', - description: 'There is content present for this command version. Please delete the content first, or use the `force` option to delete the command version and all the command contents for the version.', - color: Colors.Red, + title: 'Prefix Commands - Delete Version - Content Present', + description: + 'There is content present for this command version. Please delete the content first, or use the `force` option to delete the command version and all the command contents for the version.', + color: Colors.Red, }); const channelDefaultVersionPresentEmbed = makeEmbed({ - title: 'Prefix Commands - Delete Version - Default Channel Versions Present', - description: 'There is one or more channel with this version selected as its default version. Please change or unset the default version for those channels first, or use the `force` option to delete the command version and all the default channel versions referencing it (making them default back to the GENERIC version).', - color: Colors.Red, + title: 'Prefix Commands - Delete Version - Default Channel Versions Present', + description: + 'There is one or more channel with this version selected as its default version. Please change or unset the default version for those channels first, or use the `force` option to delete the command version and all the default channel versions referencing it (making them default back to the GENERIC version).', + color: Colors.Red, }); -const failedEmbed = (versionId: string) => makeEmbed({ +const failedEmbed = (versionId: string) => + makeEmbed({ title: 'Prefix Commands - Delete Version - Failed', description: `Failed to delete the prefix command version with id ${versionId}.`, color: Colors.Red, -}); + }); -const doesNotExistsEmbed = (version: string) => makeEmbed({ +const doesNotExistsEmbed = (version: string) => + makeEmbed({ title: 'Prefix Commands - Delete Version - Does not exist', description: `The prefix command version ${version} does not exists. Cannot delete it.`, color: Colors.Red, -}); + }); -const successEmbed = (version: string, versionId: string) => makeEmbed({ +const successEmbed = (version: string, versionId: string) => + makeEmbed({ title: `Prefix command version ${version} (${versionId}) was deleted successfully.`, color: Colors.Green, -}); + }); -const modLogEmbed = (moderator: User, version: string, emoji: string, alias: string, enabled: boolean, versionId: string) => makeEmbed({ +const modLogEmbed = ( + moderator: User, + version: string, + emoji: string, + alias: string, + enabled: boolean, + versionId: string, +) => + makeEmbed({ title: 'Prefix command version deleted', fields: [ - { - name: 'Version', - value: version, - }, - { - name: 'Moderator', - value: `${moderator}`, - }, - { - name: 'Emoji', - value: emoji, - }, - { - name: 'Alias', - value: alias, - }, - { - name: 'Enabled', - value: enabled ? 'Yes' : 'No', - }, + { + name: 'Version', + value: version, + }, + { + name: 'Moderator', + value: `${moderator}`, + }, + { + name: 'Emoji', + value: emoji, + }, + { + name: 'Alias', + value: alias, + }, + { + name: 'Enabled', + value: enabled ? 'Yes' : 'No', + }, ], footer: { text: `Version ID: ${versionId}` }, color: Colors.Red, -}); + }); const noModLogs = makeEmbed({ - title: 'Prefix Commands - Delete Version - No Mod Log', - description: 'I can\'t find the mod logs channel. Please check the channel still exists.', - color: Colors.Red, + title: 'Prefix Commands - Delete Version - No Mod Log', + description: "I can't find the mod logs channel. Please check the channel still exists.", + color: Colors.Red, }); export async function handleDeletePrefixCommandVersion(interaction: ChatInputCommandInteraction<'cached'>) { - await interaction.deferReply({ ephemeral: true }); + await interaction.deferReply({ ephemeral: true }); - const conn = getConn(); - if (!conn) { - await interaction.followUp({ embeds: [noConnEmbed], ephemeral: true }); - return; - } + const conn = getConn(); + if (!conn) { + await interaction.followUp({ embeds: [noConnEmbed], ephemeral: true }); + return; + } - const version = interaction.options.getString('version')!; - const force = interaction.options.getBoolean('force') || false; - const moderator = interaction.user; + const version = interaction.options.getString('version')!; + const force = interaction.options.getBoolean('force') || false; + const moderator = interaction.user; - //Check if the mod logs channel exists - let modLogsChannel = interaction.guild.channels.resolve(constantsConfig.channels.MOD_LOGS); - if (!modLogsChannel || !modLogsChannel.isTextBased()) { - modLogsChannel = null; - await interaction.followUp({ embeds: [noModLogs], ephemeral: true }); - } + //Check if the mod logs channel exists + let modLogsChannel = interaction.guild.channels.resolve(constantsConfig.channels.MOD_LOGS); + if (!modLogsChannel || !modLogsChannel.isTextBased()) { + modLogsChannel = null; + await interaction.followUp({ embeds: [noModLogs], ephemeral: true }); + } - const existingVersion = await PrefixCommandVersion.findOne({ name: version }); - if (!existingVersion) { - await interaction.followUp({ embeds: [doesNotExistsEmbed(version)], ephemeral: true }); - return; - } - const { id: versionId } = existingVersion; - // Find all PrefixCommands with content where version ID == versionId - const foundCommandsWithContent = await PrefixCommand.find({ 'contents.versionId': versionId }); - if (foundCommandsWithContent && foundCommandsWithContent.length > 0 && !force) { - await interaction.followUp({ embeds: [contentPresentEmbed], ephemeral: true }); - return; - } - const foundChannelDefaultVersions = await PrefixCommandChannelDefaultVersion.find({ versionId }); - if (foundChannelDefaultVersions && foundChannelDefaultVersions.length > 0 && !force) { - await interaction.followUp({ embeds: [channelDefaultVersionPresentEmbed], ephemeral: true }); - return; - } + const existingVersion = await PrefixCommandVersion.findOne({ name: version }); + if (!existingVersion) { + await interaction.followUp({ embeds: [doesNotExistsEmbed(version)], ephemeral: true }); + return; + } + const { id: versionId } = existingVersion; + // Find all PrefixCommands with content where version ID == versionId + const foundCommandsWithContent = await PrefixCommand.find({ 'contents.versionId': versionId }); + if (foundCommandsWithContent && foundCommandsWithContent.length > 0 && !force) { + await interaction.followUp({ embeds: [contentPresentEmbed], ephemeral: true }); + return; + } + const foundChannelDefaultVersions = await PrefixCommandChannelDefaultVersion.find({ versionId }); + if (foundChannelDefaultVersions && foundChannelDefaultVersions.length > 0 && !force) { + await interaction.followUp({ embeds: [channelDefaultVersionPresentEmbed], ephemeral: true }); + return; + } - if (existingVersion) { - const { name, emoji, enabled, alias } = existingVersion; + if (existingVersion) { + const { name, emoji, enabled, alias } = existingVersion; + try { + if (foundCommandsWithContent && force) { + for (const command of foundCommandsWithContent) { + const { _id: commandId } = command; + // eslint-disable-next-line no-await-in-loop + const updatedCommand = await PrefixCommand.findOneAndUpdate( + { _id: commandId }, + { $pull: { contents: { versionId } } }, + { new: true }, + ); + if (updatedCommand) { + // eslint-disable-next-line no-await-in-loop + await refreshSinglePrefixCommandCache(command, updatedCommand); + } + } + } + if (foundChannelDefaultVersions && force) { + for (const channelDefaultVersion of foundChannelDefaultVersions) { + // eslint-disable-next-line no-await-in-loop + await clearSinglePrefixCommandChannelDefaultVersionCache(channelDefaultVersion); + // eslint-disable-next-line no-await-in-loop + await channelDefaultVersion.deleteOne(); + } + } + await clearSinglePrefixCommandVersionCache(existingVersion); + await existingVersion.deleteOne(); + await interaction.followUp({ embeds: [successEmbed(name || '', versionId)], ephemeral: true }); + if (modLogsChannel) { try { - if (foundCommandsWithContent && force) { - for (const command of foundCommandsWithContent) { - const { _id: commandId } = command; - // eslint-disable-next-line no-await-in-loop - const updatedCommand = await PrefixCommand.findOneAndUpdate({ _id: commandId }, { $pull: { contents: { versionId } } }, { new: true }); - if (updatedCommand) { - // eslint-disable-next-line no-await-in-loop - await refreshSinglePrefixCommandCache(command, updatedCommand); - } - } - } - if (foundChannelDefaultVersions && force) { - for (const channelDefaultVersion of foundChannelDefaultVersions) { - // eslint-disable-next-line no-await-in-loop - await clearSinglePrefixCommandChannelDefaultVersionCache(channelDefaultVersion); - // eslint-disable-next-line no-await-in-loop - await channelDefaultVersion.deleteOne(); - } - } - await clearSinglePrefixCommandVersionCache(existingVersion); - await existingVersion.deleteOne(); - await interaction.followUp({ embeds: [successEmbed(name || '', versionId)], ephemeral: true }); - if (modLogsChannel) { - try { - await modLogsChannel.send({ embeds: [modLogEmbed(moderator, name || '', emoji || '', alias || '', enabled || false, versionId)] }); - } catch (error) { - Logger.error(`Failed to post a message to the mod logs channel: ${error}`); - } - } + await modLogsChannel.send({ + embeds: [modLogEmbed(moderator, name || '', emoji || '', alias || '', enabled || false, versionId)], + }); } catch (error) { - Logger.error(`Failed to delete a prefix command version with id ${versionId}: ${error}`); - await interaction.followUp({ embeds: [failedEmbed(versionId)], ephemeral: true }); + Logger.error(`Failed to post a message to the mod logs channel: ${error}`); } - } else { - await interaction.followUp({ embeds: [doesNotExistsEmbed(versionId)], ephemeral: true }); + } + } catch (error) { + Logger.error(`Failed to delete a prefix command version with id ${versionId}: ${error}`); + await interaction.followUp({ embeds: [failedEmbed(versionId)], ephemeral: true }); } + } else { + await interaction.followUp({ embeds: [doesNotExistsEmbed(versionId)], ephemeral: true }); + } } diff --git a/src/commands/moderation/prefixCommands/functions/listCategories.ts b/src/commands/moderation/prefixCommands/functions/listCategories.ts index 588e0921..0a74a503 100644 --- a/src/commands/moderation/prefixCommands/functions/listCategories.ts +++ b/src/commands/moderation/prefixCommands/functions/listCategories.ts @@ -2,58 +2,61 @@ import { APIEmbedField, ChatInputCommandInteraction, Colors } from 'discord.js'; import { getConn, PrefixCommandCategory, Logger, makeEmbed } from '../../../../lib'; const noConnEmbed = makeEmbed({ - title: 'Prefix Commands - List Categories - No Connection', - description: 'Could not connect to the database. Unable to list the prefix command categories.', - color: Colors.Red, + title: 'Prefix Commands - List Categories - No Connection', + description: 'Could not connect to the database. Unable to list the prefix command categories.', + color: Colors.Red, }); -const failedEmbed = (searchText: string) => makeEmbed({ +const failedEmbed = (searchText: string) => + makeEmbed({ title: 'Prefix Commands - List Categories - Failed', description: `Failed to list the prefix command categories with search text: ${searchText}.`, color: Colors.Red, -}); + }); -const noResultsEmbed = (searchText: string) => makeEmbed({ +const noResultsEmbed = (searchText: string) => + makeEmbed({ title: 'Prefix Commands - List Categories - Does not exist', description: `No prefix command categories found matching the search text: ${searchText}.`, -}); + }); -const successEmbed = (searchText: string, fields: APIEmbedField[]) => makeEmbed({ +const successEmbed = (searchText: string, fields: APIEmbedField[]) => + makeEmbed({ title: 'Prefix Commands - Categories', description: searchText ? `Matching search: ${searchText} - Maximum of 20 shown` : 'Maximum of 20 shown', fields, color: Colors.Green, -}); + }); export async function handleListPrefixCommandCategories(interaction: ChatInputCommandInteraction<'cached'>) { - await interaction.deferReply({ ephemeral: true }); - - const conn = getConn(); - if (!conn) { - await interaction.followUp({ embeds: [noConnEmbed], ephemeral: true }); - return; + await interaction.deferReply({ ephemeral: true }); + + const conn = getConn(); + if (!conn) { + await interaction.followUp({ embeds: [noConnEmbed], ephemeral: true }); + return; + } + + const searchText = interaction.options.getString('search_text') || ''; + const foundCategories = await PrefixCommandCategory.find({ name: { $regex: searchText, $options: 'i' } }); + + if (foundCategories) { + const embedFields: APIEmbedField[] = []; + for (let i = 0; i < foundCategories.length && i < 20; i++) { + const category = foundCategories[i]; + const { id, name, emoji } = category; + embedFields.push({ + name: `${name} - ${emoji}`, + value: `${id}`, + }); } - - const searchText = interaction.options.getString('search_text') || ''; - const foundCategories = await PrefixCommandCategory.find({ name: { $regex: searchText, $options: 'i' } }); - - if (foundCategories) { - const embedFields: APIEmbedField[] = []; - for (let i = 0; i < foundCategories.length && i < 20; i++) { - const category = foundCategories[i]; - const { id, name, emoji } = category; - embedFields.push({ - name: `${name} - ${emoji}`, - value: `${id}`, - }); - } - try { - await interaction.followUp({ embeds: [successEmbed(searchText, embedFields)], ephemeral: false }); - } catch (error) { - Logger.error(`Failed to list prefix command categories with search ${searchText}: ${error}`); - await interaction.followUp({ embeds: [failedEmbed(searchText)], ephemeral: true }); - } - } else { - await interaction.followUp({ embeds: [noResultsEmbed(searchText)], ephemeral: true }); + try { + await interaction.followUp({ embeds: [successEmbed(searchText, embedFields)], ephemeral: false }); + } catch (error) { + Logger.error(`Failed to list prefix command categories with search ${searchText}: ${error}`); + await interaction.followUp({ embeds: [failedEmbed(searchText)], ephemeral: true }); } + } else { + await interaction.followUp({ embeds: [noResultsEmbed(searchText)], ephemeral: true }); + } } diff --git a/src/commands/moderation/prefixCommands/functions/listCommands.ts b/src/commands/moderation/prefixCommands/functions/listCommands.ts index b48c830a..34848205 100644 --- a/src/commands/moderation/prefixCommands/functions/listCommands.ts +++ b/src/commands/moderation/prefixCommands/functions/listCommands.ts @@ -2,58 +2,61 @@ import { APIEmbedField, ChatInputCommandInteraction, Colors } from 'discord.js'; import { getConn, PrefixCommand, Logger, makeEmbed } from '../../../../lib'; const noConnEmbed = makeEmbed({ - title: 'Prefix Commands - List Commands - No Connection', - description: 'Could not connect to the database. Unable to list the prefix commands.', - color: Colors.Red, + title: 'Prefix Commands - List Commands - No Connection', + description: 'Could not connect to the database. Unable to list the prefix commands.', + color: Colors.Red, }); -const failedEmbed = (searchText: string) => makeEmbed({ +const failedEmbed = (searchText: string) => + makeEmbed({ title: 'Prefix Commands - List Commands - Failed', description: `Failed to list the prefix commands with search text: ${searchText}.`, color: Colors.Red, -}); + }); -const noResultsEmbed = (searchText: string) => makeEmbed({ +const noResultsEmbed = (searchText: string) => + makeEmbed({ title: 'Prefix Commands - List Commands - Does not exist', description: `No prefix commands found matching the search text: ${searchText}.`, -}); + }); -const successEmbed = (searchText: string, fields: APIEmbedField[]) => makeEmbed({ +const successEmbed = (searchText: string, fields: APIEmbedField[]) => + makeEmbed({ title: 'Prefix Commands', description: searchText ? `Matching search: ${searchText} - Maximum of 20 shown` : 'Maximum of 20 shown', fields, color: Colors.Green, -}); + }); export async function handleListPrefixCommands(interaction: ChatInputCommandInteraction<'cached'>) { - await interaction.deferReply({ ephemeral: true }); - - const conn = getConn(); - if (!conn) { - await interaction.followUp({ embeds: [noConnEmbed], ephemeral: true }); - return; + await interaction.deferReply({ ephemeral: true }); + + const conn = getConn(); + if (!conn) { + await interaction.followUp({ embeds: [noConnEmbed], ephemeral: true }); + return; + } + + const searchText = interaction.options.getString('search_text') || ''; + const foundCommands = await PrefixCommand.find({ name: { $regex: searchText, $options: 'i' } }); + + if (foundCommands) { + const embedFields: APIEmbedField[] = []; + for (let i = 0; i < foundCommands.length && i < 20; i++) { + const command = foundCommands[i]; + const { name, description, aliases, isEmbed, embedColor } = command; + embedFields.push({ + name: `${name} - ${aliases.join(',')} - ${isEmbed ? 'Embed' : 'No Embed'} - ${embedColor || 'No Color'}`, + value: `${description}`, + }); } - - const searchText = interaction.options.getString('search_text') || ''; - const foundCommands = await PrefixCommand.find({ name: { $regex: searchText, $options: 'i' } }); - - if (foundCommands) { - const embedFields: APIEmbedField[] = []; - for (let i = 0; i < foundCommands.length && i < 20; i++) { - const command = foundCommands[i]; - const { name, description, aliases, isEmbed, embedColor } = command; - embedFields.push({ - name: `${name} - ${aliases.join(',')} - ${isEmbed ? 'Embed' : 'No Embed'} - ${embedColor || 'No Color'}`, - value: `${description}`, - }); - } - try { - await interaction.followUp({ embeds: [successEmbed(searchText, embedFields)], ephemeral: false }); - } catch (error) { - Logger.error(`Failed to list prefix command commands with search ${searchText}: ${error}`); - await interaction.followUp({ embeds: [failedEmbed(searchText)], ephemeral: true }); - } - } else { - await interaction.followUp({ embeds: [noResultsEmbed(searchText)], ephemeral: true }); + try { + await interaction.followUp({ embeds: [successEmbed(searchText, embedFields)], ephemeral: false }); + } catch (error) { + Logger.error(`Failed to list prefix command commands with search ${searchText}: ${error}`); + await interaction.followUp({ embeds: [failedEmbed(searchText)], ephemeral: true }); } + } else { + await interaction.followUp({ embeds: [noResultsEmbed(searchText)], ephemeral: true }); + } } diff --git a/src/commands/moderation/prefixCommands/functions/listVersions.ts b/src/commands/moderation/prefixCommands/functions/listVersions.ts index f1023038..922daf5f 100644 --- a/src/commands/moderation/prefixCommands/functions/listVersions.ts +++ b/src/commands/moderation/prefixCommands/functions/listVersions.ts @@ -2,58 +2,61 @@ import { APIEmbedField, ChatInputCommandInteraction, Colors } from 'discord.js'; import { getConn, PrefixCommandVersion, Logger, makeEmbed } from '../../../../lib'; const noConnEmbed = makeEmbed({ - title: 'Prefix Commands - List Versions - No Connection', - description: 'Could not connect to the database. Unable to list the prefix command versions.', - color: Colors.Red, + title: 'Prefix Commands - List Versions - No Connection', + description: 'Could not connect to the database. Unable to list the prefix command versions.', + color: Colors.Red, }); -const failedEmbed = (searchText: string) => makeEmbed({ +const failedEmbed = (searchText: string) => + makeEmbed({ title: 'Prefix Commands - List Versions - Failed', description: `Failed to list the prefix command versions with search text: ${searchText}.`, color: Colors.Red, -}); + }); -const noResultsEmbed = (searchText: string) => makeEmbed({ +const noResultsEmbed = (searchText: string) => + makeEmbed({ title: 'Prefix Commands - List Versions - Does not exist', description: `No prefix command versions found matching the search text: ${searchText}.`, -}); + }); -const successEmbed = (searchText: string, fields: APIEmbedField[]) => makeEmbed({ +const successEmbed = (searchText: string, fields: APIEmbedField[]) => + makeEmbed({ title: 'Prefix Commands - Versions', description: searchText ? `Matching search: ${searchText} - Maximum of 20 shown` : 'Maximum of 20 shown', fields, color: Colors.Green, -}); + }); export async function handleListPrefixCommandVersions(interaction: ChatInputCommandInteraction<'cached'>) { - await interaction.deferReply({ ephemeral: true }); - - const conn = getConn(); - if (!conn) { - await interaction.followUp({ embeds: [noConnEmbed], ephemeral: true }); - return; + await interaction.deferReply({ ephemeral: true }); + + const conn = getConn(); + if (!conn) { + await interaction.followUp({ embeds: [noConnEmbed], ephemeral: true }); + return; + } + + const searchText = interaction.options.getString('search_text') || ''; + const foundVersions = await PrefixCommandVersion.find({ name: { $regex: searchText, $options: 'i' } }); + + if (foundVersions) { + const embedFields: APIEmbedField[] = []; + for (let i = 0; i < foundVersions.length && i < 20; i++) { + const version = foundVersions[i]; + const { id, name, emoji, enabled, alias } = version; + embedFields.push({ + name: `${name} - ${emoji} - ${enabled ? 'Enabled' : 'Disabled'} - ${alias}`, + value: `${id}`, + }); } - - const searchText = interaction.options.getString('search_text') || ''; - const foundVersions = await PrefixCommandVersion.find({ name: { $regex: searchText, $options: 'i' } }); - - if (foundVersions) { - const embedFields: APIEmbedField[] = []; - for (let i = 0; i < foundVersions.length && i < 20; i++) { - const version = foundVersions[i]; - const { id, name, emoji, enabled, alias } = version; - embedFields.push({ - name: `${name} - ${emoji} - ${enabled ? 'Enabled' : 'Disabled'} - ${alias}`, - value: `${id}`, - }); - } - try { - await interaction.followUp({ embeds: [successEmbed(searchText, embedFields)], ephemeral: false }); - } catch (error) { - Logger.error(`Failed to list prefix command versions with search ${searchText}: ${error}`); - await interaction.followUp({ embeds: [failedEmbed(searchText)], ephemeral: true }); - } - } else { - await interaction.followUp({ embeds: [noResultsEmbed(searchText)], ephemeral: true }); + try { + await interaction.followUp({ embeds: [successEmbed(searchText, embedFields)], ephemeral: false }); + } catch (error) { + Logger.error(`Failed to list prefix command versions with search ${searchText}: ${error}`); + await interaction.followUp({ embeds: [failedEmbed(searchText)], ephemeral: true }); } + } else { + await interaction.followUp({ embeds: [noResultsEmbed(searchText)], ephemeral: true }); + } } diff --git a/src/commands/moderation/prefixCommands/functions/modifyCategory.ts b/src/commands/moderation/prefixCommands/functions/modifyCategory.ts index 3d2e6a24..972c49fc 100644 --- a/src/commands/moderation/prefixCommands/functions/modifyCategory.ts +++ b/src/commands/moderation/prefixCommands/functions/modifyCategory.ts @@ -1,100 +1,111 @@ import { ChatInputCommandInteraction, Colors, User } from 'discord.js'; -import { constantsConfig, getConn, PrefixCommandCategory, Logger, makeEmbed, refreshSinglePrefixCommandCategoryCache } from '../../../../lib'; +import { + constantsConfig, + getConn, + PrefixCommandCategory, + Logger, + makeEmbed, + refreshSinglePrefixCommandCategoryCache, +} from '../../../../lib'; const noConnEmbed = makeEmbed({ - title: 'Prefix Commands - Modify Category - No Connection', - description: 'Could not connect to the database. Unable to modify the prefix command category.', - color: Colors.Red, + title: 'Prefix Commands - Modify Category - No Connection', + description: 'Could not connect to the database. Unable to modify the prefix command category.', + color: Colors.Red, }); -const failedEmbed = (categoryId: string) => makeEmbed({ +const failedEmbed = (categoryId: string) => + makeEmbed({ title: 'Prefix Commands - Modify Category - Failed', description: `Failed to modify the prefix command category with id ${categoryId}.`, color: Colors.Red, -}); + }); -const doesNotExistsEmbed = (category: string) => makeEmbed({ +const doesNotExistsEmbed = (category: string) => + makeEmbed({ title: 'Prefix Commands - Modify Category - Does not exist', description: `The prefix command category ${category} does not exists. Cannot modify it.`, color: Colors.Red, -}); + }); -const successEmbed = (category: string, categoryId: string) => makeEmbed({ +const successEmbed = (category: string, categoryId: string) => + makeEmbed({ title: `Prefix command category ${category} (${categoryId}) was modified successfully.`, color: Colors.Green, -}); + }); -const modLogEmbed = (moderator: User, category: string, emoji: string, categoryId: string) => makeEmbed({ +const modLogEmbed = (moderator: User, category: string, emoji: string, categoryId: string) => + makeEmbed({ title: 'Prefix command category modified', fields: [ - { - name: 'Category', - value: category, - }, - { - name: 'Moderator', - value: `${moderator}`, - }, - { - name: 'Emoji', - value: emoji, - }, + { + name: 'Category', + value: category, + }, + { + name: 'Moderator', + value: `${moderator}`, + }, + { + name: 'Emoji', + value: emoji, + }, ], footer: { text: `Category ID: ${categoryId}` }, color: Colors.Green, -}); + }); const noModLogs = makeEmbed({ - title: 'Prefix Commands - Modified Category - No Mod Log', - description: 'I can\'t find the mod logs channel. Please check the channel still exists.', - color: Colors.Red, + title: 'Prefix Commands - Modified Category - No Mod Log', + description: "I can't find the mod logs channel. Please check the channel still exists.", + color: Colors.Red, }); export async function handleModifyPrefixCommandCategory(interaction: ChatInputCommandInteraction<'cached'>) { - await interaction.deferReply({ ephemeral: true }); + await interaction.deferReply({ ephemeral: true }); - const conn = getConn(); - if (!conn) { - await interaction.followUp({ embeds: [noConnEmbed], ephemeral: true }); - return; - } + const conn = getConn(); + if (!conn) { + await interaction.followUp({ embeds: [noConnEmbed], ephemeral: true }); + return; + } - const category = interaction.options.getString('category')!; - const name = interaction.options.getString('name') || ''; - const emoji = interaction.options.getString('emoji') || ''; - const moderator = interaction.user; + const category = interaction.options.getString('category')!; + const name = interaction.options.getString('name') || ''; + const emoji = interaction.options.getString('emoji') || ''; + const moderator = interaction.user; - //Check if the mod logs channel exists - let modLogsChannel = interaction.guild.channels.resolve(constantsConfig.channels.MOD_LOGS); - if (!modLogsChannel || !modLogsChannel.isTextBased()) { - modLogsChannel = null; - await interaction.followUp({ embeds: [noModLogs], ephemeral: true }); - } + //Check if the mod logs channel exists + let modLogsChannel = interaction.guild.channels.resolve(constantsConfig.channels.MOD_LOGS); + if (!modLogsChannel || !modLogsChannel.isTextBased()) { + modLogsChannel = null; + await interaction.followUp({ embeds: [noModLogs], ephemeral: true }); + } - const existingCategory = await PrefixCommandCategory.findOne({ name: category }); + const existingCategory = await PrefixCommandCategory.findOne({ name: category }); - if (existingCategory) { - const { id: categoryId } = existingCategory; - const oldCategory = existingCategory.$clone(); - existingCategory.name = name || existingCategory.name; - existingCategory.emoji = emoji || existingCategory.emoji; + if (existingCategory) { + const { id: categoryId } = existingCategory; + const oldCategory = existingCategory.$clone(); + existingCategory.name = name || existingCategory.name; + existingCategory.emoji = emoji || existingCategory.emoji; + try { + await existingCategory.save(); + const { name, emoji } = existingCategory; + await refreshSinglePrefixCommandCategoryCache(oldCategory, existingCategory); + await interaction.followUp({ embeds: [successEmbed(name, categoryId)], ephemeral: true }); + if (modLogsChannel) { try { - await existingCategory.save(); - const { name, emoji } = existingCategory; - await refreshSinglePrefixCommandCategoryCache(oldCategory, existingCategory); - await interaction.followUp({ embeds: [successEmbed(name, categoryId)], ephemeral: true }); - if (modLogsChannel) { - try { - await modLogsChannel.send({ embeds: [modLogEmbed(moderator, name, emoji || '', categoryId)] }); - } catch (error) { - Logger.error(`Failed to post a message to the mod logs channel: ${error}`); - } - } + await modLogsChannel.send({ embeds: [modLogEmbed(moderator, name, emoji || '', categoryId)] }); } catch (error) { - Logger.error(`Failed to modify a prefix command category with id ${categoryId}: ${error}`); - await interaction.followUp({ embeds: [failedEmbed(categoryId)], ephemeral: true }); + Logger.error(`Failed to post a message to the mod logs channel: ${error}`); } - } else { - await interaction.followUp({ embeds: [doesNotExistsEmbed(category)], ephemeral: true }); + } + } catch (error) { + Logger.error(`Failed to modify a prefix command category with id ${categoryId}: ${error}`); + await interaction.followUp({ embeds: [failedEmbed(categoryId)], ephemeral: true }); } + } else { + await interaction.followUp({ embeds: [doesNotExistsEmbed(category)], ephemeral: true }); + } } diff --git a/src/commands/moderation/prefixCommands/functions/modifyCommand.ts b/src/commands/moderation/prefixCommands/functions/modifyCommand.ts index 13e85472..53a05fe9 100644 --- a/src/commands/moderation/prefixCommands/functions/modifyCommand.ts +++ b/src/commands/moderation/prefixCommands/functions/modifyCommand.ts @@ -1,205 +1,250 @@ import { ChatInputCommandInteraction, Colors, User } from 'discord.js'; -import { constantsConfig, getConn, PrefixCommand, Logger, makeEmbed, PrefixCommandCategory, refreshSinglePrefixCommandCache, PrefixCommandVersion } from '../../../../lib'; +import { + constantsConfig, + getConn, + PrefixCommand, + Logger, + makeEmbed, + PrefixCommandCategory, + refreshSinglePrefixCommandCache, + PrefixCommandVersion, +} from '../../../../lib'; const noConnEmbed = makeEmbed({ - title: 'Prefix Commands - Modify Command - No Connection', - description: 'Could not connect to the database. Unable to modify the prefix command.', - color: Colors.Red, + title: 'Prefix Commands - Modify Command - No Connection', + description: 'Could not connect to the database. Unable to modify the prefix command.', + color: Colors.Red, }); -const failedEmbed = (commandId: string) => makeEmbed({ +const failedEmbed = (commandId: string) => + makeEmbed({ title: 'Prefix Commands - Modify Command - Failed', description: `Failed to modify the prefix command with id ${commandId}.`, color: Colors.Red, -}); + }); -const wrongFormatEmbed = (invalidString: string) => makeEmbed({ +const wrongFormatEmbed = (invalidString: string) => + makeEmbed({ title: 'Prefix Commands - Modify Command - Wrong format', description: `The name and aliases of a command can only contain alphanumerical characters, underscores and dashes. "${invalidString}" is invalid.`, color: Colors.Red, -}); + }); -const categoryNotFoundEmbed = (category: string) => makeEmbed({ +const categoryNotFoundEmbed = (category: string) => + makeEmbed({ title: 'Prefix Commands - Modify Command - Category not found', description: `The prefix command category ${category} does not exist. Please create it first.`, color: Colors.Red, -}); + }); -const doesNotExistsEmbed = (command: string) => makeEmbed({ +const doesNotExistsEmbed = (command: string) => + makeEmbed({ title: 'Prefix Commands - Modify Command - Does not exist', description: `The prefix command ${command} does not exists. Cannot modify it.`, color: Colors.Red, -}); + }); -const alreadyExistsEmbed = (command: string, reason: string) => makeEmbed({ +const alreadyExistsEmbed = (command: string, reason: string) => + makeEmbed({ title: 'Prefix Commands - Modify Command - Already exists', description: `The prefix command ${command} can not be modified: ${reason}`, color: Colors.Red, -}); + }); -const successEmbed = (command: string, commandId: string) => makeEmbed({ +const successEmbed = (command: string, commandId: string) => + makeEmbed({ title: `Prefix command ${command} (${commandId}) was modified successfully.`, color: Colors.Green, -}); - -const modLogEmbed = (moderator: User, command: string, aliases: string[], description: string, isEmbed: boolean, embedColor: string, commandId: string) => makeEmbed({ + }); + +const modLogEmbed = ( + moderator: User, + command: string, + aliases: string[], + description: string, + isEmbed: boolean, + embedColor: string, + commandId: string, +) => + makeEmbed({ title: 'Prefix command modified', fields: [ - { - name: 'Command', - value: command, - }, - { - name: 'Moderator', - value: `${moderator}`, - }, - { - name: 'Aliases', - value: aliases.join(','), - }, - { - name: 'Description', - value: description, - }, - { - name: 'Is Embed', - value: isEmbed ? 'Yes' : 'No', - }, - { - name: 'Embed Color', - value: embedColor || '', - }, + { + name: 'Command', + value: command, + }, + { + name: 'Moderator', + value: `${moderator}`, + }, + { + name: 'Aliases', + value: aliases.join(','), + }, + { + name: 'Description', + value: description, + }, + { + name: 'Is Embed', + value: isEmbed ? 'Yes' : 'No', + }, + { + name: 'Embed Color', + value: embedColor || '', + }, ], footer: { text: `Command ID: ${commandId}` }, color: Colors.Green, -}); + }); const noModLogs = makeEmbed({ - title: 'Prefix Commands - Modified Command - No Mod Log', - description: 'I can\'t find the mod logs channel. Please check the channel still exists.', - color: Colors.Red, + title: 'Prefix Commands - Modified Command - No Mod Log', + description: "I can't find the mod logs channel. Please check the channel still exists.", + color: Colors.Red, }); export async function handleModifyPrefixCommand(interaction: ChatInputCommandInteraction<'cached'>) { - await interaction.deferReply({ ephemeral: true }); - - const conn = getConn(); - if (!conn) { - await interaction.followUp({ embeds: [noConnEmbed], ephemeral: true }); - return; - } - - const command = interaction.options.getString('command')!; - const name = interaction.options.getString('name')?.toLowerCase().trim() || ''; - const category = interaction.options.getString('category') || ''; - const description = interaction.options.getString('description') || ''; - const aliasesString = interaction.options.getString('aliases')?.toLowerCase().trim() || ''; - const aliases = aliasesString !== '' ? aliasesString.split(',') : []; - const isEmbed = interaction.options.getBoolean('is_embed'); - const embedColor = interaction.options.getString('embed_color') || ''; - const moderator = interaction.user; - - const nameRegex = /^[\w-]+$/; - if (name && !nameRegex.test(name)) { - await interaction.followUp({ embeds: [wrongFormatEmbed(name)], ephemeral: true }); - return; + await interaction.deferReply({ ephemeral: true }); + + const conn = getConn(); + if (!conn) { + await interaction.followUp({ embeds: [noConnEmbed], ephemeral: true }); + return; + } + + const command = interaction.options.getString('command')!; + const name = interaction.options.getString('name')?.toLowerCase().trim() || ''; + const category = interaction.options.getString('category') || ''; + const description = interaction.options.getString('description') || ''; + const aliasesString = interaction.options.getString('aliases')?.toLowerCase().trim() || ''; + const aliases = aliasesString !== '' ? aliasesString.split(',') : []; + const isEmbed = interaction.options.getBoolean('is_embed'); + const embedColor = interaction.options.getString('embed_color') || ''; + const moderator = interaction.user; + + const nameRegex = /^[\w-]+$/; + if (name && !nameRegex.test(name)) { + await interaction.followUp({ embeds: [wrongFormatEmbed(name)], ephemeral: true }); + return; + } + for (const alias of aliases) { + if (!nameRegex.test(alias)) { + // eslint-disable-next-line no-await-in-loop + await interaction.followUp({ embeds: [wrongFormatEmbed(alias)], ephemeral: true }); + return; } - for (const alias of aliases) { - if (!nameRegex.test(alias)) { - // eslint-disable-next-line no-await-in-loop - await interaction.followUp({ embeds: [wrongFormatEmbed(alias)], ephemeral: true }); - return; - } + } + // Check if command name and alias are unique, additionally check if they do not exist as a version alias. + if (name) { + const foundCommandName = await PrefixCommand.findOne({ + name: { $ne: command }, + $or: [{ name }, { aliases: name }], + }); + if (foundCommandName) { + await interaction.followUp({ + embeds: [alreadyExistsEmbed(command, `${name} already exists as a different command or alias.`)], + ephemeral: true, + }); + return; } - // Check if command name and alias are unique, additionally check if they do not exist as a version alias. - if (name) { - const foundCommandName = await PrefixCommand.findOne({ - name: { $ne: command }, - $or: [ - { name }, - { aliases: name }, - ], - }); - if (foundCommandName) { - await interaction.followUp({ embeds: [alreadyExistsEmbed(command, `${name} already exists as a different command or alias.`)], ephemeral: true }); - return; - } - const foundVersion = await PrefixCommandVersion.findOne({ - $or: [ - { alias: name }, - ], - }); - if (foundVersion || name === 'generic') { - await interaction.followUp({ embeds: [alreadyExistsEmbed(command, `${name} already exists as a version alias.`)], ephemeral: true }); - return; - } + const foundVersion = await PrefixCommandVersion.findOne({ + $or: [{ alias: name }], + }); + if (foundVersion || name === 'generic') { + await interaction.followUp({ + embeds: [alreadyExistsEmbed(command, `${name} already exists as a version alias.`)], + ephemeral: true, + }); + return; } - if (aliases.length > 0) { - const foundCommandName = await PrefixCommand.findOne({ - name: { $ne: command }, - $or: [ - { name: { $in: aliases } }, - { aliases: { $in: aliases } }, - ], - }); - if (foundCommandName) { - await interaction.followUp({ embeds: [alreadyExistsEmbed(command, 'The new aliases contain an alias that already exists as a different command or alias.')], ephemeral: true }); - return; - } - const foundVersion = await PrefixCommandVersion.findOne({ - $or: [ - { alias: { $in: aliases } }, - ], - }); - if (foundVersion || aliases.includes('generic')) { - await interaction.followUp({ embeds: [alreadyExistsEmbed(command, 'The new aliases contain an alias that already exists as a version alias.')], ephemeral: true }); - return; - } + } + if (aliases.length > 0) { + const foundCommandName = await PrefixCommand.findOne({ + name: { $ne: command }, + $or: [{ name: { $in: aliases } }, { aliases: { $in: aliases } }], + }); + if (foundCommandName) { + await interaction.followUp({ + embeds: [ + alreadyExistsEmbed( + command, + 'The new aliases contain an alias that already exists as a different command or alias.', + ), + ], + ephemeral: true, + }); + return; } - - //Check if the mod logs channel exists - let modLogsChannel = interaction.guild.channels.resolve(constantsConfig.channels.MOD_LOGS); - if (!modLogsChannel || !modLogsChannel.isTextBased()) { - modLogsChannel = null; - await interaction.followUp({ embeds: [noModLogs], ephemeral: true }); + const foundVersion = await PrefixCommandVersion.findOne({ + $or: [{ alias: { $in: aliases } }], + }); + if (foundVersion || aliases.includes('generic')) { + await interaction.followUp({ + embeds: [ + alreadyExistsEmbed(command, 'The new aliases contain an alias that already exists as a version alias.'), + ], + ephemeral: true, + }); + return; } - - let foundCategory; - if (category !== '') { - [foundCategory] = await PrefixCommandCategory.find({ name: category }); - if (!foundCategory) { - await interaction.followUp({ embeds: [categoryNotFoundEmbed(category)], ephemeral: true }); - return; - } + } + + //Check if the mod logs channel exists + let modLogsChannel = interaction.guild.channels.resolve(constantsConfig.channels.MOD_LOGS); + if (!modLogsChannel || !modLogsChannel.isTextBased()) { + modLogsChannel = null; + await interaction.followUp({ embeds: [noModLogs], ephemeral: true }); + } + + let foundCategory; + if (category !== '') { + [foundCategory] = await PrefixCommandCategory.find({ name: category }); + if (!foundCategory) { + await interaction.followUp({ embeds: [categoryNotFoundEmbed(category)], ephemeral: true }); + return; } - const existingCommand = await PrefixCommand.findOne({ name: command }); - - if (existingCommand) { - const { id: commandId } = existingCommand; - const oldCommand = existingCommand.$clone(); - existingCommand.name = name || existingCommand.name; - existingCommand.categoryId = foundCategory?.id || existingCommand.categoryId; - existingCommand.description = description || existingCommand.description; - existingCommand.aliases = aliases.length > 0 ? aliases : existingCommand.aliases; - existingCommand.isEmbed = isEmbed !== null ? isEmbed : existingCommand.isEmbed; - existingCommand.embedColor = embedColor || existingCommand.embedColor; + } + const existingCommand = await PrefixCommand.findOne({ name: command }); + + if (existingCommand) { + const { id: commandId } = existingCommand; + const oldCommand = existingCommand.$clone(); + existingCommand.name = name || existingCommand.name; + existingCommand.categoryId = foundCategory?.id || existingCommand.categoryId; + existingCommand.description = description || existingCommand.description; + existingCommand.aliases = aliases.length > 0 ? aliases : existingCommand.aliases; + existingCommand.isEmbed = isEmbed !== null ? isEmbed : existingCommand.isEmbed; + existingCommand.embedColor = embedColor || existingCommand.embedColor; + try { + await existingCommand.save(); + const { name, description, aliases, isEmbed, embedColor } = existingCommand; + await refreshSinglePrefixCommandCache(oldCommand, existingCommand); + await interaction.followUp({ embeds: [successEmbed(name, commandId)], ephemeral: true }); + if (modLogsChannel) { try { - await existingCommand.save(); - const { name, description, aliases, isEmbed, embedColor } = existingCommand; - await refreshSinglePrefixCommandCache(oldCommand, existingCommand); - await interaction.followUp({ embeds: [successEmbed(name, commandId)], ephemeral: true }); - if (modLogsChannel) { - try { - await modLogsChannel.send({ embeds: [modLogEmbed(moderator, name, aliases, description, isEmbed || false, embedColor || '', existingCommand.id)] }); - } catch (error) { - Logger.error(`Failed to post a message to the mod logs channel: ${error}`); - } - } + await modLogsChannel.send({ + embeds: [ + modLogEmbed( + moderator, + name, + aliases, + description, + isEmbed || false, + embedColor || '', + existingCommand.id, + ), + ], + }); } catch (error) { - Logger.error(`Failed to modify a prefix command command with id ${commandId}: ${error}`); - await interaction.followUp({ embeds: [failedEmbed(commandId)], ephemeral: true }); + Logger.error(`Failed to post a message to the mod logs channel: ${error}`); } - } else { - await interaction.followUp({ embeds: [doesNotExistsEmbed(command)], ephemeral: true }); + } + } catch (error) { + Logger.error(`Failed to modify a prefix command command with id ${commandId}: ${error}`); + await interaction.followUp({ embeds: [failedEmbed(commandId)], ephemeral: true }); } + } else { + await interaction.followUp({ embeds: [doesNotExistsEmbed(command)], ephemeral: true }); + } } diff --git a/src/commands/moderation/prefixCommands/functions/modifyVersion.ts b/src/commands/moderation/prefixCommands/functions/modifyVersion.ts index eeceba92..7eac49e5 100644 --- a/src/commands/moderation/prefixCommands/functions/modifyVersion.ts +++ b/src/commands/moderation/prefixCommands/functions/modifyVersion.ts @@ -1,166 +1,195 @@ import { ChatInputCommandInteraction, Colors, User } from 'discord.js'; -import { constantsConfig, getConn, PrefixCommandVersion, Logger, makeEmbed, refreshSinglePrefixCommandVersionCache, PrefixCommand } from '../../../../lib'; +import { + constantsConfig, + getConn, + PrefixCommandVersion, + Logger, + makeEmbed, + refreshSinglePrefixCommandVersionCache, + PrefixCommand, +} from '../../../../lib'; const noConnEmbed = makeEmbed({ - title: 'Prefix Commands - Modify Version - No Connection', - description: 'Could not connect to the database. Unable to modify the prefix command version.', - color: Colors.Red, + title: 'Prefix Commands - Modify Version - No Connection', + description: 'Could not connect to the database. Unable to modify the prefix command version.', + color: Colors.Red, }); -const failedEmbed = (versionId: string) => makeEmbed({ +const failedEmbed = (versionId: string) => + makeEmbed({ title: 'Prefix Commands - Modify Version - Failed', description: `Failed to modify the prefix command version with id ${versionId}.`, color: Colors.Red, -}); + }); -const wrongFormatEmbed = (invalidString: string) => makeEmbed({ +const wrongFormatEmbed = (invalidString: string) => + makeEmbed({ title: 'Prefix Commands - Modify Version - Wrong format', description: `The name and alias of a version can only contain alphanumerical characters, underscores and dashes. "${invalidString}" is invalid.`, color: Colors.Red, -}); + }); -const doesNotExistsEmbed = (version: string) => makeEmbed({ +const doesNotExistsEmbed = (version: string) => + makeEmbed({ title: 'Prefix Commands - Modify Version - Does not exist', description: `The prefix command version ${version} does not exists. Cannot modify it.`, color: Colors.Red, -}); + }); -const alreadyExistsEmbed = (version: string, reason: string) => makeEmbed({ +const alreadyExistsEmbed = (version: string, reason: string) => + makeEmbed({ title: 'Prefix Commands - Add Version - Already exists', description: `The prefix command version ${version} already exists: ${reason}`, color: Colors.Red, -}); + }); -const successEmbed = (version: string, versionId: string) => makeEmbed({ +const successEmbed = (version: string, versionId: string) => + makeEmbed({ title: `Prefix command version ${version} (${versionId}) was modified successfully.`, color: Colors.Green, -}); + }); -const modLogEmbed = (moderator: User, version: string, emoji: string, alias: string, enabled: boolean, versionId: string) => makeEmbed({ +const modLogEmbed = ( + moderator: User, + version: string, + emoji: string, + alias: string, + enabled: boolean, + versionId: string, +) => + makeEmbed({ title: 'Prefix command version modified', fields: [ - { - name: 'Version', - value: version, - }, - { - name: 'Moderator', - value: `${moderator}`, - }, - { - name: 'Emoji', - value: emoji, - }, - { - name: 'Alias', - value: alias, - }, - { - name: 'Enabled', - value: enabled ? 'Yes' : 'No', - }, + { + name: 'Version', + value: version, + }, + { + name: 'Moderator', + value: `${moderator}`, + }, + { + name: 'Emoji', + value: emoji, + }, + { + name: 'Alias', + value: alias, + }, + { + name: 'Enabled', + value: enabled ? 'Yes' : 'No', + }, ], footer: { text: `Version ID: ${versionId}` }, color: Colors.Green, -}); + }); const noModLogs = makeEmbed({ - title: 'Prefix Commands - Modified Version - No Mod Log', - description: 'I can\'t find the mod logs channel. Please check the channel still exists.', - color: Colors.Red, + title: 'Prefix Commands - Modified Version - No Mod Log', + description: "I can't find the mod logs channel. Please check the channel still exists.", + color: Colors.Red, }); export async function handleModifyPrefixCommandVersion(interaction: ChatInputCommandInteraction<'cached'>) { - await interaction.deferReply({ ephemeral: true }); + await interaction.deferReply({ ephemeral: true }); - const conn = getConn(); - if (!conn) { - await interaction.followUp({ embeds: [noConnEmbed], ephemeral: true }); - return; - } + const conn = getConn(); + if (!conn) { + await interaction.followUp({ embeds: [noConnEmbed], ephemeral: true }); + return; + } - const version = interaction.options.getString('version')!; - const name = interaction.options.getString('name') || ''; - const emoji = interaction.options.getString('emoji') || ''; - const alias = interaction.options.getString('alias')?.toLowerCase() || ''; - const enabled = interaction.options.getBoolean('is_enabled'); - const moderator = interaction.user; + const version = interaction.options.getString('version')!; + const name = interaction.options.getString('name') || ''; + const emoji = interaction.options.getString('emoji') || ''; + const alias = interaction.options.getString('alias')?.toLowerCase() || ''; + const enabled = interaction.options.getBoolean('is_enabled'); + const moderator = interaction.user; - const nameRegex = /^[\w-]+$/; - if (name && !nameRegex.test(name)) { - await interaction.followUp({ embeds: [wrongFormatEmbed(name)], ephemeral: true }); - return; + const nameRegex = /^[\w-]+$/; + if (name && !nameRegex.test(name)) { + await interaction.followUp({ embeds: [wrongFormatEmbed(name)], ephemeral: true }); + return; + } + if (alias && !nameRegex.test(alias)) { + await interaction.followUp({ embeds: [wrongFormatEmbed(alias)], ephemeral: true }); + return; + } + if (name) { + const foundVersion = await PrefixCommandVersion.findOne({ + name: { + $ne: version, + $eq: name, + }, + }); + if (foundVersion || name.toLowerCase() === 'generic') { + await interaction.followUp({ + embeds: [alreadyExistsEmbed(version, `${name} already exists as a version.`)], + ephemeral: true, + }); + return; } - if (alias && !nameRegex.test(alias)) { - await interaction.followUp({ embeds: [wrongFormatEmbed(alias)], ephemeral: true }); - return; + } + if (alias) { + const foundVersion = await PrefixCommandVersion.findOne({ + name: { $ne: version }, + alias, + }); + if (foundVersion || alias === 'generic') { + await interaction.followUp({ + embeds: [alreadyExistsEmbed(version, `${alias} already exists as a version alias.`)], + ephemeral: true, + }); + return; } - if (name) { - const foundVersion = await PrefixCommandVersion.findOne({ - name: { - $ne: version, - $eq: name, - }, - }); - if (foundVersion || name.toLowerCase() === 'generic') { - await interaction.followUp({ embeds: [alreadyExistsEmbed(version, `${name} already exists as a version.`)], ephemeral: true }); - return; - } - } - if (alias) { - const foundVersion = await PrefixCommandVersion.findOne({ - name: { $ne: version }, - alias, - }); - if (foundVersion || alias === 'generic') { - await interaction.followUp({ embeds: [alreadyExistsEmbed(version, `${alias} already exists as a version alias.`)], ephemeral: true }); - return; - } - const foundCommandName = await PrefixCommand.findOne({ - $or: [ - { name: alias }, - { aliases: alias }, - ], - }); - if (foundCommandName) { - await interaction.followUp({ embeds: [alreadyExistsEmbed(version, `${alias} already exists as a command or command alias.`)], ephemeral: true }); - return; - } + const foundCommandName = await PrefixCommand.findOne({ + $or: [{ name: alias }, { aliases: alias }], + }); + if (foundCommandName) { + await interaction.followUp({ + embeds: [alreadyExistsEmbed(version, `${alias} already exists as a command or command alias.`)], + ephemeral: true, + }); + return; } + } - //Check if the mod logs channel exists - let modLogsChannel = interaction.guild.channels.resolve(constantsConfig.channels.MOD_LOGS); - if (!modLogsChannel || !modLogsChannel.isTextBased()) { - modLogsChannel = null; - await interaction.followUp({ embeds: [noModLogs], ephemeral: true }); - } + //Check if the mod logs channel exists + let modLogsChannel = interaction.guild.channels.resolve(constantsConfig.channels.MOD_LOGS); + if (!modLogsChannel || !modLogsChannel.isTextBased()) { + modLogsChannel = null; + await interaction.followUp({ embeds: [noModLogs], ephemeral: true }); + } - const existingVersion = await PrefixCommandVersion.findOne({ name: version }); + const existingVersion = await PrefixCommandVersion.findOne({ name: version }); - if (existingVersion) { - const { id: versionId } = existingVersion; - const oldVersion = existingVersion.$clone(); - existingVersion.name = name || existingVersion.name; - existingVersion.emoji = emoji || existingVersion.emoji; - existingVersion.alias = alias || existingVersion.alias; - existingVersion.enabled = enabled !== null ? enabled : existingVersion.enabled; + if (existingVersion) { + const { id: versionId } = existingVersion; + const oldVersion = existingVersion.$clone(); + existingVersion.name = name || existingVersion.name; + existingVersion.emoji = emoji || existingVersion.emoji; + existingVersion.alias = alias || existingVersion.alias; + existingVersion.enabled = enabled !== null ? enabled : existingVersion.enabled; + try { + await existingVersion.save(); + const { name, emoji, alias, enabled } = existingVersion; + await refreshSinglePrefixCommandVersionCache(oldVersion, existingVersion); + await interaction.followUp({ embeds: [successEmbed(name, versionId)], ephemeral: true }); + if (modLogsChannel) { try { - await existingVersion.save(); - const { name, emoji, alias, enabled } = existingVersion; - await refreshSinglePrefixCommandVersionCache(oldVersion, existingVersion); - await interaction.followUp({ embeds: [successEmbed(name, versionId)], ephemeral: true }); - if (modLogsChannel) { - try { - await modLogsChannel.send({ embeds: [modLogEmbed(moderator, name, emoji, alias, enabled || false, versionId)] }); - } catch (error) { - Logger.error(`Failed to post a message to the mod logs channel: ${error}`); - } - } + await modLogsChannel.send({ + embeds: [modLogEmbed(moderator, name, emoji, alias, enabled || false, versionId)], + }); } catch (error) { - Logger.error(`Failed to modify a prefix command version with id ${versionId}: ${error}`); - await interaction.followUp({ embeds: [failedEmbed(versionId)], ephemeral: true }); + Logger.error(`Failed to post a message to the mod logs channel: ${error}`); } - } else { - await interaction.followUp({ embeds: [doesNotExistsEmbed(version)], ephemeral: true }); + } + } catch (error) { + Logger.error(`Failed to modify a prefix command version with id ${versionId}: ${error}`); + await interaction.followUp({ embeds: [failedEmbed(versionId)], ephemeral: true }); } + } else { + await interaction.followUp({ embeds: [doesNotExistsEmbed(version)], ephemeral: true }); + } } diff --git a/src/commands/moderation/prefixCommands/functions/removeChannelPermission.ts b/src/commands/moderation/prefixCommands/functions/removeChannelPermission.ts index 7b930896..7a7444cb 100644 --- a/src/commands/moderation/prefixCommands/functions/removeChannelPermission.ts +++ b/src/commands/moderation/prefixCommands/functions/removeChannelPermission.ts @@ -1,110 +1,122 @@ import { ChatInputCommandInteraction, Colors, User } from 'discord.js'; -import { constantsConfig, getConn, PrefixCommand, Logger, makeEmbed, refreshSinglePrefixCommandCache } from '../../../../lib'; +import { + constantsConfig, + getConn, + PrefixCommand, + Logger, + makeEmbed, + refreshSinglePrefixCommandCache, +} from '../../../../lib'; const noConnEmbed = makeEmbed({ - title: 'Prefix Commands - Remove Channel - No Connection', - description: 'Could not connect to the database. Unable to remove the prefix command channel.', - color: Colors.Red, + title: 'Prefix Commands - Remove Channel - No Connection', + description: 'Could not connect to the database. Unable to remove the prefix command channel.', + color: Colors.Red, }); -const noCommandEmbed = (command: string) => makeEmbed({ +const noCommandEmbed = (command: string) => + makeEmbed({ title: 'Prefix Commands - Remove Channel - No Command', description: `Failed to remove the prefix command channel for command ${command} as the command does not exist or there are more than one matching.`, color: Colors.Red, -}); + }); -const failedEmbed = (command: string, channel: string) => makeEmbed({ +const failedEmbed = (command: string, channel: string) => + makeEmbed({ title: 'Prefix Commands - Remove Channel- Failed', description: `Failed to remove the prefix command channel <#${channel}> for command ${command}.`, color: Colors.Red, -}); + }); -const doesNotExistEmbed = (command: string, channel: string) => makeEmbed({ +const doesNotExistEmbed = (command: string, channel: string) => + makeEmbed({ title: 'Prefix Commands - Remove Channel - Does not exist', description: `A prefix command channel <#${channel}> for command ${command} does not exist.`, color: Colors.Red, -}); + }); -const successEmbed = (command: string, channel: string) => makeEmbed({ +const successEmbed = (command: string, channel: string) => + makeEmbed({ title: `Prefix command channel <#${channel}> removed for command ${command}.`, color: Colors.Green, -}); + }); -const modLogEmbed = (moderator: User, command: string, channel: string) => makeEmbed({ +const modLogEmbed = (moderator: User, command: string, channel: string) => + makeEmbed({ title: 'Remove prefix command channel permission', fields: [ - { - name: 'Command', - value: command, - }, - { - name: 'Channel', - value: `<#${channel}>`, - }, - { - name: 'Moderator', - value: `${moderator}`, - }, + { + name: 'Command', + value: command, + }, + { + name: 'Channel', + value: `<#${channel}>`, + }, + { + name: 'Moderator', + value: `${moderator}`, + }, ], color: Colors.Red, -}); + }); const noModLogs = makeEmbed({ - title: 'Prefix Commands - Remove Channel - No Mod Log', - description: 'I can\'t find the mod logs channel. Please check the channel still exists.', - color: Colors.Red, + title: 'Prefix Commands - Remove Channel - No Mod Log', + description: "I can't find the mod logs channel. Please check the channel still exists.", + color: Colors.Red, }); export async function handleRemovePrefixCommandChannelPermission(interaction: ChatInputCommandInteraction<'cached'>) { - await interaction.deferReply({ ephemeral: true }); + await interaction.deferReply({ ephemeral: true }); - const conn = getConn(); - if (!conn) { - await interaction.followUp({ embeds: [noConnEmbed], ephemeral: true }); - return; - } + const conn = getConn(); + if (!conn) { + await interaction.followUp({ embeds: [noConnEmbed], ephemeral: true }); + return; + } - const command = interaction.options.getString('command')!; - const channel = interaction.options.getChannel('channel')!; - const moderator = interaction.user; + const command = interaction.options.getString('command')!; + const channel = interaction.options.getChannel('channel')!; + const moderator = interaction.user; - //Check if the mod logs channel exists - let modLogsChannel = interaction.guild.channels.resolve(constantsConfig.channels.MOD_LOGS); - if (!modLogsChannel || !modLogsChannel.isTextBased()) { - modLogsChannel = null; - await interaction.followUp({ embeds: [noModLogs], ephemeral: true }); - } + //Check if the mod logs channel exists + let modLogsChannel = interaction.guild.channels.resolve(constantsConfig.channels.MOD_LOGS); + if (!modLogsChannel || !modLogsChannel.isTextBased()) { + modLogsChannel = null; + await interaction.followUp({ embeds: [noModLogs], ephemeral: true }); + } - let foundCommands = await PrefixCommand.find({ name: command }); - if (!foundCommands || foundCommands.length > 1) { - foundCommands = await PrefixCommand.find({ aliases: { $in: [command] } }); - } - if (!foundCommands || foundCommands.length > 1) { - await interaction.followUp({ embeds: [noCommandEmbed(command)], ephemeral: true }); - return; - } - const [foundCommand] = foundCommands; - const { id: channelId } = channel; + let foundCommands = await PrefixCommand.find({ name: command }); + if (!foundCommands || foundCommands.length > 1) { + foundCommands = await PrefixCommand.find({ aliases: { $in: [command] } }); + } + if (!foundCommands || foundCommands.length > 1) { + await interaction.followUp({ embeds: [noCommandEmbed(command)], ephemeral: true }); + return; + } + const [foundCommand] = foundCommands; + const { id: channelId } = channel; - const existingChannelPermission = foundCommand.permissions.channels?.includes(channelId); - if (existingChannelPermission) { - foundCommand.permissions.channels = foundCommand.permissions.channels?.filter((id) => id !== channelId); + const existingChannelPermission = foundCommand.permissions.channels?.includes(channelId); + if (existingChannelPermission) { + foundCommand.permissions.channels = foundCommand.permissions.channels?.filter((id) => id !== channelId); + try { + await foundCommand.save(); + await refreshSinglePrefixCommandCache(foundCommand, foundCommand); + await interaction.followUp({ embeds: [successEmbed(command, channelId)], ephemeral: true }); + if (modLogsChannel) { try { - await foundCommand.save(); - await refreshSinglePrefixCommandCache(foundCommand, foundCommand); - await interaction.followUp({ embeds: [successEmbed(command, channelId)], ephemeral: true }); - if (modLogsChannel) { - try { - await modLogsChannel.send({ embeds: [modLogEmbed(moderator, command, channelId)] }); - } catch (error) { - Logger.error(`Failed to post a message to the mod logs channel: ${error}`); - } - } + await modLogsChannel.send({ embeds: [modLogEmbed(moderator, command, channelId)] }); } catch (error) { - Logger.error(`Failed to remove prefix command channel <#${channel}> for command ${command}: ${error}`); - await interaction.followUp({ embeds: [failedEmbed(command, channelId)], ephemeral: true }); + Logger.error(`Failed to post a message to the mod logs channel: ${error}`); } - } else { - await interaction.followUp({ embeds: [doesNotExistEmbed(command, channelId)], ephemeral: true }); + } + } catch (error) { + Logger.error(`Failed to remove prefix command channel <#${channel}> for command ${command}: ${error}`); + await interaction.followUp({ embeds: [failedEmbed(command, channelId)], ephemeral: true }); } + } else { + await interaction.followUp({ embeds: [doesNotExistEmbed(command, channelId)], ephemeral: true }); + } } diff --git a/src/commands/moderation/prefixCommands/functions/removeRolePermission.ts b/src/commands/moderation/prefixCommands/functions/removeRolePermission.ts index 7a63c983..fcbfa5c2 100644 --- a/src/commands/moderation/prefixCommands/functions/removeRolePermission.ts +++ b/src/commands/moderation/prefixCommands/functions/removeRolePermission.ts @@ -1,110 +1,122 @@ import { ChatInputCommandInteraction, Colors, User } from 'discord.js'; -import { constantsConfig, getConn, PrefixCommand, Logger, makeEmbed, refreshSinglePrefixCommandCache } from '../../../../lib'; +import { + constantsConfig, + getConn, + PrefixCommand, + Logger, + makeEmbed, + refreshSinglePrefixCommandCache, +} from '../../../../lib'; const noConnEmbed = makeEmbed({ - title: 'Prefix Commands - Remove Role - No Connection', - description: 'Could not connect to the database. Unable to remove the prefix command role.', - color: Colors.Red, + title: 'Prefix Commands - Remove Role - No Connection', + description: 'Could not connect to the database. Unable to remove the prefix command role.', + color: Colors.Red, }); -const noCommandEmbed = (command: string) => makeEmbed({ +const noCommandEmbed = (command: string) => + makeEmbed({ title: 'Prefix Commands - Remove Role - No Command', description: `Failed to remove the prefix command role for command ${command} as the command does not exist or there are more than one matching.`, color: Colors.Red, -}); + }); -const failedEmbed = (command: string, roleName: string) => makeEmbed({ +const failedEmbed = (command: string, roleName: string) => + makeEmbed({ title: 'Prefix Commands - Remove Role - Failed', description: `Failed to remove the prefix command role ${roleName} for command ${command}.`, color: Colors.Red, -}); + }); -const doesNotExistEmbed = (command: string, roleName: string) => makeEmbed({ +const doesNotExistEmbed = (command: string, roleName: string) => + makeEmbed({ title: 'Prefix Commands - Remove Role - Already exists', description: `A prefix command role ${roleName} for command ${command} and role does not exist.`, color: Colors.Red, -}); + }); -const successEmbed = (command: string, roleName: string) => makeEmbed({ +const successEmbed = (command: string, roleName: string) => + makeEmbed({ title: `Prefix command role ${roleName} removed for command ${command}.`, color: Colors.Green, -}); + }); -const modLogEmbed = (moderator: User, command: string, roleName: string) => makeEmbed({ +const modLogEmbed = (moderator: User, command: string, roleName: string) => + makeEmbed({ title: 'Remove prefix command role permission', fields: [ - { - name: 'Command', - value: command, - }, - { - name: 'Role', - value: roleName, - }, - { - name: 'Moderator', - value: `${moderator}`, - }, + { + name: 'Command', + value: command, + }, + { + name: 'Role', + value: roleName, + }, + { + name: 'Moderator', + value: `${moderator}`, + }, ], color: Colors.Green, -}); + }); const noModLogs = makeEmbed({ - title: 'Prefix Commands - Remove Role - No Mod Log', - description: 'I can\'t find the mod logs role. Please check the role still exists.', - color: Colors.Red, + title: 'Prefix Commands - Remove Role - No Mod Log', + description: "I can't find the mod logs role. Please check the role still exists.", + color: Colors.Red, }); export async function handleRemovePrefixCommandRolePermission(interaction: ChatInputCommandInteraction<'cached'>) { - await interaction.deferReply({ ephemeral: true }); + await interaction.deferReply({ ephemeral: true }); - const conn = getConn(); - if (!conn) { - await interaction.followUp({ embeds: [noConnEmbed], ephemeral: true }); - return; - } + const conn = getConn(); + if (!conn) { + await interaction.followUp({ embeds: [noConnEmbed], ephemeral: true }); + return; + } - const command = interaction.options.getString('command')!; - const role = interaction.options.getRole('role')!; - const moderator = interaction.user; + const command = interaction.options.getString('command')!; + const role = interaction.options.getRole('role')!; + const moderator = interaction.user; - //Check if the mod logs role exists - let modLogsChannel = interaction.guild.channels.resolve(constantsConfig.channels.MOD_LOGS); - if (!modLogsChannel || !modLogsChannel.isTextBased()) { - modLogsChannel = null; - await interaction.followUp({ embeds: [noModLogs], ephemeral: true }); - } + //Check if the mod logs role exists + let modLogsChannel = interaction.guild.channels.resolve(constantsConfig.channels.MOD_LOGS); + if (!modLogsChannel || !modLogsChannel.isTextBased()) { + modLogsChannel = null; + await interaction.followUp({ embeds: [noModLogs], ephemeral: true }); + } - let foundCommands = await PrefixCommand.find({ name: command }); - if (!foundCommands || foundCommands.length > 1) { - foundCommands = await PrefixCommand.find({ aliases: { $in: [command] } }); - } - if (!foundCommands || foundCommands.length > 1) { - await interaction.followUp({ embeds: [noCommandEmbed(command)], ephemeral: true }); - return; - } - const [foundCommand] = foundCommands; - const { id: roleId, name: roleName } = role; + let foundCommands = await PrefixCommand.find({ name: command }); + if (!foundCommands || foundCommands.length > 1) { + foundCommands = await PrefixCommand.find({ aliases: { $in: [command] } }); + } + if (!foundCommands || foundCommands.length > 1) { + await interaction.followUp({ embeds: [noCommandEmbed(command)], ephemeral: true }); + return; + } + const [foundCommand] = foundCommands; + const { id: roleId, name: roleName } = role; - const existingRolePermission = foundCommand.permissions.roles?.includes(roleId); - if (existingRolePermission) { - foundCommand.permissions.roles = foundCommand.permissions.roles?.filter((id) => id !== roleId); + const existingRolePermission = foundCommand.permissions.roles?.includes(roleId); + if (existingRolePermission) { + foundCommand.permissions.roles = foundCommand.permissions.roles?.filter((id) => id !== roleId); + try { + await foundCommand.save(); + await refreshSinglePrefixCommandCache(foundCommand, foundCommand); + await interaction.followUp({ embeds: [successEmbed(command, roleName)], ephemeral: true }); + if (modLogsChannel) { try { - await foundCommand.save(); - await refreshSinglePrefixCommandCache(foundCommand, foundCommand); - await interaction.followUp({ embeds: [successEmbed(command, roleName)], ephemeral: true }); - if (modLogsChannel) { - try { - await modLogsChannel.send({ embeds: [modLogEmbed(moderator, command, roleName)] }); - } catch (error) { - Logger.error(`Failed to post a message to the mod logs role: ${error}`); - } - } + await modLogsChannel.send({ embeds: [modLogEmbed(moderator, command, roleName)] }); } catch (error) { - Logger.error(`Failed to remove prefix command role ${roleName} for command ${command}: ${error}`); - await interaction.followUp({ embeds: [failedEmbed(command, roleName)], ephemeral: true }); + Logger.error(`Failed to post a message to the mod logs role: ${error}`); } - } else { - await interaction.followUp({ embeds: [doesNotExistEmbed(command, roleName)], ephemeral: true }); + } + } catch (error) { + Logger.error(`Failed to remove prefix command role ${roleName} for command ${command}: ${error}`); + await interaction.followUp({ embeds: [failedEmbed(command, roleName)], ephemeral: true }); } + } else { + await interaction.followUp({ embeds: [doesNotExistEmbed(command, roleName)], ephemeral: true }); + } } diff --git a/src/commands/moderation/prefixCommands/functions/setChannelDefaultVersion.ts b/src/commands/moderation/prefixCommands/functions/setChannelDefaultVersion.ts index 1fc531ca..48ef9979 100644 --- a/src/commands/moderation/prefixCommands/functions/setChannelDefaultVersion.ts +++ b/src/commands/moderation/prefixCommands/functions/setChannelDefaultVersion.ts @@ -1,109 +1,124 @@ import { ChatInputCommandInteraction, Colors, User } from 'discord.js'; -import { constantsConfig, getConn, PrefixCommandVersion, PrefixCommandChannelDefaultVersion, Logger, makeEmbed, loadSinglePrefixCommandChannelDefaultVersionToCache } from '../../../../lib'; +import { + constantsConfig, + getConn, + PrefixCommandVersion, + PrefixCommandChannelDefaultVersion, + Logger, + makeEmbed, + loadSinglePrefixCommandChannelDefaultVersionToCache, +} from '../../../../lib'; const noConnEmbed = makeEmbed({ - title: 'Prefix Commands - Set Default Channel Version - No Connection', - description: 'Could not connect to the database. Unable to set the channel default version.', - color: Colors.Red, + title: 'Prefix Commands - Set Default Channel Version - No Connection', + description: 'Could not connect to the database. Unable to set the channel default version.', + color: Colors.Red, }); -const noVersionEmbed = (channel: string) => makeEmbed({ +const noVersionEmbed = (channel: string) => + makeEmbed({ title: 'Prefix Commands - Show Default Channel Version - No Version', description: `Failed to show default channel version for channel ${channel} as the configured version does not exist.`, color: Colors.Red, -}); + }); -const failedEmbed = (channel: string) => makeEmbed({ +const failedEmbed = (channel: string) => + makeEmbed({ title: 'Prefix Commands - Set Default Channel Version - Failed', description: `Failed to set the channel default version for channel ${channel}.`, color: Colors.Red, -}); + }); -const successEmbed = (channel: string, version: string, emoji: string) => makeEmbed({ +const successEmbed = (channel: string, version: string, emoji: string) => + makeEmbed({ title: `Prefix Command Channel Default version set for channel ${channel} to version ${version} ${emoji}.`, color: Colors.Green, -}); + }); -const modLogEmbed = (moderator: User, channel: string, version: string, emoji: string) => makeEmbed({ +const modLogEmbed = (moderator: User, channel: string, version: string, emoji: string) => + makeEmbed({ title: 'Prefix channel default version set', fields: [ - { - name: 'Channel', - value: channel, - }, - { - name: 'Version', - value: `${version} - ${emoji}`, - }, - { - name: 'Moderator', - value: `${moderator}`, - }, + { + name: 'Channel', + value: channel, + }, + { + name: 'Version', + value: `${version} - ${emoji}`, + }, + { + name: 'Moderator', + value: `${moderator}`, + }, ], color: Colors.Green, -}); + }); const noModLogs = makeEmbed({ - title: 'Prefix Commands - Set Default Channel Version - No Mod Log', - description: 'I can\'t find the mod logs channel. Please check the channel still exists.', - color: Colors.Red, + title: 'Prefix Commands - Set Default Channel Version - No Mod Log', + description: "I can't find the mod logs channel. Please check the channel still exists.", + color: Colors.Red, }); export async function handleSetPrefixCommandChannelDefaultVersion(interaction: ChatInputCommandInteraction<'cached'>) { - await interaction.deferReply({ ephemeral: true }); + await interaction.deferReply({ ephemeral: true }); - const conn = getConn(); - if (!conn) { - await interaction.followUp({ embeds: [noConnEmbed], ephemeral: true }); - return; - } + const conn = getConn(); + if (!conn) { + await interaction.followUp({ embeds: [noConnEmbed], ephemeral: true }); + return; + } - const channel = interaction.options.getChannel('channel')!; - const version = interaction.options.getString('version')!; - const moderator = interaction.user; + const channel = interaction.options.getChannel('channel')!; + const version = interaction.options.getString('version')!; + const moderator = interaction.user; - //Check if the mod logs channel exists - let modLogsChannel = interaction.guild.channels.resolve(constantsConfig.channels.MOD_LOGS); - if (!modLogsChannel || !modLogsChannel.isTextBased()) { - modLogsChannel = null; - await interaction.followUp({ embeds: [noModLogs], ephemeral: true }); - } + //Check if the mod logs channel exists + let modLogsChannel = interaction.guild.channels.resolve(constantsConfig.channels.MOD_LOGS); + if (!modLogsChannel || !modLogsChannel.isTextBased()) { + modLogsChannel = null; + await interaction.followUp({ embeds: [noModLogs], ephemeral: true }); + } - let foundVersion; - if (version !== 'GENERIC') { - foundVersion = await PrefixCommandVersion.findOne({ name: version }); - } + let foundVersion; + if (version !== 'GENERIC') { + foundVersion = await PrefixCommandVersion.findOne({ name: version }); + } - if (foundVersion || version === 'GENERIC') { - const { id: channelId, name: channelName } = channel; - let versionId = ''; - let emoji = ''; - if (version === 'GENERIC') { - versionId = 'GENERIC'; - emoji = ''; - } else if (foundVersion) { - versionId = foundVersion.id; - emoji = foundVersion.emoji; - } - const foundChannelDefaultVersion = await PrefixCommandChannelDefaultVersion.findOne({ channelId }); - const channelDefaultVersion = foundChannelDefaultVersion || new PrefixCommandChannelDefaultVersion({ channelId, versionId }); - channelDefaultVersion.versionId = versionId; + if (foundVersion || version === 'GENERIC') { + const { id: channelId, name: channelName } = channel; + let versionId = ''; + let emoji = ''; + if (version === 'GENERIC') { + versionId = 'GENERIC'; + emoji = ''; + } else if (foundVersion) { + versionId = foundVersion.id; + emoji = foundVersion.emoji; + } + const foundChannelDefaultVersion = await PrefixCommandChannelDefaultVersion.findOne({ channelId }); + const channelDefaultVersion = + foundChannelDefaultVersion || new PrefixCommandChannelDefaultVersion({ channelId, versionId }); + channelDefaultVersion.versionId = versionId; + try { + await channelDefaultVersion.save(); + await loadSinglePrefixCommandChannelDefaultVersionToCache(channelDefaultVersion); + await interaction.followUp({ embeds: [successEmbed(channelName, version, emoji)], ephemeral: true }); + if (modLogsChannel) { try { - await channelDefaultVersion.save(); - await loadSinglePrefixCommandChannelDefaultVersionToCache(channelDefaultVersion); - await interaction.followUp({ embeds: [successEmbed(channelName, version, emoji)], ephemeral: true }); - if (modLogsChannel) { - try { - await modLogsChannel.send({ embeds: [modLogEmbed(moderator, channelName, version, emoji)] }); - } catch (error) { - Logger.error(`Failed to post a message to the mod logs channel: ${error}`); - } - } + await modLogsChannel.send({ embeds: [modLogEmbed(moderator, channelName, version, emoji)] }); } catch (error) { - Logger.error(`Failed to set the default channel version for channel ${channelName} to version ${version}: ${error}`); - await interaction.followUp({ embeds: [failedEmbed(channelName)], ephemeral: true }); + Logger.error(`Failed to post a message to the mod logs channel: ${error}`); } - } else { - await interaction.followUp({ embeds: [noVersionEmbed(version)], ephemeral: true }); + } + } catch (error) { + Logger.error( + `Failed to set the default channel version for channel ${channelName} to version ${version}: ${error}`, + ); + await interaction.followUp({ embeds: [failedEmbed(channelName)], ephemeral: true }); } + } else { + await interaction.followUp({ embeds: [noVersionEmbed(version)], ephemeral: true }); + } } diff --git a/src/commands/moderation/prefixCommands/functions/setCommandPermissionSettings.ts b/src/commands/moderation/prefixCommands/functions/setCommandPermissionSettings.ts index 388fdcd0..110babfb 100644 --- a/src/commands/moderation/prefixCommands/functions/setCommandPermissionSettings.ts +++ b/src/commands/moderation/prefixCommands/functions/setCommandPermissionSettings.ts @@ -1,123 +1,144 @@ import { ChatInputCommandInteraction, Colors, User } from 'discord.js'; -import { constantsConfig, getConn, Logger, makeEmbed, PrefixCommand, PrefixCommandPermissions, refreshSinglePrefixCommandCache } from '../../../../lib'; +import { + constantsConfig, + getConn, + Logger, + makeEmbed, + PrefixCommand, + PrefixCommandPermissions, + refreshSinglePrefixCommandCache, +} from '../../../../lib'; const noConnEmbed = makeEmbed({ - title: 'Prefix Commands - Set Permission Settings - No Connection', - description: 'Could not connect to the database. Unable to set the permission settings.', - color: Colors.Red, + title: 'Prefix Commands - Set Permission Settings - No Connection', + description: 'Could not connect to the database. Unable to set the permission settings.', + color: Colors.Red, }); -const noCommandEmbed = (command: string) => makeEmbed({ +const noCommandEmbed = (command: string) => + makeEmbed({ title: 'Prefix Commands - Set Permission Settings - No Command', description: `Failed to set default channel version for command ${command} as the command does not exist.`, color: Colors.Red, -}); + }); -const failedEmbed = (command: string) => makeEmbed({ +const failedEmbed = (command: string) => + makeEmbed({ title: 'Prefix Commands - Set Permission Settings - Failed', description: `Failed to set the permission settings for command ${command}.`, color: Colors.Red, -}); + }); -const successEmbed = (command: string) => makeEmbed({ +const successEmbed = (command: string) => + makeEmbed({ title: `Prefix Command permission settings set for command ${command}.`, color: Colors.Green, -}); + }); -const modLogEmbed = (moderator: User, command: string, rolesBlocklist: boolean, channelsBlocklist: boolean, quietErrors: boolean, verboseErrors: boolean) => makeEmbed({ +const modLogEmbed = ( + moderator: User, + command: string, + rolesBlocklist: boolean, + channelsBlocklist: boolean, + quietErrors: boolean, + verboseErrors: boolean, +) => + makeEmbed({ title: 'Prefix command permission set', fields: [ - { - name: 'Command', - value: command, - }, - { - name: 'Roles Blocklist', - value: rolesBlocklist ? 'Enabled' : 'Disabled', - }, - { - name: 'Channels Blocklist', - value: channelsBlocklist ? 'Enabled' : 'Disabled', - }, - { - name: 'Quiet Errors', - value: quietErrors ? 'Enabled' : 'Disabled', - }, - { - name: 'Verbose Errors', - value: verboseErrors ? 'Enabled' : 'Disabled', - }, - { - name: 'Moderator', - value: `${moderator}`, - }, + { + name: 'Command', + value: command, + }, + { + name: 'Roles Blocklist', + value: rolesBlocklist ? 'Enabled' : 'Disabled', + }, + { + name: 'Channels Blocklist', + value: channelsBlocklist ? 'Enabled' : 'Disabled', + }, + { + name: 'Quiet Errors', + value: quietErrors ? 'Enabled' : 'Disabled', + }, + { + name: 'Verbose Errors', + value: verboseErrors ? 'Enabled' : 'Disabled', + }, + { + name: 'Moderator', + value: `${moderator}`, + }, ], color: Colors.Green, -}); + }); const noModLogs = makeEmbed({ - title: 'Prefix Commands - Set Permission Settings - No Mod Log', - description: 'I can\'t find the mod logs channel. Please check the channel still exists.', - color: Colors.Red, + title: 'Prefix Commands - Set Permission Settings - No Mod Log', + description: "I can't find the mod logs channel. Please check the channel still exists.", + color: Colors.Red, }); export async function handleSetPrefixCommandPermissionSettings(interaction: ChatInputCommandInteraction<'cached'>) { - await interaction.deferReply({ ephemeral: true }); + await interaction.deferReply({ ephemeral: true }); - const conn = getConn(); - if (!conn) { - await interaction.followUp({ embeds: [noConnEmbed], ephemeral: true }); - return; - } + const conn = getConn(); + if (!conn) { + await interaction.followUp({ embeds: [noConnEmbed], ephemeral: true }); + return; + } - const command = interaction.options.getString('command')!; - const rolesBlocklist = interaction.options.getBoolean('roles-blocklist') || false; - const channelsBlocklist = interaction.options.getBoolean('channels-blocklist') || false; - const quietErrors = interaction.options.getBoolean('quiet-errors') || false; - const verboseErrors = interaction.options.getBoolean('verbose-errors') || false; - const moderator = interaction.user; + const command = interaction.options.getString('command')!; + const rolesBlocklist = interaction.options.getBoolean('roles-blocklist') || false; + const channelsBlocklist = interaction.options.getBoolean('channels-blocklist') || false; + const quietErrors = interaction.options.getBoolean('quiet-errors') || false; + const verboseErrors = interaction.options.getBoolean('verbose-errors') || false; + const moderator = interaction.user; - //Check if the mod logs channel exists - let modLogsChannel = interaction.guild.channels.resolve(constantsConfig.channels.MOD_LOGS); - if (!modLogsChannel || !modLogsChannel.isTextBased()) { - modLogsChannel = null; - await interaction.followUp({ embeds: [noModLogs], ephemeral: true }); - } + //Check if the mod logs channel exists + let modLogsChannel = interaction.guild.channels.resolve(constantsConfig.channels.MOD_LOGS); + if (!modLogsChannel || !modLogsChannel.isTextBased()) { + modLogsChannel = null; + await interaction.followUp({ embeds: [noModLogs], ephemeral: true }); + } - let foundCommands = await PrefixCommand.find({ name: command }); - if (!foundCommands || foundCommands.length > 1) { - foundCommands = await PrefixCommand.find({ aliases: { $in: [command] } }); - } - if (!foundCommands || foundCommands.length > 1) { - await interaction.followUp({ embeds: [noCommandEmbed(command)], ephemeral: true }); - return; - } + let foundCommands = await PrefixCommand.find({ name: command }); + if (!foundCommands || foundCommands.length > 1) { + foundCommands = await PrefixCommand.find({ aliases: { $in: [command] } }); + } + if (!foundCommands || foundCommands.length > 1) { + await interaction.followUp({ embeds: [noCommandEmbed(command)], ephemeral: true }); + return; + } - const [foundCommand] = foundCommands; - if (foundCommand) { - if (!foundCommand.permissions) { - foundCommand.permissions = new PrefixCommandPermissions(); - } - foundCommand.permissions.rolesBlocklist = rolesBlocklist; - foundCommand.permissions.channelsBlocklist = channelsBlocklist; - foundCommand.permissions.quietErrors = quietErrors; - foundCommand.permissions.verboseErrors = verboseErrors; + const [foundCommand] = foundCommands; + if (foundCommand) { + if (!foundCommand.permissions) { + foundCommand.permissions = new PrefixCommandPermissions(); + } + foundCommand.permissions.rolesBlocklist = rolesBlocklist; + foundCommand.permissions.channelsBlocklist = channelsBlocklist; + foundCommand.permissions.quietErrors = quietErrors; + foundCommand.permissions.verboseErrors = verboseErrors; + try { + await foundCommand.save(); + await refreshSinglePrefixCommandCache(foundCommand, foundCommand); + await interaction.followUp({ embeds: [successEmbed(command)], ephemeral: true }); + if (modLogsChannel) { try { - await foundCommand.save(); - await refreshSinglePrefixCommandCache(foundCommand, foundCommand); - await interaction.followUp({ embeds: [successEmbed(command)], ephemeral: true }); - if (modLogsChannel) { - try { - await modLogsChannel.send({ embeds: [modLogEmbed(moderator, command, rolesBlocklist, channelsBlocklist, quietErrors, verboseErrors)] }); - } catch (error) { - Logger.error(`Failed to post a message to the mod logs channel: ${error}`); - } - } + await modLogsChannel.send({ + embeds: [modLogEmbed(moderator, command, rolesBlocklist, channelsBlocklist, quietErrors, verboseErrors)], + }); } catch (error) { - Logger.error(`Failed to set the permission settings for command ${command}: ${error}`); - await interaction.followUp({ embeds: [failedEmbed(command)], ephemeral: true }); + Logger.error(`Failed to post a message to the mod logs channel: ${error}`); } - } else { - await interaction.followUp({ embeds: [noCommandEmbed(command)], ephemeral: true }); + } + } catch (error) { + Logger.error(`Failed to set the permission settings for command ${command}: ${error}`); + await interaction.followUp({ embeds: [failedEmbed(command)], ephemeral: true }); } + } else { + await interaction.followUp({ embeds: [noCommandEmbed(command)], ephemeral: true }); + } } diff --git a/src/commands/moderation/prefixCommands/functions/setContent.ts b/src/commands/moderation/prefixCommands/functions/setContent.ts index 72f7eb4c..9377b7b6 100644 --- a/src/commands/moderation/prefixCommands/functions/setContent.ts +++ b/src/commands/moderation/prefixCommands/functions/setContent.ts @@ -1,230 +1,265 @@ -import { ActionRowBuilder, ChatInputCommandInteraction, Colors, ModalBuilder, ModalSubmitInteraction, TextInputBuilder, TextInputStyle, User } from 'discord.js'; -import { constantsConfig, getConn, PrefixCommandVersion, PrefixCommand, Logger, makeEmbed, refreshSinglePrefixCommandCache, PrefixCommandContent } from '../../../../lib'; +import { + ActionRowBuilder, + ChatInputCommandInteraction, + Colors, + ModalBuilder, + ModalSubmitInteraction, + TextInputBuilder, + TextInputStyle, + User, +} from 'discord.js'; +import { + constantsConfig, + getConn, + PrefixCommandVersion, + PrefixCommand, + Logger, + makeEmbed, + refreshSinglePrefixCommandCache, + PrefixCommandContent, +} from '../../../../lib'; const noConnEmbed = makeEmbed({ - title: 'Prefix Commands - Set Content - No Connection', - description: 'Could not connect to the database. Unable to set the prefix command content.', - color: Colors.Red, + title: 'Prefix Commands - Set Content - No Connection', + description: 'Could not connect to the database. Unable to set the prefix command content.', + color: Colors.Red, }); -const noCommandEmbed = (command: string) => makeEmbed({ +const noCommandEmbed = (command: string) => + makeEmbed({ title: 'Prefix Commands - Set Content - No Command', description: `Failed to set command content for command ${command} as the command does not exist or there are more than one matching.`, color: Colors.Red, -}); + }); -const noVersionEmbed = (version: string) => makeEmbed({ +const noVersionEmbed = (version: string) => + makeEmbed({ title: 'Prefix Commands - Set Content - No Version', description: `Failed to set command content for version ${version} as the version does not exist or there are more than one matching.`, color: Colors.Red, -}); + }); -const failedEmbed = (command: string, version: string) => makeEmbed({ +const failedEmbed = (command: string, version: string) => + makeEmbed({ title: 'Prefix Commands - Set Content - Failed', description: `Failed to set command content for command ${command} and version ${version}.`, color: Colors.Red, -}); + }); -const successEmbed = (command: string, version: string) => makeEmbed({ +const successEmbed = (command: string, version: string) => + makeEmbed({ title: `Prefix command content set for command ${command} and version ${version}.`, color: Colors.Green, -}); + }); -const modLogEmbed = (moderator: User, command: string, version: string, title: string, content: string, image: string, commandId: string, versionId: string) => makeEmbed({ +const modLogEmbed = ( + moderator: User, + command: string, + version: string, + title: string, + content: string, + image: string, + commandId: string, + versionId: string, +) => + makeEmbed({ title: 'Prefix command content set', fields: [ - { - name: 'Command', - value: command, - }, - { - name: 'Version', - value: version, - }, - { - name: 'Title', - value: title, - }, - { - name: 'Content', - value: content, - }, - { - name: 'Image', - value: image, - }, - { - name: 'Moderator', - value: `${moderator}`, - }, + { + name: 'Command', + value: command, + }, + { + name: 'Version', + value: version, + }, + { + name: 'Title', + value: title, + }, + { + name: 'Content', + value: content, + }, + { + name: 'Image', + value: image, + }, + { + name: 'Moderator', + value: `${moderator}`, + }, ], footer: { text: `Command ID: ${commandId} - Version ID: ${versionId}` }, color: Colors.Green, -}); + }); const noModLogs = makeEmbed({ - title: 'Prefix Commands - Set Content - No Mod Log', - description: 'I can\'t find the mod logs channel. Please check the channel still exists.', - color: Colors.Red, + title: 'Prefix Commands - Set Content - No Mod Log', + description: "I can't find the mod logs channel. Please check the channel still exists.", + color: Colors.Red, }); export async function handleSetPrefixCommandContent(interaction: ChatInputCommandInteraction<'cached'>) { - const conn = getConn(); - if (!conn) { - await interaction.reply({ embeds: [noConnEmbed], ephemeral: true }); - return; - } + const conn = getConn(); + if (!conn) { + await interaction.reply({ embeds: [noConnEmbed], ephemeral: true }); + return; + } - const command = interaction.options.getString('command')!; - const version = interaction.options.getString('version')!; - const moderator = interaction.user; + const command = interaction.options.getString('command')!; + const version = interaction.options.getString('version')!; + const moderator = interaction.user; - let foundCommands = await PrefixCommand.find({ name: command }); - if (!foundCommands || foundCommands.length !== 1) { - foundCommands = await PrefixCommand.find({ aliases: { $in: [command] } }); - } - if (!foundCommands || foundCommands.length !== 1) { - await interaction.reply({ embeds: [noCommandEmbed(command)], ephemeral: true }); - return; - } + let foundCommands = await PrefixCommand.find({ name: command }); + if (!foundCommands || foundCommands.length !== 1) { + foundCommands = await PrefixCommand.find({ aliases: { $in: [command] } }); + } + if (!foundCommands || foundCommands.length !== 1) { + await interaction.reply({ embeds: [noCommandEmbed(command)], ephemeral: true }); + return; + } - const foundCommand = foundCommands[0]; - const { _id: commandId } = foundCommand; - let versionId = ''; - let foundVersions = null; - if (version === 'GENERIC' || version === 'generic') { - versionId = 'GENERIC'; + const foundCommand = foundCommands[0]; + const { _id: commandId } = foundCommand; + let versionId = ''; + let foundVersions = null; + if (version === 'GENERIC' || version === 'generic') { + versionId = 'GENERIC'; + } else { + foundVersions = await PrefixCommandVersion.find({ name: version }); + if (foundVersions && foundVersions.length === 1) { + [{ _id: versionId }] = foundVersions; } else { - foundVersions = await PrefixCommandVersion.find({ name: version }); - if (foundVersions && foundVersions.length === 1) { - [{ _id: versionId }] = foundVersions; - } else { - await interaction.reply({ embeds: [noVersionEmbed(version)], ephemeral: true }); - return; - } + await interaction.reply({ embeds: [noVersionEmbed(version)], ephemeral: true }); + return; } + } - const foundContent = foundCommand.contents.find((c) => c.versionId.toString() === versionId.toString()); - const contentModal = new ModalBuilder({ - customId: 'commandContentModal', - title: `Content for ${command} - ${version}`, - }); + const foundContent = foundCommand.contents.find((c) => c.versionId.toString() === versionId.toString()); + const contentModal = new ModalBuilder({ + customId: 'commandContentModal', + title: `Content for ${command} - ${version}`, + }); - const commandContentTitle = new TextInputBuilder() - .setCustomId('commandContentTitle') - .setLabel('Title') - .setPlaceholder('Provide a title for the command.') - .setStyle(TextInputStyle.Short) - .setMaxLength(255) - .setMinLength(0) - .setRequired(false) - .setValue(foundContent ? foundContent.title : ''); - - const commandContentContent = new TextInputBuilder() - .setCustomId('commandContentContent') - .setLabel('Content') - .setPlaceholder('Provide the content for the command.') - .setStyle(TextInputStyle.Paragraph) - .setMaxLength(4000) - .setMinLength(0) - .setRequired(false) - .setValue(foundContent && foundContent.content ? foundContent.content : ''); - - const commandContentImageUrl = new TextInputBuilder() - .setCustomId('commandContentImageUrl') - .setLabel('Image URL') - .setPlaceholder('Provide an optional Image URL for the command.') - .setStyle(TextInputStyle.Short) - .setMaxLength(2048) - .setMinLength(0) - .setRequired(false) - .setValue(foundContent && foundContent.image ? foundContent.image : ''); - - const titleActionRow = new ActionRowBuilder().addComponents(commandContentTitle); - const contentActionRow = new ActionRowBuilder().addComponents(commandContentContent); - const imageUrlActionRow = new ActionRowBuilder().addComponents(commandContentImageUrl); - - contentModal.addComponents(titleActionRow); - contentModal.addComponents(contentActionRow); - contentModal.addComponents(imageUrlActionRow); - - await interaction.showModal(contentModal); - - const filter = (interaction: ModalSubmitInteraction) => interaction.customId === 'commandContentModal' && interaction.user.id === moderator.id; - - let title = ''; - let content = ''; - let image = ''; + const commandContentTitle = new TextInputBuilder() + .setCustomId('commandContentTitle') + .setLabel('Title') + .setPlaceholder('Provide a title for the command.') + .setStyle(TextInputStyle.Short) + .setMaxLength(255) + .setMinLength(0) + .setRequired(false) + .setValue(foundContent ? foundContent.title : ''); - try { - //Await a modal response - const modalSubmitInteraction = await interaction.awaitModalSubmit({ - filter, - time: 120000, - }); + const commandContentContent = new TextInputBuilder() + .setCustomId('commandContentContent') + .setLabel('Content') + .setPlaceholder('Provide the content for the command.') + .setStyle(TextInputStyle.Paragraph) + .setMaxLength(4000) + .setMinLength(0) + .setRequired(false) + .setValue(foundContent && foundContent.content ? foundContent.content : ''); - title = modalSubmitInteraction.fields.getTextInputValue('commandContentTitle').trim(); - content = modalSubmitInteraction.fields.getTextInputValue('commandContentContent').trim(); - image = modalSubmitInteraction.fields.getTextInputValue('commandContentImageUrl').trim(); - - if (!title && !content && !image) { - await modalSubmitInteraction.reply({ - content: 'You did not provide any content information and the change was not made.', - ephemeral: true, - }); - return; - } - await modalSubmitInteraction.reply({ - content: 'Processing command content data.', - ephemeral: true, - }); - } catch (error) { - //Handle the error if the user does not respond in time - Logger.error(error); - await interaction.followUp({ - content: 'You did not provide the necessary content information in time (2 minutes) and the change was not made.', - ephemeral: true, - }); - return; - } - //Check if the mod logs channel exists - let modLogsChannel = interaction.guild.channels.resolve(constantsConfig.channels.MOD_LOGS); - if (!modLogsChannel || !modLogsChannel.isTextBased()) { - modLogsChannel = null; - await interaction.followUp({ embeds: [noModLogs], ephemeral: true }); - } + const commandContentImageUrl = new TextInputBuilder() + .setCustomId('commandContentImageUrl') + .setLabel('Image URL') + .setPlaceholder('Provide an optional Image URL for the command.') + .setStyle(TextInputStyle.Short) + .setMaxLength(2048) + .setMinLength(0) + .setRequired(false) + .setValue(foundContent && foundContent.image ? foundContent.image : ''); + + const titleActionRow = new ActionRowBuilder().addComponents(commandContentTitle); + const contentActionRow = new ActionRowBuilder().addComponents(commandContentContent); + const imageUrlActionRow = new ActionRowBuilder().addComponents(commandContentImageUrl); + + contentModal.addComponents(titleActionRow); + contentModal.addComponents(contentActionRow); + contentModal.addComponents(imageUrlActionRow); + + await interaction.showModal(contentModal); + + const filter = (interaction: ModalSubmitInteraction) => + interaction.customId === 'commandContentModal' && interaction.user.id === moderator.id; + + let title = ''; + let content = ''; + let image = ''; - if (foundContent) { - const foundData = foundCommand.contents.find((c) => c.versionId === foundContent.versionId); - try { - await foundData?.deleteOne(); - } catch (error) { - Logger.error(`Failed to delete existing content for prefix command ${command} and version ${version}: ${error}`); - await interaction.followUp({ embeds: [failedEmbed(command, version)], ephemeral: true }); - return; - } + try { + //Await a modal response + const modalSubmitInteraction = await interaction.awaitModalSubmit({ + filter, + time: 120000, + }); + + title = modalSubmitInteraction.fields.getTextInputValue('commandContentTitle').trim(); + content = modalSubmitInteraction.fields.getTextInputValue('commandContentContent').trim(); + image = modalSubmitInteraction.fields.getTextInputValue('commandContentImageUrl').trim(); + + if (!title && !content && !image) { + await modalSubmitInteraction.reply({ + content: 'You did not provide any content information and the change was not made.', + ephemeral: true, + }); + return; } - const contentData = new PrefixCommandContent({ - versionId, - title, - content, - image, + await modalSubmitInteraction.reply({ + content: 'Processing command content data.', + ephemeral: true, + }); + } catch (error) { + //Handle the error if the user does not respond in time + Logger.error(error); + await interaction.followUp({ + content: 'You did not provide the necessary content information in time (2 minutes) and the change was not made.', + ephemeral: true, }); - foundCommand.contents.push(contentData); + return; + } + //Check if the mod logs channel exists + let modLogsChannel = interaction.guild.channels.resolve(constantsConfig.channels.MOD_LOGS); + if (!modLogsChannel || !modLogsChannel.isTextBased()) { + modLogsChannel = null; + await interaction.followUp({ embeds: [noModLogs], ephemeral: true }); + } + if (foundContent) { + const foundData = foundCommand.contents.find((c) => c.versionId === foundContent.versionId); try { - await foundCommand.save(); - await refreshSinglePrefixCommandCache(foundCommand, foundCommand); - await interaction.followUp({ embeds: [successEmbed(command, version)], ephemeral: true }); - if (modLogsChannel) { - try { - await modLogsChannel.send({ embeds: [modLogEmbed(moderator, command, version, title, content, image, commandId, versionId)] }); - } catch (error) { - Logger.error(`Failed to post a message to the mod logs channel: ${error}`); - } - } + await foundData?.deleteOne(); } catch (error) { - Logger.error(`Failed to set prefix command content for command ${command} and version ${version}: ${error}`); - await interaction.followUp({ embeds: [failedEmbed(command, version)], ephemeral: true }); + Logger.error(`Failed to delete existing content for prefix command ${command} and version ${version}: ${error}`); + await interaction.followUp({ embeds: [failedEmbed(command, version)], ephemeral: true }); + return; + } + } + const contentData = new PrefixCommandContent({ + versionId, + title, + content, + image, + }); + foundCommand.contents.push(contentData); + + try { + await foundCommand.save(); + await refreshSinglePrefixCommandCache(foundCommand, foundCommand); + await interaction.followUp({ embeds: [successEmbed(command, version)], ephemeral: true }); + if (modLogsChannel) { + try { + await modLogsChannel.send({ + embeds: [modLogEmbed(moderator, command, version, title, content, image, commandId, versionId)], + }); + } catch (error) { + Logger.error(`Failed to post a message to the mod logs channel: ${error}`); + } } + } catch (error) { + Logger.error(`Failed to set prefix command content for command ${command} and version ${version}: ${error}`); + await interaction.followUp({ embeds: [failedEmbed(command, version)], ephemeral: true }); + } } diff --git a/src/commands/moderation/prefixCommands/functions/showChannelDefaultVersion.ts b/src/commands/moderation/prefixCommands/functions/showChannelDefaultVersion.ts index 03846f87..a8fcef88 100644 --- a/src/commands/moderation/prefixCommands/functions/showChannelDefaultVersion.ts +++ b/src/commands/moderation/prefixCommands/functions/showChannelDefaultVersion.ts @@ -2,75 +2,86 @@ import { ChatInputCommandInteraction, Colors } from 'discord.js'; import { getConn, PrefixCommandChannelDefaultVersion, PrefixCommandVersion, Logger, makeEmbed } from '../../../../lib'; const noConnEmbed = makeEmbed({ - title: 'Prefix Commands - Show Default Channel Version - No Connection', - description: 'Could not connect to the database. Unable to show the channel default version.', - color: Colors.Red, + title: 'Prefix Commands - Show Default Channel Version - No Connection', + description: 'Could not connect to the database. Unable to show the channel default version.', + color: Colors.Red, }); -const noVersionEmbed = (channel: string) => makeEmbed({ +const noVersionEmbed = (channel: string) => + makeEmbed({ title: 'Prefix Commands - Show Default Channel Version - No Version', description: `Failed to show default channel version for channel ${channel} as the configured version does not exist.`, color: Colors.Red, -}); + }); -const noChannelDefaultVersionEmbed = (channel: string) => makeEmbed({ +const noChannelDefaultVersionEmbed = (channel: string) => + makeEmbed({ title: 'Prefix Commands - Show Default Channel Version - No Default Channel Version', description: `Failed to show the channel default version for channel ${channel} as there is no default version set.`, color: Colors.Red, -}); + }); -const failedEmbed = (channel: string) => makeEmbed({ +const failedEmbed = (channel: string) => + makeEmbed({ title: 'Prefix Commands - Show Default Channel Version - Failed', description: `Failed to show the channel default version for channel ${channel}.`, color: Colors.Red, -}); + }); -const contentEmbed = (channel: string, version: string, emoji: string, versionId: string) => makeEmbed({ +const contentEmbed = (channel: string, version: string, emoji: string, versionId: string) => + makeEmbed({ title: `Prefix Commands - Show Default Channel Version - ${channel} - ${version}`, fields: [ - { - name: 'Channel', - value: channel, - }, - { - name: 'Version', - value: `${version} - ${emoji}`, - }, + { + name: 'Channel', + value: channel, + }, + { + name: 'Version', + value: `${version} - ${emoji}`, + }, ], footer: { text: `Version ID: ${versionId}` }, color: Colors.Green, -}); + }); export async function handleShowPrefixCommandChannelDefaultVersion(interaction: ChatInputCommandInteraction<'cached'>) { - await interaction.deferReply({ ephemeral: true }); + await interaction.deferReply({ ephemeral: true }); - const conn = getConn(); - if (!conn) { - await interaction.followUp({ embeds: [noConnEmbed], ephemeral: true }); - return; - } + const conn = getConn(); + if (!conn) { + await interaction.followUp({ embeds: [noConnEmbed], ephemeral: true }); + return; + } - const channel = interaction.options.getChannel('channel')!; - const { id: channelId, name: channelName } = channel; - const foundChannelDefaultVersions = await PrefixCommandChannelDefaultVersion.find({ channelId }); - if (!foundChannelDefaultVersions || foundChannelDefaultVersions.length === 0 || foundChannelDefaultVersions.length > 1) { - await interaction.followUp({ embeds: [noChannelDefaultVersionEmbed(channelName)], ephemeral: true }); - return; - } + const channel = interaction.options.getChannel('channel')!; + const { id: channelId, name: channelName } = channel; + const foundChannelDefaultVersions = await PrefixCommandChannelDefaultVersion.find({ channelId }); + if ( + !foundChannelDefaultVersions || + foundChannelDefaultVersions.length === 0 || + foundChannelDefaultVersions.length > 1 + ) { + await interaction.followUp({ embeds: [noChannelDefaultVersionEmbed(channelName)], ephemeral: true }); + return; + } - const [foundChannelDefaultVersion] = foundChannelDefaultVersions; - const { versionId } = foundChannelDefaultVersion; - const foundVersion = await PrefixCommandVersion.findById(versionId); - if (!foundVersion) { - await interaction.followUp({ embeds: [noVersionEmbed(channelName)], ephemeral: true }); - return; - } + const [foundChannelDefaultVersion] = foundChannelDefaultVersions; + const { versionId } = foundChannelDefaultVersion; + const foundVersion = await PrefixCommandVersion.findById(versionId); + if (!foundVersion) { + await interaction.followUp({ embeds: [noVersionEmbed(channelName)], ephemeral: true }); + return; + } - const { name: version, emoji } = foundVersion; - try { - await interaction.followUp({ embeds: [contentEmbed(channelName, `${version}`, `${emoji}`, `${versionId}`)], ephemeral: false }); - } catch (error) { - Logger.error(`Failed to show the channel default version for channel ${channel} and version ${version}: ${error}`); - await interaction.followUp({ embeds: [failedEmbed(channelName)], ephemeral: true }); - } + const { name: version, emoji } = foundVersion; + try { + await interaction.followUp({ + embeds: [contentEmbed(channelName, `${version}`, `${emoji}`, `${versionId}`)], + ephemeral: false, + }); + } catch (error) { + Logger.error(`Failed to show the channel default version for channel ${channel} and version ${version}: ${error}`); + await interaction.followUp({ embeds: [failedEmbed(channelName)], ephemeral: true }); + } } diff --git a/src/commands/moderation/prefixCommands/functions/showCommandPermissions.ts b/src/commands/moderation/prefixCommands/functions/showCommandPermissions.ts index b64bb990..73dcad84 100644 --- a/src/commands/moderation/prefixCommands/functions/showCommandPermissions.ts +++ b/src/commands/moderation/prefixCommands/functions/showCommandPermissions.ts @@ -2,103 +2,127 @@ import { ChatInputCommandInteraction, Colors } from 'discord.js'; import { getConn, PrefixCommand, Logger, makeEmbed } from '../../../../lib'; const noConnEmbed = makeEmbed({ - title: 'Prefix Commands - Show Command Permissions - No Connection', - description: 'Could not connect to the database. Unable to show the prefix command permissions.', - color: Colors.Red, + title: 'Prefix Commands - Show Command Permissions - No Connection', + description: 'Could not connect to the database. Unable to show the prefix command permissions.', + color: Colors.Red, }); -const noCommandEmbed = (command: string) => makeEmbed({ +const noCommandEmbed = (command: string) => + makeEmbed({ title: 'Prefix Commands - Show Command Permissions - No Command', description: `Failed to show command permissions for command ${command} as the command does not exist or there are more than one matching.`, color: Colors.Red, -}); + }); -const failedEmbed = (command: string) => makeEmbed({ +const failedEmbed = (command: string) => + makeEmbed({ title: 'Prefix Commands - Show Command Permissions - Failed', description: `Failed to show command permissions for command ${command}.`, color: Colors.Red, -}); + }); -const permissionEmbed = (command: string, roles: string[], rolesBlocklist: boolean, channels: string[], channelsBlocklist: boolean, quietErrors: boolean, verboseErrors: boolean) => makeEmbed({ +const permissionEmbed = ( + command: string, + roles: string[], + rolesBlocklist: boolean, + channels: string[], + channelsBlocklist: boolean, + quietErrors: boolean, + verboseErrors: boolean, +) => + makeEmbed({ title: `Prefix Commands - Show Command Permissions - ${command}`, fields: [ - { - name: 'Roles', - value: roles.length > 0 ? roles.join(', ') : 'None', - }, - { - name: 'Roles Blocklist', - value: rolesBlocklist ? 'Enabled' : 'Disabled', - }, - { - name: 'Channels', - value: channels.length > 0 ? channels.join(', ') : 'None', - }, - { - name: 'Channels Blocklist', - value: channelsBlocklist ? 'Enabled' : 'Disabled', - }, - { - name: 'Quiet Errors', - value: quietErrors ? 'Enabled' : 'Disabled', - }, - { - name: 'Verbose Errors', - value: verboseErrors ? 'Enabled' : 'Disabled', - }, + { + name: 'Roles', + value: roles.length > 0 ? roles.join(', ') : 'None', + }, + { + name: 'Roles Blocklist', + value: rolesBlocklist ? 'Enabled' : 'Disabled', + }, + { + name: 'Channels', + value: channels.length > 0 ? channels.join(', ') : 'None', + }, + { + name: 'Channels Blocklist', + value: channelsBlocklist ? 'Enabled' : 'Disabled', + }, + { + name: 'Quiet Errors', + value: quietErrors ? 'Enabled' : 'Disabled', + }, + { + name: 'Verbose Errors', + value: verboseErrors ? 'Enabled' : 'Disabled', + }, ], color: Colors.Green, -}); + }); export async function handleShowPrefixCommandPermissions(interaction: ChatInputCommandInteraction<'cached'>) { - await interaction.deferReply({ ephemeral: true }); + await interaction.deferReply({ ephemeral: true }); - const conn = getConn(); - if (!conn) { - await interaction.followUp({ embeds: [noConnEmbed], ephemeral: true }); - return; - } + const conn = getConn(); + if (!conn) { + await interaction.followUp({ embeds: [noConnEmbed], ephemeral: true }); + return; + } - const command = interaction.options.getString('command') || ''; - let foundCommands = await PrefixCommand.find({ name: command }); - if (!foundCommands || foundCommands.length > 1) { - foundCommands = await PrefixCommand.find({ aliases: { $in: [command] } }); - } - if (!foundCommands || foundCommands.length > 1) { - await interaction.followUp({ embeds: [noCommandEmbed(command)], ephemeral: true }); - return; - } + const command = interaction.options.getString('command') || ''; + let foundCommands = await PrefixCommand.find({ name: command }); + if (!foundCommands || foundCommands.length > 1) { + foundCommands = await PrefixCommand.find({ aliases: { $in: [command] } }); + } + if (!foundCommands || foundCommands.length > 1) { + await interaction.followUp({ embeds: [noCommandEmbed(command)], ephemeral: true }); + return; + } - const [foundCommand] = foundCommands; - const { permissions } = foundCommand; - const { roles, rolesBlocklist, channels, channelsBlocklist, quietErrors, verboseErrors } = permissions; - const roleNames = []; - const channelNames = []; - if (roles) { - for (const role of roles) { - // eslint-disable-next-line no-await-in-loop - const discordRole = await interaction.guild.roles.fetch(role); - if (discordRole) { - const { name } = discordRole; - roleNames.push(name); - } - } + const [foundCommand] = foundCommands; + const { permissions } = foundCommand; + const { roles, rolesBlocklist, channels, channelsBlocklist, quietErrors, verboseErrors } = permissions; + const roleNames = []; + const channelNames = []; + if (roles) { + for (const role of roles) { + // eslint-disable-next-line no-await-in-loop + const discordRole = await interaction.guild.roles.fetch(role); + if (discordRole) { + const { name } = discordRole; + roleNames.push(name); + } } - if (channels) { - for (const channel of channels) { - // eslint-disable-next-line no-await-in-loop - const discordChannel = await interaction.guild.channels.fetch(channel); - if (discordChannel) { - const { id: channelId } = discordChannel; - channelNames.push(`<#${channelId}>`); - } - } + } + if (channels) { + for (const channel of channels) { + // eslint-disable-next-line no-await-in-loop + const discordChannel = await interaction.guild.channels.fetch(channel); + if (discordChannel) { + const { id: channelId } = discordChannel; + channelNames.push(`<#${channelId}>`); + } } + } - try { - await interaction.followUp({ embeds: [permissionEmbed(command, roleNames, rolesBlocklist || false, channelNames, channelsBlocklist || false, quietErrors || false, verboseErrors || false)], ephemeral: false }); - } catch (error) { - Logger.error(`Failed to show prefix command content for command ${command}: ${error}`); - await interaction.followUp({ embeds: [failedEmbed(command)], ephemeral: true }); - } + try { + await interaction.followUp({ + embeds: [ + permissionEmbed( + command, + roleNames, + rolesBlocklist || false, + channelNames, + channelsBlocklist || false, + quietErrors || false, + verboseErrors || false, + ), + ], + ephemeral: false, + }); + } catch (error) { + Logger.error(`Failed to show prefix command content for command ${command}: ${error}`); + await interaction.followUp({ embeds: [failedEmbed(command)], ephemeral: true }); + } } diff --git a/src/commands/moderation/prefixCommands/functions/showContent.ts b/src/commands/moderation/prefixCommands/functions/showContent.ts index 286d7997..d6c532fd 100644 --- a/src/commands/moderation/prefixCommands/functions/showContent.ts +++ b/src/commands/moderation/prefixCommands/functions/showContent.ts @@ -2,101 +2,129 @@ import { ChatInputCommandInteraction, Colors } from 'discord.js'; import { getConn, PrefixCommandVersion, PrefixCommand, Logger, makeEmbed } from '../../../../lib'; const noConnEmbed = makeEmbed({ - title: 'Prefix Commands - Show Content - No Connection', - description: 'Could not connect to the database. Unable to show the prefix command content.', - color: Colors.Red, + title: 'Prefix Commands - Show Content - No Connection', + description: 'Could not connect to the database. Unable to show the prefix command content.', + color: Colors.Red, }); -const noCommandEmbed = (command: string) => makeEmbed({ +const noCommandEmbed = (command: string) => + makeEmbed({ title: 'Prefix Commands - Show Content - No Command', description: `Failed to show command content for command ${command} as the command does not exist or there are more than one matching.`, color: Colors.Red, -}); + }); -const noVersionEmbed = (version: string) => makeEmbed({ +const noVersionEmbed = (version: string) => + makeEmbed({ title: 'Prefix Commands - Show Content - No Version', description: `Failed to show command content for version ${version} as the version does not exist or there are more than one matching.`, color: Colors.Red, -}); + }); -const noContentEmbed = (command: string, version: string) => makeEmbed({ +const noContentEmbed = (command: string, version: string) => + makeEmbed({ title: 'Prefix Commands - Show Content - No Content', description: `Failed to show command content for command ${command} and version ${version} as the content does not exist.`, color: Colors.Red, -}); + }); -const failedEmbed = (command: string, version: string) => makeEmbed({ +const failedEmbed = (command: string, version: string) => + makeEmbed({ title: 'Prefix Commands - Show Content - Failed', description: `Failed to show command content for command ${command} and version ${version}.`, color: Colors.Red, -}); + }); -const contentEmbed = (command: string, version: string, title: string, content: string, image: string, commandId: string, versionId: string, contentId: string) => makeEmbed({ +const contentEmbed = ( + command: string, + version: string, + title: string, + content: string, + image: string, + commandId: string, + versionId: string, + contentId: string, +) => + makeEmbed({ title: `Prefix Commands - Show Content - ${command} - ${version}`, fields: [ - { - name: 'Title', - value: title, - }, - { - name: 'Content', - value: content, - }, - { - name: 'Image', - value: image, - }, + { + name: 'Title', + value: title, + }, + { + name: 'Content', + value: content, + }, + { + name: 'Image', + value: image, + }, ], footer: { text: `Command ID: ${commandId} - Version ID: ${versionId} - Content ID: ${contentId}` }, color: Colors.Green, -}); + }); export async function handleShowPrefixCommandContent(interaction: ChatInputCommandInteraction<'cached'>) { - await interaction.deferReply({ ephemeral: true }); + await interaction.deferReply({ ephemeral: true }); - const conn = getConn(); - if (!conn) { - await interaction.followUp({ embeds: [noConnEmbed], ephemeral: true }); - return; - } + const conn = getConn(); + if (!conn) { + await interaction.followUp({ embeds: [noConnEmbed], ephemeral: true }); + return; + } - const command = interaction.options.getString('command') || ''; - const version = interaction.options.getString('version') || ''; - let foundCommands = await PrefixCommand.find({ name: command }); - if (!foundCommands || foundCommands.length > 1) { - foundCommands = await PrefixCommand.find({ aliases: { $in: [command] } }); - } - if (!foundCommands || foundCommands.length > 1) { - await interaction.followUp({ embeds: [noCommandEmbed(command)], ephemeral: true }); - return; - } + const command = interaction.options.getString('command') || ''; + const version = interaction.options.getString('version') || ''; + let foundCommands = await PrefixCommand.find({ name: command }); + if (!foundCommands || foundCommands.length > 1) { + foundCommands = await PrefixCommand.find({ aliases: { $in: [command] } }); + } + if (!foundCommands || foundCommands.length > 1) { + await interaction.followUp({ embeds: [noCommandEmbed(command)], ephemeral: true }); + return; + } - const [foundCommand] = foundCommands; - const { id: commandId } = foundCommand; - let versionId = ''; - if (version === 'GENERIC' || version === 'generic') { - versionId = 'GENERIC'; + const [foundCommand] = foundCommands; + const { id: commandId } = foundCommand; + let versionId = ''; + if (version === 'GENERIC' || version === 'generic') { + versionId = 'GENERIC'; + } else { + const foundVersions = await PrefixCommandVersion.find({ name: version }); + if (foundVersions && foundVersions.length === 1) { + const [foundVersion] = foundVersions; + ({ id: versionId } = foundVersion); } else { - const foundVersions = await PrefixCommandVersion.find({ name: version }); - if (foundVersions && foundVersions.length === 1) { - const [foundVersion] = foundVersions; - ({ id: versionId } = foundVersion); - } else { - await interaction.followUp({ embeds: [noVersionEmbed(version)], ephemeral: true }); - return; - } + await interaction.followUp({ embeds: [noVersionEmbed(version)], ephemeral: true }); + return; } + } - const foundContent = foundCommand.contents.find((content) => content.versionId === versionId); - if (!foundContent) { - await interaction.followUp({ embeds: [noContentEmbed(command, version)], ephemeral: true }); - return; - } - const { id: contentId, title, content, image } = foundContent; - try { - await interaction.followUp({ embeds: [contentEmbed(command, version, title || '', content || '', image || '', `${commandId}`, `${versionId}`, `${contentId}`)], ephemeral: false }); - } catch (error) { - Logger.error(`Failed to show prefix command content for command ${command} and version ${version}: ${error}`); - await interaction.followUp({ embeds: [failedEmbed(command, version)], ephemeral: true }); - } + const foundContent = foundCommand.contents.find((content) => content.versionId === versionId); + if (!foundContent) { + await interaction.followUp({ embeds: [noContentEmbed(command, version)], ephemeral: true }); + return; + } + const { id: contentId, title, content, image } = foundContent; + try { + await interaction.followUp({ + embeds: [ + contentEmbed( + command, + version, + title || '', + content || '', + image || '', + `${commandId}`, + `${versionId}`, + `${contentId}`, + ), + ], + ephemeral: false, + }); + } catch (error) { + Logger.error(`Failed to show prefix command content for command ${command} and version ${version}: ${error}`); + await interaction.followUp({ embeds: [failedEmbed(command, version)], ephemeral: true }); + } } diff --git a/src/commands/moderation/prefixCommands/prefixCommandCacheUpdate.ts b/src/commands/moderation/prefixCommands/prefixCommandCacheUpdate.ts index f4f87233..35eebfd4 100644 --- a/src/commands/moderation/prefixCommands/prefixCommandCacheUpdate.ts +++ b/src/commands/moderation/prefixCommands/prefixCommandCacheUpdate.ts @@ -1,80 +1,79 @@ import { APIEmbedField, ApplicationCommandType, Colors, EmbedField, TextChannel, User } from 'discord.js'; -import { constantsConfig, slashCommand, slashCommandStructure, makeEmbed, refreshAllPrefixCommandsCache, refreshAllPrefixCommandVersionsCache, refreshAllPrefixCommandCategoriesCache, refreshAllPrefixCommandChannelDefaultVersionsCache } from '../../../lib'; +import { + constantsConfig, + slashCommand, + slashCommandStructure, + makeEmbed, + refreshAllPrefixCommandsCache, + refreshAllPrefixCommandVersionsCache, + refreshAllPrefixCommandCategoriesCache, + refreshAllPrefixCommandChannelDefaultVersionsCache, +} from '../../../lib'; const data = slashCommandStructure({ - name: 'prefix-commands-cache-update', - description: 'Updates the in-memory prefix command cache of the bot.', - type: ApplicationCommandType.ChatInput, - default_member_permissions: constantsConfig.commandPermission.MANAGE_SERVER, //Overrides need to be added for admin, moderator and bot developer roles - dm_permission: false, - options: [], + name: 'prefix-commands-cache-update', + description: 'Updates the in-memory prefix command cache of the bot.', + type: ApplicationCommandType.ChatInput, + default_member_permissions: constantsConfig.commandPermission.MANAGE_SERVER, //Overrides need to be added for admin, moderator and bot developer roles + dm_permission: false, + options: [], }); -const cacheUpdateEmbed = (fields: APIEmbedField[], color: number) => makeEmbed({ +const cacheUpdateEmbed = (fields: APIEmbedField[], color: number) => + makeEmbed({ title: 'Prefix Command Cache Update', fields, color, -}); + }); -const noChannelEmbed = (channelName: string) => makeEmbed({ +const noChannelEmbed = (channelName: string) => + makeEmbed({ title: `Prefix Command Cache Update - No ${channelName} channel`, description: `The command was successful, but no message to ${channelName} was sent. Please check the channel still exists.`, color: Colors.Yellow, -}); + }); const cacheUpdateEmbedField = (moderator: User, duration: string): EmbedField[] => [ - { - name: 'Moderator', - value: `${moderator}`, - inline: true, - }, - { - name: 'Duration', - value: `${duration}s`, - inline: true, - }, + { + name: 'Moderator', + value: `${moderator}`, + inline: true, + }, + { + name: 'Duration', + value: `${duration}s`, + inline: true, + }, ]; export default slashCommand(data, async ({ interaction }) => { - await interaction.deferReply({ ephemeral: true }); + await interaction.deferReply({ ephemeral: true }); - const modLogsChannel = interaction.guild.channels.resolve(constantsConfig.channels.MOD_LOGS) as TextChannel; - const start = new Date().getTime(); - try { - await Promise.all([ - refreshAllPrefixCommandVersionsCache(), - refreshAllPrefixCommandCategoriesCache(), - refreshAllPrefixCommandsCache(), - refreshAllPrefixCommandChannelDefaultVersionsCache(), - ]); - } catch (error) { - await interaction.editReply({ content: `An error occurred while updating the cache: ${error}` }); - return; - } + const modLogsChannel = interaction.guild.channels.resolve(constantsConfig.channels.MOD_LOGS) as TextChannel; + const start = new Date().getTime(); + try { + await Promise.all([ + refreshAllPrefixCommandVersionsCache(), + refreshAllPrefixCommandCategoriesCache(), + refreshAllPrefixCommandsCache(), + refreshAllPrefixCommandChannelDefaultVersionsCache(), + ]); + } catch (error) { + await interaction.editReply({ content: `An error occurred while updating the cache: ${error}` }); + return; + } - const duration = ((new Date().getTime() - start) / 1000).toFixed(2); + const duration = ((new Date().getTime() - start) / 1000).toFixed(2); - await interaction.editReply({ - embeds: [cacheUpdateEmbed( - cacheUpdateEmbedField( - interaction.user, - duration, - ), - Colors.Green, - )], - }); + await interaction.editReply({ + embeds: [cacheUpdateEmbed(cacheUpdateEmbedField(interaction.user, duration), Colors.Green)], + }); - try { - await modLogsChannel.send({ - embeds: [cacheUpdateEmbed( - cacheUpdateEmbedField( - interaction.user, - duration, - ), - Colors.Green, - )], - }); - } catch (error) { - await interaction.followUp({ embeds: [noChannelEmbed('mod-log')] }); - } + try { + await modLogsChannel.send({ + embeds: [cacheUpdateEmbed(cacheUpdateEmbedField(interaction.user, duration), Colors.Green)], + }); + } catch (error) { + await interaction.followUp({ embeds: [noChannelEmbed('mod-log')] }); + } }); diff --git a/src/commands/moderation/prefixCommands/prefixCommandPermissions.ts b/src/commands/moderation/prefixCommands/prefixCommandPermissions.ts index 62d2dd3e..a508b507 100644 --- a/src/commands/moderation/prefixCommands/prefixCommandPermissions.ts +++ b/src/commands/moderation/prefixCommands/prefixCommandPermissions.ts @@ -1,5 +1,12 @@ import { ApplicationCommandOptionChoiceData, ApplicationCommandOptionType, ApplicationCommandType } from 'discord.js'; -import { AutocompleteCallback, constantsConfig, getConn, PrefixCommand, slashCommand, slashCommandStructure } from '../../../lib'; +import { + AutocompleteCallback, + constantsConfig, + getConn, + PrefixCommand, + slashCommand, + slashCommandStructure, +} from '../../../lib'; import { handleAddPrefixCommandChannelPermission } from './functions/addChannelPermission'; import { handleAddPrefixCommandRolePermission } from './functions/addRolePermission'; import { handleRemovePrefixCommandChannelPermission } from './functions/removeChannelPermission'; @@ -8,235 +15,239 @@ import { handleSetPrefixCommandPermissionSettings } from './functions/setCommand import { handleShowPrefixCommandPermissions } from './functions/showCommandPermissions'; const data = slashCommandStructure({ - name: 'prefix-command-permissions', - description: 'Command to manage the permissions of prefix based commands.', - type: ApplicationCommandType.ChatInput, - default_member_permissions: constantsConfig.commandPermission.MANAGE_SERVER, //Overrides need to be added for admin and moderator roles - dm_permission: false, - options: [ + name: 'prefix-command-permissions', + description: 'Command to manage the permissions of prefix based commands.', + type: ApplicationCommandType.ChatInput, + default_member_permissions: constantsConfig.commandPermission.MANAGE_SERVER, //Overrides need to be added for admin and moderator roles + dm_permission: false, + options: [ + { + name: 'show', + description: 'Show the permissions of a prefix command.', + type: ApplicationCommandOptionType.Subcommand, + options: [ { - name: 'show', - description: 'Show the permissions of a prefix command.', - type: ApplicationCommandOptionType.Subcommand, - options: [ - { - name: 'command', - description: 'Provide the name of the prefix command.', - type: ApplicationCommandOptionType.String, - required: true, - autocomplete: true, - max_length: 32, - }, - ], + name: 'command', + description: 'Provide the name of the prefix command.', + type: ApplicationCommandOptionType.String, + required: true, + autocomplete: true, + max_length: 32, }, + ], + }, + { + name: 'settings', + description: 'Manage prefix command permission settings.', + type: ApplicationCommandOptionType.Subcommand, + options: [ { - name: 'settings', - description: 'Manage prefix command permission settings.', - type: ApplicationCommandOptionType.Subcommand, - options: [ - { - name: 'command', - description: 'Provide the name of the prefix command.', - type: ApplicationCommandOptionType.String, - required: true, - autocomplete: true, - max_length: 32, - }, - { - name: 'roles-blocklist', - description: 'Enable or disable the role blocklist.', - type: ApplicationCommandOptionType.Boolean, - required: false, - }, - { - name: 'channels-blocklist', - description: 'Enable or disable the channel blocklist.', - type: ApplicationCommandOptionType.Boolean, - required: false, - }, - { - name: 'quiet-errors', - description: 'Enable or disable quiet errors.', - type: ApplicationCommandOptionType.Boolean, - required: false, - }, - { - name: 'verbose-errors', - description: 'Enable or disable verbose errors.', - type: ApplicationCommandOptionType.Boolean, - required: false, - }, - ], + name: 'command', + description: 'Provide the name of the prefix command.', + type: ApplicationCommandOptionType.String, + required: true, + autocomplete: true, + max_length: 32, }, { - name: 'channels', - description: 'Manage prefix command channel permissions.', - type: ApplicationCommandOptionType.SubcommandGroup, - options: [ - { - name: 'add', - description: 'Add a channel permission for a prefix command.', - type: ApplicationCommandOptionType.Subcommand, - options: [ - { - name: 'command', - description: 'Provide the name of the prefix command.', - type: ApplicationCommandOptionType.String, - required: true, - autocomplete: true, - max_length: 32, - }, - { - name: 'channel', - description: 'Provide the channel to add or remove from the selected list.', - type: ApplicationCommandOptionType.Channel, - required: true, - }, - ], - }, - { - name: 'remove', - description: 'Remove a channel permission for a prefix command.', - type: ApplicationCommandOptionType.Subcommand, - options: [ - { - name: 'command', - description: 'Provide the name of the prefix command.', - type: ApplicationCommandOptionType.String, - required: true, - autocomplete: true, - max_length: 32, - }, - { - name: 'channel', - description: 'Provide the channel to add or remove from the selected list.', - type: ApplicationCommandOptionType.Channel, - required: true, - }, - ], - }, - ], + name: 'roles-blocklist', + description: 'Enable or disable the role blocklist.', + type: ApplicationCommandOptionType.Boolean, + required: false, }, { - name: 'roles', - description: 'Manage prefix command role permissions.', - type: ApplicationCommandOptionType.SubcommandGroup, - options: [ - { - name: 'add', - description: 'Add a role permission for a prefix command.', - type: ApplicationCommandOptionType.Subcommand, - options: [ - { - name: 'command', - description: 'Provide the name of the prefix command.', - type: ApplicationCommandOptionType.String, - required: true, - autocomplete: true, - max_length: 32, - }, - { - name: 'role', - description: 'Provide the role to add or remove from the selected list.', - type: ApplicationCommandOptionType.Role, - required: true, - }, - ], - }, - { - name: 'remove', - description: 'Remove a role permission for a prefix command.', - type: ApplicationCommandOptionType.Subcommand, - options: [ - { - name: 'command', - description: 'Provide the name of the prefix command.', - type: ApplicationCommandOptionType.String, - required: true, - autocomplete: true, - max_length: 32, - }, - { - name: 'role', - description: 'Provide the role to add or remove from the selected list.', - type: ApplicationCommandOptionType.Role, - required: true, - }, - ], - }, - ], + name: 'channels-blocklist', + description: 'Enable or disable the channel blocklist.', + type: ApplicationCommandOptionType.Boolean, + required: false, }, - ], + { + name: 'quiet-errors', + description: 'Enable or disable quiet errors.', + type: ApplicationCommandOptionType.Boolean, + required: false, + }, + { + name: 'verbose-errors', + description: 'Enable or disable verbose errors.', + type: ApplicationCommandOptionType.Boolean, + required: false, + }, + ], + }, + { + name: 'channels', + description: 'Manage prefix command channel permissions.', + type: ApplicationCommandOptionType.SubcommandGroup, + options: [ + { + name: 'add', + description: 'Add a channel permission for a prefix command.', + type: ApplicationCommandOptionType.Subcommand, + options: [ + { + name: 'command', + description: 'Provide the name of the prefix command.', + type: ApplicationCommandOptionType.String, + required: true, + autocomplete: true, + max_length: 32, + }, + { + name: 'channel', + description: 'Provide the channel to add or remove from the selected list.', + type: ApplicationCommandOptionType.Channel, + required: true, + }, + ], + }, + { + name: 'remove', + description: 'Remove a channel permission for a prefix command.', + type: ApplicationCommandOptionType.Subcommand, + options: [ + { + name: 'command', + description: 'Provide the name of the prefix command.', + type: ApplicationCommandOptionType.String, + required: true, + autocomplete: true, + max_length: 32, + }, + { + name: 'channel', + description: 'Provide the channel to add or remove from the selected list.', + type: ApplicationCommandOptionType.Channel, + required: true, + }, + ], + }, + ], + }, + { + name: 'roles', + description: 'Manage prefix command role permissions.', + type: ApplicationCommandOptionType.SubcommandGroup, + options: [ + { + name: 'add', + description: 'Add a role permission for a prefix command.', + type: ApplicationCommandOptionType.Subcommand, + options: [ + { + name: 'command', + description: 'Provide the name of the prefix command.', + type: ApplicationCommandOptionType.String, + required: true, + autocomplete: true, + max_length: 32, + }, + { + name: 'role', + description: 'Provide the role to add or remove from the selected list.', + type: ApplicationCommandOptionType.Role, + required: true, + }, + ], + }, + { + name: 'remove', + description: 'Remove a role permission for a prefix command.', + type: ApplicationCommandOptionType.Subcommand, + options: [ + { + name: 'command', + description: 'Provide the name of the prefix command.', + type: ApplicationCommandOptionType.String, + required: true, + autocomplete: true, + max_length: 32, + }, + { + name: 'role', + description: 'Provide the role to add or remove from the selected list.', + type: ApplicationCommandOptionType.Role, + required: true, + }, + ], + }, + ], + }, + ], }); const autocompleteCallback: AutocompleteCallback = async ({ interaction }) => { - const autoCompleteOption = interaction.options.getFocused(true); - const { name: optionName, value: searchText } = autoCompleteOption; - let choices: ApplicationCommandOptionChoiceData[] = []; + const autoCompleteOption = interaction.options.getFocused(true); + const { name: optionName, value: searchText } = autoCompleteOption; + let choices: ApplicationCommandOptionChoiceData[] = []; - const conn = getConn(); + const conn = getConn(); - switch (optionName) { + switch (optionName) { case 'command': - if (!conn) { - return interaction.respond(choices); - } - const foundCommands = await PrefixCommand.find({ name: { $regex: searchText, $options: 'i' } }) - .sort({ name: 1 }) - .limit(25); - for (let i = 0; i < foundCommands.length; i++) { - const command = foundCommands[i]; - const { name } = command; - choices.push({ name, value: name }); - } - break; + if (!conn) { + return interaction.respond(choices); + } + const foundCommands = await PrefixCommand.find({ name: { $regex: searchText, $options: 'i' } }) + .sort({ name: 1 }) + .limit(25); + for (let i = 0; i < foundCommands.length; i++) { + const command = foundCommands[i]; + const { name } = command; + choices.push({ name, value: name }); + } + break; default: - choices = []; - } + choices = []; + } - return interaction.respond(choices); + return interaction.respond(choices); }; -export default slashCommand(data, async ({ interaction }) => { +export default slashCommand( + data, + async ({ interaction }) => { const subcommandGroup = interaction.options.getSubcommandGroup(); const subcommandName = interaction.options.getSubcommand(); switch (subcommandName) { - case 'show': + case 'show': await handleShowPrefixCommandPermissions(interaction); return; - case 'settings': + case 'settings': await handleSetPrefixCommandPermissionSettings(interaction); return; - default: + default: } switch (subcommandGroup) { - case 'channels': + case 'channels': switch (subcommandName) { - case 'add': + case 'add': await handleAddPrefixCommandChannelPermission(interaction); break; - case 'remove': + case 'remove': await handleRemovePrefixCommandChannelPermission(interaction); break; - default: + default: await interaction.reply({ content: 'Unknown subcommand', ephemeral: true }); } break; - case 'roles': + case 'roles': switch (subcommandName) { - case 'add': + case 'add': await handleAddPrefixCommandRolePermission(interaction); break; - case 'remove': + case 'remove': await handleRemovePrefixCommandRolePermission(interaction); break; - default: + default: await interaction.reply({ content: 'Unknown subcommand', ephemeral: true }); } break; - default: + default: await interaction.reply({ content: 'Unknown subcommand', ephemeral: true }); } -}, autocompleteCallback); + }, + autocompleteCallback, +); diff --git a/src/commands/moderation/prefixCommands/prefixCommands.ts b/src/commands/moderation/prefixCommands/prefixCommands.ts index 6662056d..ff1f616b 100644 --- a/src/commands/moderation/prefixCommands/prefixCommands.ts +++ b/src/commands/moderation/prefixCommands/prefixCommands.ts @@ -1,5 +1,14 @@ import { ApplicationCommandOptionChoiceData, ApplicationCommandOptionType, ApplicationCommandType } from 'discord.js'; -import { AutocompleteCallback, constantsConfig, getConn, PrefixCommand, PrefixCommandCategory, PrefixCommandVersion, slashCommand, slashCommandStructure } from '../../../lib'; +import { + AutocompleteCallback, + constantsConfig, + getConn, + PrefixCommand, + PrefixCommandCategory, + PrefixCommandVersion, + slashCommand, + slashCommandStructure, +} from '../../../lib'; import { handleAddPrefixCommandCategory } from './functions/addCategory'; import { handleModifyPrefixCommandCategory } from './functions/modifyCategory'; import { handleDeletePrefixCommandCategory } from './functions/deleteCategory'; @@ -21,645 +30,649 @@ import { handleDeletePrefixCommandChannelDefaultVersion } from './functions/dele const colorChoices = []; for (let i = 0; i < Object.keys(constantsConfig.colors).length; i++) { - const name = Object.keys(constantsConfig.colors)[i]; - const value = constantsConfig.colors[name]; - colorChoices.push({ name, value }); + const name = Object.keys(constantsConfig.colors)[i]; + const value = constantsConfig.colors[name]; + colorChoices.push({ name, value }); } const data = slashCommandStructure({ - name: 'prefix-commands', - description: 'Command to manage prefix based commands.', - type: ApplicationCommandType.ChatInput, - default_member_permissions: constantsConfig.commandPermission.MANAGE_SERVER, //Overrides need to be added for admin and moderator roles - dm_permission: false, - options: [ + name: 'prefix-commands', + description: 'Command to manage prefix based commands.', + type: ApplicationCommandType.ChatInput, + default_member_permissions: constantsConfig.commandPermission.MANAGE_SERVER, //Overrides need to be added for admin and moderator roles + dm_permission: false, + options: [ + { + name: 'categories', + description: 'Manage prefix command categories.', + type: ApplicationCommandOptionType.SubcommandGroup, + options: [ { - name: 'categories', - description: 'Manage prefix command categories.', - type: ApplicationCommandOptionType.SubcommandGroup, - options: [ - { - name: 'add', - description: 'Add a prefix command category.', - type: ApplicationCommandOptionType.Subcommand, - options: [ - { - name: 'name', - description: 'Provide a name for the prefix command category.', - type: ApplicationCommandOptionType.String, - required: true, - autocomplete: true, - max_length: 32, - }, - { - name: 'emoji', - description: 'Provide an emoji to identify the prefix command category.', - type: ApplicationCommandOptionType.String, - required: false, - max_length: 128, - }, - ], - }, - { - name: 'modify', - description: 'Modify a prefix command category.', - type: ApplicationCommandOptionType.Subcommand, - options: [ - { - name: 'category', - description: 'Provide the category name of the prefix command category.', - type: ApplicationCommandOptionType.String, - required: true, - autocomplete: true, - max_length: 32, - }, - { - name: 'name', - description: 'Provide a name for the prefix command category.', - type: ApplicationCommandOptionType.String, - required: false, - max_length: 32, - }, - { - name: 'emoji', - description: 'Provide an emoji to identify the prefix command category.', - type: ApplicationCommandOptionType.String, - required: false, - max_length: 128, - }, - ], - }, - { - name: 'delete', - description: 'Delete a prefix command category.', - type: ApplicationCommandOptionType.Subcommand, - options: [ - { - name: 'category', - description: 'Provide the category name of the prefix command category.', - type: ApplicationCommandOptionType.String, - required: true, - autocomplete: true, - max_length: 32, - }, - ], - }, - { - name: 'list', - description: 'Get list of prefix command categories.', - type: ApplicationCommandOptionType.Subcommand, - options: [ - { - name: 'search_text', - description: 'Provide an optional search term.', - type: ApplicationCommandOptionType.String, - required: false, - max_length: 32, - }, - ], - }, - ], + name: 'add', + description: 'Add a prefix command category.', + type: ApplicationCommandOptionType.Subcommand, + options: [ + { + name: 'name', + description: 'Provide a name for the prefix command category.', + type: ApplicationCommandOptionType.String, + required: true, + autocomplete: true, + max_length: 32, + }, + { + name: 'emoji', + description: 'Provide an emoji to identify the prefix command category.', + type: ApplicationCommandOptionType.String, + required: false, + max_length: 128, + }, + ], }, { - name: 'versions', - description: 'Manage prefix command versions.', - type: ApplicationCommandOptionType.SubcommandGroup, - options: [ - { - name: 'add', - description: 'Add a prefix command version.', - type: ApplicationCommandOptionType.Subcommand, - options: [ - { - name: 'name', - description: 'Provide a name for the prefix command version.', - type: ApplicationCommandOptionType.String, - required: true, - max_length: 32, - }, - { - name: 'emoji', - description: 'Provide an emoji to identify the prefix command version.', - type: ApplicationCommandOptionType.String, - required: true, - max_length: 128, - }, - { - name: 'alias', - description: 'Provide an alias for the prefix command version.', - type: ApplicationCommandOptionType.String, - required: true, - max_length: 32, - }, - { - name: 'is_enabled', - description: 'Indicate wether this version is enabled.', - type: ApplicationCommandOptionType.Boolean, - required: false, - }, - ], - }, - { - name: 'modify', - description: 'Modify a prefix command version.', - type: ApplicationCommandOptionType.Subcommand, - options: [ - { - name: 'version', - description: 'Provide the name of the prefix command version.', - type: ApplicationCommandOptionType.String, - required: true, - autocomplete: true, - max_length: 32, - }, - { - name: 'name', - description: 'Provide a name for the prefix command version.', - type: ApplicationCommandOptionType.String, - required: false, - max_length: 32, - }, - { - name: 'emoji', - description: 'Provide an emoji to identify the prefix command version.', - type: ApplicationCommandOptionType.String, - required: false, - max_length: 128, - }, - { - name: 'alias', - description: 'Provide an alias for the prefix command version.', - type: ApplicationCommandOptionType.String, - required: false, - max_length: 32, - }, - { - name: 'is_enabled', - description: 'Indicate wether this version is enabled.', - type: ApplicationCommandOptionType.Boolean, - required: false, - }, - ], - }, - { - name: 'delete', - description: 'Delete a prefix command version.', - type: ApplicationCommandOptionType.Subcommand, - options: [ - { - name: 'version', - description: 'Provide the name of the prefix command version.', - type: ApplicationCommandOptionType.String, - required: true, - autocomplete: true, - max_length: 32, - }, - { - name: 'force', - description: 'Force delete the version even if it is used for command content.', - type: ApplicationCommandOptionType.Boolean, - required: false, - }, - ], - }, - { - name: 'list', - description: 'Get list of prefix command versions.', - type: ApplicationCommandOptionType.Subcommand, - options: [ - { - name: 'search_text', - description: 'Provide an optional search term.', - type: ApplicationCommandOptionType.String, - required: false, - max_length: 32, - }, - ], - }, - ], + name: 'modify', + description: 'Modify a prefix command category.', + type: ApplicationCommandOptionType.Subcommand, + options: [ + { + name: 'category', + description: 'Provide the category name of the prefix command category.', + type: ApplicationCommandOptionType.String, + required: true, + autocomplete: true, + max_length: 32, + }, + { + name: 'name', + description: 'Provide a name for the prefix command category.', + type: ApplicationCommandOptionType.String, + required: false, + max_length: 32, + }, + { + name: 'emoji', + description: 'Provide an emoji to identify the prefix command category.', + type: ApplicationCommandOptionType.String, + required: false, + max_length: 128, + }, + ], }, { - name: 'commands', - description: 'Manage prefix commands.', - type: ApplicationCommandOptionType.SubcommandGroup, - options: [ - { - name: 'add', - description: 'Add a prefix command.', - type: ApplicationCommandOptionType.Subcommand, - options: [ - { - name: 'name', - description: 'Provide a name for the prefix command.', - type: ApplicationCommandOptionType.String, - required: true, - max_length: 32, - }, - { - name: 'category', - description: 'Provide the category for the prefix command.', - type: ApplicationCommandOptionType.String, - required: true, - autocomplete: true, - max_length: 32, - }, - { - name: 'description', - description: 'Provide a description for the prefix command.', - type: ApplicationCommandOptionType.String, - required: true, - max_length: 255, - }, - { - name: 'aliases', - description: 'Provide a comma separated list of aliases for the prefix command.', - type: ApplicationCommandOptionType.String, - required: false, - max_length: 255, - }, - { - name: 'is_embed', - description: 'Indicate wether this prefix command should print as an embed or regular message.', - type: ApplicationCommandOptionType.Boolean, - required: false, - }, - { - name: 'embed_color', - description: 'If this command results in an embed, specify the color.', - type: ApplicationCommandOptionType.String, - required: false, - max_length: 16, - choices: colorChoices, - }, - ], - }, - { - name: 'modify', - description: 'Modify a prefix command.', - type: ApplicationCommandOptionType.Subcommand, - options: [ - { - name: 'command', - description: 'Provide the command name of the prefix command.', - type: ApplicationCommandOptionType.String, - required: true, - autocomplete: true, - max_length: 24, - }, - { - name: 'name', - description: 'Provide a name for the prefix command.', - type: ApplicationCommandOptionType.String, - required: false, - max_length: 32, - }, - { - name: 'category', - description: 'Provide the category for the prefix command.', - type: ApplicationCommandOptionType.String, - required: false, - autocomplete: true, - max_length: 32, - }, - { - name: 'description', - description: 'Provide a description for the prefix command.', - type: ApplicationCommandOptionType.String, - required: false, - max_length: 255, - }, - { - name: 'aliases', - description: 'Provide a comma separated list of aliases for the prefix command.', - type: ApplicationCommandOptionType.String, - required: false, - max_length: 255, - }, - { - name: 'is_embed', - description: 'Indicate wether this prefix command should print as an embed or regular message.', - type: ApplicationCommandOptionType.Boolean, - required: false, - }, - { - name: 'embed_color', - description: 'If this command results in an embed, specify the color.', - type: ApplicationCommandOptionType.String, - required: false, - max_length: 16, - choices: colorChoices, - }, - ], - }, - { - name: 'delete', - description: 'Delete a prefix command.', - type: ApplicationCommandOptionType.Subcommand, - options: [ - { - name: 'command', - description: 'Provide the command name of the prefix command.', - type: ApplicationCommandOptionType.String, - required: true, - autocomplete: true, - max_length: 24, - }, - ], - }, - { - name: 'list', - description: 'Get list of prefix commands.', - type: ApplicationCommandOptionType.Subcommand, - options: [ - { - name: 'search_text', - description: 'Provide an optional search term.', - type: ApplicationCommandOptionType.String, - required: false, - max_length: 32, - }, - ], - }, - ], + name: 'delete', + description: 'Delete a prefix command category.', + type: ApplicationCommandOptionType.Subcommand, + options: [ + { + name: 'category', + description: 'Provide the category name of the prefix command category.', + type: ApplicationCommandOptionType.String, + required: true, + autocomplete: true, + max_length: 32, + }, + ], }, { - name: 'content', - description: 'Manage prefix command content.', - type: ApplicationCommandOptionType.SubcommandGroup, - options: [ - { - name: 'show', - description: 'Show the details of the content of a command.', - type: ApplicationCommandOptionType.Subcommand, - options: [ - { - name: 'command', - description: 'Provide the name of the prefix command.', - type: ApplicationCommandOptionType.String, - required: true, - autocomplete: true, - max_length: 32, - }, - { - name: 'version', - description: 'Provide the name of the prefix command version. Use GENERIC for the generic content.', - type: ApplicationCommandOptionType.String, - required: true, - autocomplete: true, - max_length: 32, - }, - ], - }, - { - name: 'set', - description: 'Set a prefix command\'s content for a specific version.', - type: ApplicationCommandOptionType.Subcommand, - options: [ - { - name: 'command', - description: 'Provide the name of the prefix command.', - type: ApplicationCommandOptionType.String, - required: true, - autocomplete: true, - max_length: 32, - }, - { - name: 'version', - description: 'Provide the name of the prefix command version. Use GENERIC for the generic content.', - type: ApplicationCommandOptionType.String, - required: true, - autocomplete: true, - max_length: 32, - }, - ], - }, - { - name: 'delete', - description: 'Delete a prefix command\'s content for a specific version.', - type: ApplicationCommandOptionType.Subcommand, - options: [ - { - name: 'command', - description: 'Provide the name of the prefix command.', - type: ApplicationCommandOptionType.String, - required: true, - autocomplete: true, - max_length: 32, - }, - { - name: 'version', - description: 'Provide the name of the prefix command version. Use GENERIC for the generic content.', - type: ApplicationCommandOptionType.String, - required: true, - autocomplete: true, - max_length: 32, - }, - ], - }, - ], + name: 'list', + description: 'Get list of prefix command categories.', + type: ApplicationCommandOptionType.Subcommand, + options: [ + { + name: 'search_text', + description: 'Provide an optional search term.', + type: ApplicationCommandOptionType.String, + required: false, + max_length: 32, + }, + ], }, + ], + }, + { + name: 'versions', + description: 'Manage prefix command versions.', + type: ApplicationCommandOptionType.SubcommandGroup, + options: [ { - name: 'channel-default-version', - description: 'Manage prefix command default versions for channels.', - type: ApplicationCommandOptionType.SubcommandGroup, - options: [ - { - name: 'show', - description: 'Show the default version for a channel.', - type: ApplicationCommandOptionType.Subcommand, - options: [ - { - name: 'channel', - description: 'Provide the channel to show the default version for.', - type: ApplicationCommandOptionType.Channel, - required: true, - }, - ], - }, - { - name: 'set', - description: 'Set the default version for a channel.', - type: ApplicationCommandOptionType.Subcommand, - options: [ - { - name: 'channel', - description: 'Provide the channel to set the default version for.', - type: ApplicationCommandOptionType.Channel, - required: true, - }, - { - name: 'version', - description: 'Provide the version to set as default.', - type: ApplicationCommandOptionType.String, - required: true, - autocomplete: true, - max_length: 32, - }, - ], - }, - { - name: 'delete', - description: 'Delete the default version for a channel.', - type: ApplicationCommandOptionType.Subcommand, - options: [ - { - name: 'channel', - description: 'Provide the channel to unset the default version for.', - type: ApplicationCommandOptionType.Channel, - required: true, - }, - ], - }, - ], + name: 'add', + description: 'Add a prefix command version.', + type: ApplicationCommandOptionType.Subcommand, + options: [ + { + name: 'name', + description: 'Provide a name for the prefix command version.', + type: ApplicationCommandOptionType.String, + required: true, + max_length: 32, + }, + { + name: 'emoji', + description: 'Provide an emoji to identify the prefix command version.', + type: ApplicationCommandOptionType.String, + required: true, + max_length: 128, + }, + { + name: 'alias', + description: 'Provide an alias for the prefix command version.', + type: ApplicationCommandOptionType.String, + required: true, + max_length: 32, + }, + { + name: 'is_enabled', + description: 'Indicate wether this version is enabled.', + type: ApplicationCommandOptionType.Boolean, + required: false, + }, + ], }, - ], + { + name: 'modify', + description: 'Modify a prefix command version.', + type: ApplicationCommandOptionType.Subcommand, + options: [ + { + name: 'version', + description: 'Provide the name of the prefix command version.', + type: ApplicationCommandOptionType.String, + required: true, + autocomplete: true, + max_length: 32, + }, + { + name: 'name', + description: 'Provide a name for the prefix command version.', + type: ApplicationCommandOptionType.String, + required: false, + max_length: 32, + }, + { + name: 'emoji', + description: 'Provide an emoji to identify the prefix command version.', + type: ApplicationCommandOptionType.String, + required: false, + max_length: 128, + }, + { + name: 'alias', + description: 'Provide an alias for the prefix command version.', + type: ApplicationCommandOptionType.String, + required: false, + max_length: 32, + }, + { + name: 'is_enabled', + description: 'Indicate wether this version is enabled.', + type: ApplicationCommandOptionType.Boolean, + required: false, + }, + ], + }, + { + name: 'delete', + description: 'Delete a prefix command version.', + type: ApplicationCommandOptionType.Subcommand, + options: [ + { + name: 'version', + description: 'Provide the name of the prefix command version.', + type: ApplicationCommandOptionType.String, + required: true, + autocomplete: true, + max_length: 32, + }, + { + name: 'force', + description: 'Force delete the version even if it is used for command content.', + type: ApplicationCommandOptionType.Boolean, + required: false, + }, + ], + }, + { + name: 'list', + description: 'Get list of prefix command versions.', + type: ApplicationCommandOptionType.Subcommand, + options: [ + { + name: 'search_text', + description: 'Provide an optional search term.', + type: ApplicationCommandOptionType.String, + required: false, + max_length: 32, + }, + ], + }, + ], + }, + { + name: 'commands', + description: 'Manage prefix commands.', + type: ApplicationCommandOptionType.SubcommandGroup, + options: [ + { + name: 'add', + description: 'Add a prefix command.', + type: ApplicationCommandOptionType.Subcommand, + options: [ + { + name: 'name', + description: 'Provide a name for the prefix command.', + type: ApplicationCommandOptionType.String, + required: true, + max_length: 32, + }, + { + name: 'category', + description: 'Provide the category for the prefix command.', + type: ApplicationCommandOptionType.String, + required: true, + autocomplete: true, + max_length: 32, + }, + { + name: 'description', + description: 'Provide a description for the prefix command.', + type: ApplicationCommandOptionType.String, + required: true, + max_length: 255, + }, + { + name: 'aliases', + description: 'Provide a comma separated list of aliases for the prefix command.', + type: ApplicationCommandOptionType.String, + required: false, + max_length: 255, + }, + { + name: 'is_embed', + description: 'Indicate wether this prefix command should print as an embed or regular message.', + type: ApplicationCommandOptionType.Boolean, + required: false, + }, + { + name: 'embed_color', + description: 'If this command results in an embed, specify the color.', + type: ApplicationCommandOptionType.String, + required: false, + max_length: 16, + choices: colorChoices, + }, + ], + }, + { + name: 'modify', + description: 'Modify a prefix command.', + type: ApplicationCommandOptionType.Subcommand, + options: [ + { + name: 'command', + description: 'Provide the command name of the prefix command.', + type: ApplicationCommandOptionType.String, + required: true, + autocomplete: true, + max_length: 24, + }, + { + name: 'name', + description: 'Provide a name for the prefix command.', + type: ApplicationCommandOptionType.String, + required: false, + max_length: 32, + }, + { + name: 'category', + description: 'Provide the category for the prefix command.', + type: ApplicationCommandOptionType.String, + required: false, + autocomplete: true, + max_length: 32, + }, + { + name: 'description', + description: 'Provide a description for the prefix command.', + type: ApplicationCommandOptionType.String, + required: false, + max_length: 255, + }, + { + name: 'aliases', + description: 'Provide a comma separated list of aliases for the prefix command.', + type: ApplicationCommandOptionType.String, + required: false, + max_length: 255, + }, + { + name: 'is_embed', + description: 'Indicate wether this prefix command should print as an embed or regular message.', + type: ApplicationCommandOptionType.Boolean, + required: false, + }, + { + name: 'embed_color', + description: 'If this command results in an embed, specify the color.', + type: ApplicationCommandOptionType.String, + required: false, + max_length: 16, + choices: colorChoices, + }, + ], + }, + { + name: 'delete', + description: 'Delete a prefix command.', + type: ApplicationCommandOptionType.Subcommand, + options: [ + { + name: 'command', + description: 'Provide the command name of the prefix command.', + type: ApplicationCommandOptionType.String, + required: true, + autocomplete: true, + max_length: 24, + }, + ], + }, + { + name: 'list', + description: 'Get list of prefix commands.', + type: ApplicationCommandOptionType.Subcommand, + options: [ + { + name: 'search_text', + description: 'Provide an optional search term.', + type: ApplicationCommandOptionType.String, + required: false, + max_length: 32, + }, + ], + }, + ], + }, + { + name: 'content', + description: 'Manage prefix command content.', + type: ApplicationCommandOptionType.SubcommandGroup, + options: [ + { + name: 'show', + description: 'Show the details of the content of a command.', + type: ApplicationCommandOptionType.Subcommand, + options: [ + { + name: 'command', + description: 'Provide the name of the prefix command.', + type: ApplicationCommandOptionType.String, + required: true, + autocomplete: true, + max_length: 32, + }, + { + name: 'version', + description: 'Provide the name of the prefix command version. Use GENERIC for the generic content.', + type: ApplicationCommandOptionType.String, + required: true, + autocomplete: true, + max_length: 32, + }, + ], + }, + { + name: 'set', + description: "Set a prefix command's content for a specific version.", + type: ApplicationCommandOptionType.Subcommand, + options: [ + { + name: 'command', + description: 'Provide the name of the prefix command.', + type: ApplicationCommandOptionType.String, + required: true, + autocomplete: true, + max_length: 32, + }, + { + name: 'version', + description: 'Provide the name of the prefix command version. Use GENERIC for the generic content.', + type: ApplicationCommandOptionType.String, + required: true, + autocomplete: true, + max_length: 32, + }, + ], + }, + { + name: 'delete', + description: "Delete a prefix command's content for a specific version.", + type: ApplicationCommandOptionType.Subcommand, + options: [ + { + name: 'command', + description: 'Provide the name of the prefix command.', + type: ApplicationCommandOptionType.String, + required: true, + autocomplete: true, + max_length: 32, + }, + { + name: 'version', + description: 'Provide the name of the prefix command version. Use GENERIC for the generic content.', + type: ApplicationCommandOptionType.String, + required: true, + autocomplete: true, + max_length: 32, + }, + ], + }, + ], + }, + { + name: 'channel-default-version', + description: 'Manage prefix command default versions for channels.', + type: ApplicationCommandOptionType.SubcommandGroup, + options: [ + { + name: 'show', + description: 'Show the default version for a channel.', + type: ApplicationCommandOptionType.Subcommand, + options: [ + { + name: 'channel', + description: 'Provide the channel to show the default version for.', + type: ApplicationCommandOptionType.Channel, + required: true, + }, + ], + }, + { + name: 'set', + description: 'Set the default version for a channel.', + type: ApplicationCommandOptionType.Subcommand, + options: [ + { + name: 'channel', + description: 'Provide the channel to set the default version for.', + type: ApplicationCommandOptionType.Channel, + required: true, + }, + { + name: 'version', + description: 'Provide the version to set as default.', + type: ApplicationCommandOptionType.String, + required: true, + autocomplete: true, + max_length: 32, + }, + ], + }, + { + name: 'delete', + description: 'Delete the default version for a channel.', + type: ApplicationCommandOptionType.Subcommand, + options: [ + { + name: 'channel', + description: 'Provide the channel to unset the default version for.', + type: ApplicationCommandOptionType.Channel, + required: true, + }, + ], + }, + ], + }, + ], }); const autocompleteCallback: AutocompleteCallback = async ({ interaction }) => { - const autoCompleteOption = interaction.options.getFocused(true); - const { name: optionName, value: searchText } = autoCompleteOption; - const choices: ApplicationCommandOptionChoiceData[] = []; + const autoCompleteOption = interaction.options.getFocused(true); + const { name: optionName, value: searchText } = autoCompleteOption; + const choices: ApplicationCommandOptionChoiceData[] = []; - const conn = getConn(); + const conn = getConn(); - switch (optionName) { + switch (optionName) { case 'category': - if (!conn) { - return interaction.respond(choices); - } - const foundCategories = await PrefixCommandCategory.find({ name: { $regex: searchText, $options: 'i' } }) - .sort({ name: 1 }) - .limit(25); - for (let i = 0; i < foundCategories.length; i++) { - const category = foundCategories[i]; - const { name } = category; - choices.push({ name, value: name }); - } - break; + if (!conn) { + return interaction.respond(choices); + } + const foundCategories = await PrefixCommandCategory.find({ name: { $regex: searchText, $options: 'i' } }) + .sort({ name: 1 }) + .limit(25); + for (let i = 0; i < foundCategories.length; i++) { + const category = foundCategories[i]; + const { name } = category; + choices.push({ name, value: name }); + } + break; case 'command': - if (!conn) { - return interaction.respond(choices); - } - const foundCommands = await PrefixCommand.find({ name: { $regex: searchText, $options: 'i' } }) - .sort({ name: 1 }) - .limit(25); - for (let i = 0; i < foundCommands.length; i++) { - const command = foundCommands[i]; - const { name } = command; - choices.push({ name, value: name }); - } - break; + if (!conn) { + return interaction.respond(choices); + } + const foundCommands = await PrefixCommand.find({ name: { $regex: searchText, $options: 'i' } }) + .sort({ name: 1 }) + .limit(25); + for (let i = 0; i < foundCommands.length; i++) { + const command = foundCommands[i]; + const { name } = command; + choices.push({ name, value: name }); + } + break; case 'version': - choices.push({ name: 'GENERIC', value: 'GENERIC' }); - if (!conn) { - return interaction.respond(choices); - } - const foundVersions = await PrefixCommandVersion.find({ name: { $regex: searchText, $options: 'i' } }) - .sort({ name: 1 }) - .limit(25); - for (let i = 0; i < foundVersions.length; i++) { - const version = foundVersions[i]; - const { name } = version; - choices.push({ name, value: name }); - } - break; + choices.push({ name: 'GENERIC', value: 'GENERIC' }); + if (!conn) { + return interaction.respond(choices); + } + const foundVersions = await PrefixCommandVersion.find({ name: { $regex: searchText, $options: 'i' } }) + .sort({ name: 1 }) + .limit(25); + for (let i = 0; i < foundVersions.length; i++) { + const version = foundVersions[i]; + const { name } = version; + choices.push({ name, value: name }); + } + break; default: - break; - } + break; + } - return interaction.respond(choices); + return interaction.respond(choices); }; -export default slashCommand(data, async ({ interaction }) => { +export default slashCommand( + data, + async ({ interaction }) => { const subcommandGroup = interaction.options.getSubcommandGroup(); const subcommandName = interaction.options.getSubcommand(); switch (subcommandGroup) { - case 'categories': + case 'categories': switch (subcommandName) { - case 'add': + case 'add': await handleAddPrefixCommandCategory(interaction); break; - case 'modify': + case 'modify': await handleModifyPrefixCommandCategory(interaction); break; - case 'delete': + case 'delete': await handleDeletePrefixCommandCategory(interaction); break; - case 'list': + case 'list': await handleListPrefixCommandCategories(interaction); break; - default: + default: await interaction.reply({ content: 'Unknown subcommand', ephemeral: true }); } break; - case 'versions': + case 'versions': switch (subcommandName) { - case 'add': + case 'add': await handleAddPrefixCommandVersion(interaction); break; - case 'modify': + case 'modify': await handleModifyPrefixCommandVersion(interaction); break; - case 'delete': + case 'delete': await handleDeletePrefixCommandVersion(interaction); break; - case 'list': + case 'list': await handleListPrefixCommandVersions(interaction); break; - default: + default: await interaction.reply({ content: 'Unknown subcommand', ephemeral: true }); } break; - case 'commands': + case 'commands': switch (subcommandName) { - case 'add': + case 'add': await handleAddPrefixCommand(interaction); break; - case 'modify': + case 'modify': await handleModifyPrefixCommand(interaction); break; - case 'delete': + case 'delete': await handleDeletePrefixCommand(interaction); break; - case 'list': + case 'list': await handleListPrefixCommands(interaction); break; - default: + default: await interaction.reply({ content: 'Unknown subcommand', ephemeral: true }); } break; - case 'content': + case 'content': switch (subcommandName) { - case 'show': + case 'show': await handleShowPrefixCommandContent(interaction); break; - case 'set': + case 'set': await handleSetPrefixCommandContent(interaction); break; - case 'delete': + case 'delete': await handleDeletePrefixCommandContent(interaction); break; - default: + default: await interaction.reply({ content: 'Unknown subcommand', ephemeral: true }); } break; - case 'channel-default-version': + case 'channel-default-version': switch (subcommandName) { - case 'show': + case 'show': await handleShowPrefixCommandChannelDefaultVersion(interaction); break; - case 'set': + case 'set': await handleSetPrefixCommandChannelDefaultVersion(interaction); break; - case 'delete': + case 'delete': await handleDeletePrefixCommandChannelDefaultVersion(interaction); break; - default: + default: await interaction.reply({ content: 'Unknown subcommand', ephemeral: true }); } break; - default: + default: await interaction.reply({ content: 'Unknown subcommand', ephemeral: true }); } -}, autocompleteCallback); + }, + autocompleteCallback, +); diff --git a/src/commands/utils/prefixHelp.ts b/src/commands/utils/prefixHelp.ts index 76968c5a..3c4d169c 100644 --- a/src/commands/utils/prefixHelp.ts +++ b/src/commands/utils/prefixHelp.ts @@ -1,78 +1,96 @@ import { ApplicationCommandOptionChoiceData, ApplicationCommandOptionType, ApplicationCommandType } from 'discord.js'; -import { makeEmbed, createPaginatedEmbedHandler, slashCommand, slashCommandStructure, getInMemoryCache, MemoryCachePrefix, AutocompleteCallback, makeLines, Logger, PrefixCommand, PrefixCommandVersion, PrefixCommandCategory, IPrefixCommand } from '../../lib'; +import { + makeEmbed, + createPaginatedEmbedHandler, + slashCommand, + slashCommandStructure, + getInMemoryCache, + MemoryCachePrefix, + AutocompleteCallback, + makeLines, + Logger, + PrefixCommand, + PrefixCommandVersion, + PrefixCommandCategory, + IPrefixCommand, +} from '../../lib'; const data = slashCommandStructure({ - name: 'prefix-help', - description: 'Display a list of all the prefix commands matching an optional search.', - type: ApplicationCommandType.ChatInput, - options: [{ - name: 'category', - description: 'The category to show the prefix commands for.', - type: ApplicationCommandOptionType.String, - max_length: 32, - autocomplete: true, - required: true, + name: 'prefix-help', + description: 'Display a list of all the prefix commands matching an optional search.', + type: ApplicationCommandType.ChatInput, + options: [ + { + name: 'category', + description: 'The category to show the prefix commands for.', + type: ApplicationCommandOptionType.String, + max_length: 32, + autocomplete: true, + required: true, }, { - name: 'search', - description: 'The search term to filter the prefix commands by.', - type: ApplicationCommandOptionType.String, - max_length: 32, - autocomplete: true, - required: false, - }], + name: 'search', + description: 'The search term to filter the prefix commands by.', + type: ApplicationCommandOptionType.String, + max_length: 32, + autocomplete: true, + required: false, + }, + ], }); const autocompleteCallback: AutocompleteCallback = async ({ interaction }) => { - const autoCompleteOption = interaction.options.getFocused(true); - const { name: optionName, value: searchText } = autoCompleteOption; - const choices: ApplicationCommandOptionChoiceData[] = []; + const autoCompleteOption = interaction.options.getFocused(true); + const { name: optionName, value: searchText } = autoCompleteOption; + const choices: ApplicationCommandOptionChoiceData[] = []; - const inMemoryCache = getInMemoryCache(); + const inMemoryCache = getInMemoryCache(); - switch (optionName) { + switch (optionName) { case 'category': - if (inMemoryCache) { - const foundCategories = await inMemoryCache.store.keys(); - for (const key of foundCategories) { - if (key.startsWith(MemoryCachePrefix.CATEGORY) && key.includes(searchText.toLowerCase())) { - // eslint-disable-next-line no-await-in-loop - const categoryCached = await inMemoryCache.get(key); - if (categoryCached) { - const category = PrefixCommandCategory.hydrate(categoryCached); - const { name } = category; - choices.push({ name, value: name }); - if (choices.length >= 25) { - break; - } - } - } + if (inMemoryCache) { + const foundCategories = await inMemoryCache.store.keys(); + for (const key of foundCategories) { + if (key.startsWith(MemoryCachePrefix.CATEGORY) && key.includes(searchText.toLowerCase())) { + // eslint-disable-next-line no-await-in-loop + const categoryCached = await inMemoryCache.get(key); + if (categoryCached) { + const category = PrefixCommandCategory.hydrate(categoryCached); + const { name } = category; + choices.push({ name, value: name }); + if (choices.length >= 25) { + break; + } } + } } - break; + } + break; case 'search': - if (inMemoryCache) { - const foundCommands = await inMemoryCache.store.keys(); - for (const key of foundCommands) { - if (key.startsWith(MemoryCachePrefix.COMMAND) && key.includes(searchText.toLowerCase())) { - // Explicitly does not use the cache to hydrate the command to also capture aliases, resulting in commands - const commandName = key.split(':')[1]; - choices.push({ name: commandName, value: commandName }); - if (choices.length >= 25) { - break; - } - } + if (inMemoryCache) { + const foundCommands = await inMemoryCache.store.keys(); + for (const key of foundCommands) { + if (key.startsWith(MemoryCachePrefix.COMMAND) && key.includes(searchText.toLowerCase())) { + // Explicitly does not use the cache to hydrate the command to also capture aliases, resulting in commands + const commandName = key.split(':')[1]; + choices.push({ name: commandName, value: commandName }); + if (choices.length >= 25) { + break; } + } } - break; + } + break; default: - break; - } + break; + } - return interaction.respond(choices); + return interaction.respond(choices); }; -export default slashCommand(data, async ({ interaction }) => { +export default slashCommand( + data, + async ({ interaction }) => { await interaction.deferReply({ ephemeral: true }); const categoryName = interaction.options.getString('category')!; @@ -80,36 +98,36 @@ export default slashCommand(data, async ({ interaction }) => { const inMemoryCache = getInMemoryCache(); if (!inMemoryCache) { - return interaction.reply({ - content: 'An error occurred while fetching commands.', - ephemeral: true, - }); + return interaction.reply({ + content: 'An error occurred while fetching commands.', + ephemeral: true, + }); } const categoryCached = await inMemoryCache.get(`${MemoryCachePrefix.CATEGORY}:${categoryName.toLowerCase()}`); if (!categoryCached) { - return interaction.reply({ - content: 'Invalid category, please select an existing category.', - ephemeral: true, - }); + return interaction.reply({ + content: 'Invalid category, please select an existing category.', + ephemeral: true, + }); } const category = PrefixCommandCategory.hydrate(categoryCached); const commands: { [key: string]: IPrefixCommand } = {}; const keys = await inMemoryCache.store.keys(); for (const key of keys) { - if (key.startsWith(MemoryCachePrefix.COMMAND) && key.includes(search.toLowerCase())) { - // eslint-disable-next-line no-await-in-loop - const commandCached = await inMemoryCache.get(key); - if (commandCached) { - const command = PrefixCommand.hydrate(commandCached); - const { name, categoryId: commandCategoryId } = command; - const { _id: categoryId } = category; - if (commandCategoryId.toString() === categoryId.toString() && !(name in commands)) { - commands[name] = command; - } - } + if (key.startsWith(MemoryCachePrefix.COMMAND) && key.includes(search.toLowerCase())) { + // eslint-disable-next-line no-await-in-loop + const commandCached = await inMemoryCache.get(key); + if (commandCached) { + const command = PrefixCommand.hydrate(commandCached); + const { name, categoryId: commandCategoryId } = command; + const { _id: categoryId } = category; + if (commandCategoryId.toString() === categoryId.toString() && !(name in commands)) { + commands[name] = command; + } } + } } const sortedCommands = Object.values(commands).sort((a, b) => a.name.localeCompare(b.name)); @@ -117,44 +135,46 @@ export default slashCommand(data, async ({ interaction }) => { const pageLimit = 10; const embeds = []; for (let page = 0; page * pageLimit < sortedCommands.length; page++) { - const startIndex = page * pageLimit; - const endIndex = startIndex + pageLimit; - const currentCommands = sortedCommands.slice(startIndex, endIndex); - const totalPages = Math.ceil(sortedCommands.length / pageLimit); - - const descriptionLines: string[] = []; - for (const command of currentCommands) { - const { name, aliases, description, contents } = command; - const versionEmojis = []; - for (const content of contents) { - const { versionId } = content; - if (versionId !== 'GENERIC') { - Logger.debug(`Fetching version ${versionId} for command ${name}`); - // eslint-disable-next-line no-await-in-loop - const versionCached = await inMemoryCache.get(`${MemoryCachePrefix.VERSION}:${versionId}`); - if (versionCached) { - const version = PrefixCommandVersion.hydrate(versionCached); - const { emoji } = version; - Logger.debug(`Found version ${versionId} for command ${name} with emoji ${emoji}`); - versionEmojis.push(emoji); - } - } + const startIndex = page * pageLimit; + const endIndex = startIndex + pageLimit; + const currentCommands = sortedCommands.slice(startIndex, endIndex); + const totalPages = Math.ceil(sortedCommands.length / pageLimit); + + const descriptionLines: string[] = []; + for (const command of currentCommands) { + const { name, aliases, description, contents } = command; + const versionEmojis = []; + for (const content of contents) { + const { versionId } = content; + if (versionId !== 'GENERIC') { + Logger.debug(`Fetching version ${versionId} for command ${name}`); + // eslint-disable-next-line no-await-in-loop + const versionCached = await inMemoryCache.get(`${MemoryCachePrefix.VERSION}:${versionId}`); + if (versionCached) { + const version = PrefixCommandVersion.hydrate(versionCached); + const { emoji } = version; + Logger.debug(`Found version ${versionId} for command ${name} with emoji ${emoji}`); + versionEmojis.push(emoji); } - const sortedVersionEmojis = versionEmojis.sort((a, b) => a.localeCompare(b)); - descriptionLines.push(`**${name}** ${sortedVersionEmojis.join(', ')}`); - descriptionLines.push(description); - if (aliases.length > 0) descriptionLines.push(`Aliases: ${aliases.join(', ')}`); - descriptionLines.push(''); + } } - - const { name: categoryName, emoji: categoryEmoji } = category; - const embed = makeEmbed({ - title: `${categoryEmoji || ''}${categoryName} Commands (${page + 1}/${totalPages})`, - description: makeLines(descriptionLines), - }); - - embeds.push(embed); + const sortedVersionEmojis = versionEmojis.sort((a, b) => a.localeCompare(b)); + descriptionLines.push(`**${name}** ${sortedVersionEmojis.join(', ')}`); + descriptionLines.push(description); + if (aliases.length > 0) descriptionLines.push(`Aliases: ${aliases.join(', ')}`); + descriptionLines.push(''); + } + + const { name: categoryName, emoji: categoryEmoji } = category; + const embed = makeEmbed({ + title: `${categoryEmoji || ''}${categoryName} Commands (${page + 1}/${totalPages})`, + description: makeLines(descriptionLines), + }); + + embeds.push(embed); } return createPaginatedEmbedHandler(interaction, embeds); -}, autocompleteCallback); + }, + autocompleteCallback, +); diff --git a/src/events/index.ts b/src/events/index.ts index 684f5870..af732465 100644 --- a/src/events/index.ts +++ b/src/events/index.ts @@ -12,14 +12,14 @@ import autocompleteHandler from './autocompleteHandler'; import buttonHandler from './buttonHandlers/buttonHandler'; export default [ - ready, - scamLogs, - detectBan, - slashCommandHandler, - contextInteractionHandler, - messageDelete, - messageUpdate, - messageCreateHandler, - autocompleteHandler, - buttonHandler, + ready, + scamLogs, + detectBan, + slashCommandHandler, + contextInteractionHandler, + messageDelete, + messageUpdate, + messageCreateHandler, + autocompleteHandler, + buttonHandler, ] as Event[]; diff --git a/src/events/messageCreateHandler.ts b/src/events/messageCreateHandler.ts index 78a2f0db..4f864a33 100644 --- a/src/events/messageCreateHandler.ts +++ b/src/events/messageCreateHandler.ts @@ -1,298 +1,424 @@ -import { ActionRowBuilder, ButtonBuilder, ButtonInteraction, ButtonStyle, EmbedBuilder, Interaction, Message } from 'discord.js'; -import { event, getInMemoryCache, MemoryCachePrefix, Logger, Events, constantsConfig, makeEmbed, makeLines, PrefixCommand, PrefixCommandPermissions, PrefixCommandVersion } from '../lib'; +import { + ActionRowBuilder, + ButtonBuilder, + ButtonInteraction, + ButtonStyle, + EmbedBuilder, + Interaction, + Message, +} from 'discord.js'; +import { + event, + getInMemoryCache, + MemoryCachePrefix, + Logger, + Events, + constantsConfig, + makeEmbed, + makeLines, + PrefixCommand, + PrefixCommandPermissions, + PrefixCommandVersion, +} from '../lib'; -const commandEmbed = (title: string, description: string, color: string, imageUrl: string = '') => makeEmbed({ +const commandEmbed = (title: string, description: string, color: string, imageUrl: string = '') => + makeEmbed({ title, description, color: Number(color), ...(imageUrl && { image: { url: imageUrl } }), -}); + }); -async function replyWithEmbed(msg: Message, embed: EmbedBuilder, buttonRow?: ActionRowBuilder) : Promise> { - return msg.fetchReference() - .then((res) => { - embed = EmbedBuilder.from(embed.data); - embed.setFooter({ text: `Executed by ${msg.author.tag} - ${msg.author.id}` }); - return res.reply({ - embeds: [embed], - components: buttonRow ? [buttonRow] : [], - }); - }) - .catch(() => msg.reply({ - embeds: [embed], - components: buttonRow ? [buttonRow] : [], - })); +async function replyWithEmbed( + msg: Message, + embed: EmbedBuilder, + buttonRow?: ActionRowBuilder, +): Promise> { + return msg + .fetchReference() + .then((res) => { + embed = EmbedBuilder.from(embed.data); + embed.setFooter({ text: `Executed by ${msg.author.tag} - ${msg.author.id}` }); + return res.reply({ + embeds: [embed], + components: buttonRow ? [buttonRow] : [], + }); + }) + .catch(() => + msg.reply({ + embeds: [embed], + components: buttonRow ? [buttonRow] : [], + }), + ); } -async function replyWithMsg(msg: Message, text: string, buttonRow?:ActionRowBuilder) : Promise> { - return msg.fetchReference() - .then((res) => res.reply({ - content: `${text}\n\n\`Executed by ${msg.author.tag} - ${msg.author.id}\``, - components: buttonRow ? [buttonRow] : [], - })) - .catch(() => msg.reply({ - content: text, - components: buttonRow ? [buttonRow] : [], - })); +async function replyWithMsg( + msg: Message, + text: string, + buttonRow?: ActionRowBuilder, +): Promise> { + return msg + .fetchReference() + .then((res) => + res.reply({ + content: `${text}\n\n\`Executed by ${msg.author.tag} - ${msg.author.id}\``, + components: buttonRow ? [buttonRow] : [], + }), + ) + .catch(() => + msg.reply({ + content: text, + components: buttonRow ? [buttonRow] : [], + }), + ); } -async function sendReply(message: Message, commandTitle: string, commandContent: string, isEmbed: boolean, embedColor: string, commandImage: string, versionButtonRow?: ActionRowBuilder) : Promise> { - try { - let actualCommandContent = commandContent; - if (!commandTitle && !commandContent && !commandImage) { - actualCommandContent = 'No content available.'; - } - if (isEmbed) { - return replyWithEmbed(message, commandEmbed(commandTitle, actualCommandContent, embedColor, commandImage), versionButtonRow); - } - const content: string[] = []; - if (commandTitle) { - content.push(`**${commandTitle}**`); - } - content.push(actualCommandContent); - return replyWithMsg(message, makeLines(content), versionButtonRow); - } catch (error) { - Logger.error(error); - return message.reply('An error occurred while processing the command.'); +async function sendReply( + message: Message, + commandTitle: string, + commandContent: string, + isEmbed: boolean, + embedColor: string, + commandImage: string, + versionButtonRow?: ActionRowBuilder, +): Promise> { + try { + let actualCommandContent = commandContent; + if (!commandTitle && !commandContent && !commandImage) { + actualCommandContent = 'No content available.'; } + if (isEmbed) { + return replyWithEmbed( + message, + commandEmbed(commandTitle, actualCommandContent, embedColor, commandImage), + versionButtonRow, + ); + } + const content: string[] = []; + if (commandTitle) { + content.push(`**${commandTitle}**`); + } + content.push(actualCommandContent); + return replyWithMsg(message, makeLines(content), versionButtonRow); + } catch (error) { + Logger.error(error); + return message.reply('An error occurred while processing the command.'); + } } -async function expireChoiceReply(message: Message, commandTitle: string, commandContent: string, isEmbed: boolean, embedColor: string, commandImage: string) : Promise> { - try { - let actualCommandContent = commandContent; - if (!commandTitle && !commandContent && !commandImage) { - actualCommandContent = 'No content available.'; - } - if (isEmbed) { - const commandEmbedData = commandEmbed(commandTitle, actualCommandContent, embedColor, commandImage); - const { footer } = message.embeds[0]; - const newFooter = footer?.text ? `${footer.text} - The choice has expired.` : 'The choice has expired.'; - commandEmbedData.setFooter({ text: newFooter }); - return message.edit({ embeds: [commandEmbedData], components: [] }); - } +async function expireChoiceReply( + message: Message, + commandTitle: string, + commandContent: string, + isEmbed: boolean, + embedColor: string, + commandImage: string, +): Promise> { + try { + let actualCommandContent = commandContent; + if (!commandTitle && !commandContent && !commandImage) { + actualCommandContent = 'No content available.'; + } + if (isEmbed) { + const commandEmbedData = commandEmbed(commandTitle, actualCommandContent, embedColor, commandImage); + const { footer } = message.embeds[0]; + const newFooter = footer?.text ? `${footer.text} - The choice has expired.` : 'The choice has expired.'; + commandEmbedData.setFooter({ text: newFooter }); + return message.edit({ embeds: [commandEmbedData], components: [] }); + } - const content: string[] = []; - if (commandTitle) { - content.push(`**${commandTitle}**`); - } - content.push(actualCommandContent); - content.push('\n`The choice has expired.`'); - return message.edit({ - content: makeLines(content), - components: [], - }); - } catch (error) { - Logger.error(error); - return message.reply('An error occurred while updating the message.'); + const content: string[] = []; + if (commandTitle) { + content.push(`**${commandTitle}**`); } + content.push(actualCommandContent); + content.push('\n`The choice has expired.`'); + return message.edit({ + content: makeLines(content), + components: [], + }); + } catch (error) { + Logger.error(error); + return message.reply('An error occurred while updating the message.'); + } } async function sendPermError(message: Message, errorText: string) { - if (constantsConfig.prefixCommandPermissionDelay > 0) { - errorText += `\n\nThis message & the original command message will be deleted in ${constantsConfig.prefixCommandPermissionDelay / 1000} seconds.`; - } - const permReply = await sendReply(message, 'Permission Error', errorText, true, constantsConfig.colors.FBW_RED, ''); - if (constantsConfig.prefixCommandPermissionDelay > 0) { - setTimeout(() => { - try { - permReply.delete(); - message.delete(); - } catch (error) { - Logger.error(`Error while deleting permission error message for command: ${error}`); - } - }, constantsConfig.prefixCommandPermissionDelay); - } + if (constantsConfig.prefixCommandPermissionDelay > 0) { + errorText += `\n\nThis message & the original command message will be deleted in ${constantsConfig.prefixCommandPermissionDelay / 1000} seconds.`; + } + const permReply = await sendReply(message, 'Permission Error', errorText, true, constantsConfig.colors.FBW_RED, ''); + if (constantsConfig.prefixCommandPermissionDelay > 0) { + setTimeout(() => { + try { + permReply.delete(); + message.delete(); + } catch (error) { + Logger.error(`Error while deleting permission error message for command: ${error}`); + } + }, constantsConfig.prefixCommandPermissionDelay); + } } export default event(Events.MessageCreate, async (_, message) => { - const { id: messageId, author, channel, content } = message; - const { id: authorId, bot } = author; + const { id: messageId, author, channel, content } = message; + const { id: authorId, bot } = author; - if (bot || channel.isDMBased()) return; - const { id: channelId, guild } = channel; - const { id: guildId } = guild; - Logger.debug(`Processing message ${messageId} from user ${authorId} in channel ${channelId} of server ${guildId}.`); + if (bot || channel.isDMBased()) return; + const { id: channelId, guild } = channel; + const { id: guildId } = guild; + Logger.debug(`Processing message ${messageId} from user ${authorId} in channel ${channelId} of server ${guildId}.`); - const inMemoryCache = getInMemoryCache(); - if (inMemoryCache && content.startsWith(constantsConfig.prefixCommandPrefix)) { - const commandTextMatch = content.match(`^\\${constantsConfig.prefixCommandPrefix}([\\w\\d-_]+)[^\\w\\d-_]*([\\w\\d-_]+)?`); - if (commandTextMatch) { - let [commandText] = commandTextMatch.slice(1); - const commandVersionExplicitGeneric = (commandText.toLowerCase() === 'generic'); + const inMemoryCache = getInMemoryCache(); + if (inMemoryCache && content.startsWith(constantsConfig.prefixCommandPrefix)) { + const commandTextMatch = content.match( + `^\\${constantsConfig.prefixCommandPrefix}([\\w\\d-_]+)[^\\w\\d-_]*([\\w\\d-_]+)?`, + ); + if (commandTextMatch) { + let [commandText] = commandTextMatch.slice(1); + const commandVersionExplicitGeneric = commandText.toLowerCase() === 'generic'; - // Step 1: Check if the command is actually a version alias - const commandCachedVersion = await inMemoryCache.get(`${MemoryCachePrefix.VERSION}:${commandText.toLowerCase()}`); - let commandVersionId: string; - let commandVersionName: string; - let commandVersionEnabled: boolean; - if (commandCachedVersion) { - const commandVersion = PrefixCommandVersion.hydrate(commandCachedVersion); - ({ id: commandVersionId, name: commandVersionName, enabled: commandVersionEnabled } = commandVersion); - } else { - commandVersionId = 'GENERIC'; - commandVersionName = 'GENERIC'; - commandVersionEnabled = true; - } + // Step 1: Check if the command is actually a version alias + const commandCachedVersion = await inMemoryCache.get(`${MemoryCachePrefix.VERSION}:${commandText.toLowerCase()}`); + let commandVersionId: string; + let commandVersionName: string; + let commandVersionEnabled: boolean; + if (commandCachedVersion) { + const commandVersion = PrefixCommandVersion.hydrate(commandCachedVersion); + ({ id: commandVersionId, name: commandVersionName, enabled: commandVersionEnabled } = commandVersion); + } else { + commandVersionId = 'GENERIC'; + commandVersionName = 'GENERIC'; + commandVersionEnabled = true; + } - // Step 2: Check if there's a default version for the channel if commandVersionName is GENERIC - let channelDefaultVersionUsed = false; - if (commandVersionName === 'GENERIC' && !commandVersionExplicitGeneric) { - const channelDefaultVersionCached = await inMemoryCache.get(`${MemoryCachePrefix.CHANNEL_DEFAULT_VERSION}:${channelId}`); - if (channelDefaultVersionCached) { - const channelDefaultVersion = PrefixCommandVersion.hydrate(channelDefaultVersionCached); - ({ id: commandVersionId, name: commandVersionName, enabled: commandVersionEnabled } = channelDefaultVersion); - channelDefaultVersionUsed = true; - } - } + // Step 2: Check if there's a default version for the channel if commandVersionName is GENERIC + let channelDefaultVersionUsed = false; + if (commandVersionName === 'GENERIC' && !commandVersionExplicitGeneric) { + const channelDefaultVersionCached = await inMemoryCache.get( + `${MemoryCachePrefix.CHANNEL_DEFAULT_VERSION}:${channelId}`, + ); + if (channelDefaultVersionCached) { + const channelDefaultVersion = PrefixCommandVersion.hydrate(channelDefaultVersionCached); + ({ id: commandVersionId, name: commandVersionName, enabled: commandVersionEnabled } = channelDefaultVersion); + channelDefaultVersionUsed = true; + } + } - // Drop execution if the version is disabled and we aren't using the default version for a channel - if (!commandVersionEnabled && !channelDefaultVersionUsed) { - if ((commandCachedVersion || commandVersionExplicitGeneric) && commandTextMatch[2]) { - [commandText] = commandTextMatch.slice(2); - } - Logger.debug(`Prefix Command - Version "${commandVersionName}" is disabled - Not executing command "${commandText}"`); - return; - } - // If the version is disabled and we are using the default version for a channel, switch to the generic version - if (!commandVersionEnabled && channelDefaultVersionUsed) { - commandVersionId = 'GENERIC'; - commandVersionName = 'GENERIC'; - commandVersionEnabled = true; - } + // Drop execution if the version is disabled and we aren't using the default version for a channel + if (!commandVersionEnabled && !channelDefaultVersionUsed) { + if ((commandCachedVersion || commandVersionExplicitGeneric) && commandTextMatch[2]) { + [commandText] = commandTextMatch.slice(2); + } + Logger.debug( + `Prefix Command - Version "${commandVersionName}" is disabled - Not executing command "${commandText}"`, + ); + return; + } + // If the version is disabled and we are using the default version for a channel, switch to the generic version + if (!commandVersionEnabled && channelDefaultVersionUsed) { + commandVersionId = 'GENERIC'; + commandVersionName = 'GENERIC'; + commandVersionEnabled = true; + } - // Step 2.5: If the first command was actually a version alias, take the actual command as CommandText - if ((commandCachedVersion || commandVersionExplicitGeneric) && commandTextMatch[2]) { - [commandText] = commandTextMatch.slice(2); - } + // Step 2.5: If the first command was actually a version alias, take the actual command as CommandText + if ((commandCachedVersion || commandVersionExplicitGeneric) && commandTextMatch[2]) { + [commandText] = commandTextMatch.slice(2); + } - // Step 3: Check if the command exists itself and process it - const cachedCommandDetails = await inMemoryCache.get(`${MemoryCachePrefix.COMMAND}:${commandText.toLowerCase()}`); - if (cachedCommandDetails) { - const commandDetails = PrefixCommand.hydrate(cachedCommandDetails); - const { name, contents, isEmbed, embedColor, permissions } = commandDetails; - const { roles: permRoles, rolesBlocklist, channels: permChannels, channelsBlocklist, quietErrors, verboseErrors } = permissions ?? new PrefixCommandPermissions(); - const authorMember = await guild.members.fetch(authorId); + // Step 3: Check if the command exists itself and process it + const cachedCommandDetails = await inMemoryCache.get(`${MemoryCachePrefix.COMMAND}:${commandText.toLowerCase()}`); + if (cachedCommandDetails) { + const commandDetails = PrefixCommand.hydrate(cachedCommandDetails); + const { name, contents, isEmbed, embedColor, permissions } = commandDetails; + const { + roles: permRoles, + rolesBlocklist, + channels: permChannels, + channelsBlocklist, + quietErrors, + verboseErrors, + } = permissions ?? new PrefixCommandPermissions(); + const authorMember = await guild.members.fetch(authorId); - // Check permissions - const hasAnyRole = permRoles && permRoles.some((role) => authorMember.roles.cache.has(role)); - const isInChannel = permChannels && permChannels.includes(channelId); - const meetsRoleRequirements = !permRoles || permRoles.length === 0 - || (hasAnyRole && !rolesBlocklist) - || (!hasAnyRole && rolesBlocklist); - const meetsChannelRequirements = !permChannels || permChannels.length === 0 - || (isInChannel && !channelsBlocklist) - || (!isInChannel && channelsBlocklist); + // Check permissions + const hasAnyRole = permRoles && permRoles.some((role) => authorMember.roles.cache.has(role)); + const isInChannel = permChannels && permChannels.includes(channelId); + const meetsRoleRequirements = + !permRoles || permRoles.length === 0 || (hasAnyRole && !rolesBlocklist) || (!hasAnyRole && rolesBlocklist); + const meetsChannelRequirements = + !permChannels || + permChannels.length === 0 || + (isInChannel && !channelsBlocklist) || + (!isInChannel && channelsBlocklist); - if (!meetsRoleRequirements) { - Logger.debug(`Prefix Command - User does not meet role requirements for command "${name}" based on user command "${commandText}"`); - if (quietErrors) return; - let errorText = ''; - if (verboseErrors && !rolesBlocklist) { - errorText = `You do not have the required role to execute this command. Required roles: ${permRoles.map((role) => guild.roles.cache.get(role)?.name).join(', ')}.`; - } else if (verboseErrors && rolesBlocklist) { - errorText = `You have a blocklisted role for this command. Blocklisted roles: ${permRoles.map((role) => guild.roles.cache.get(role)?.name).join(', ')}.`; - } else if (!verboseErrors && !rolesBlocklist) { - errorText = 'You do not have the required role to execute this command.'; - } else { - errorText = 'You have a blocklisted role for this command.'; - } - await sendPermError(message, errorText); - return; - } + if (!meetsRoleRequirements) { + Logger.debug( + `Prefix Command - User does not meet role requirements for command "${name}" based on user command "${commandText}"`, + ); + if (quietErrors) return; + let errorText = ''; + if (verboseErrors && !rolesBlocklist) { + errorText = `You do not have the required role to execute this command. Required roles: ${permRoles.map((role) => guild.roles.cache.get(role)?.name).join(', ')}.`; + } else if (verboseErrors && rolesBlocklist) { + errorText = `You have a blocklisted role for this command. Blocklisted roles: ${permRoles.map((role) => guild.roles.cache.get(role)?.name).join(', ')}.`; + } else if (!verboseErrors && !rolesBlocklist) { + errorText = 'You do not have the required role to execute this command.'; + } else { + errorText = 'You have a blocklisted role for this command.'; + } + await sendPermError(message, errorText); + return; + } - if (!meetsChannelRequirements) { - Logger.debug(`Prefix Command - Message does not meet channel requirements for command "${name}" based on user command "${commandText}"`); - if (quietErrors) return; - let errorText = ''; - if (verboseErrors && !channelsBlocklist) { - errorText = `This command is not available in this channel. Required channels: ${permChannels.map((channel) => guild.channels.cache.get(channel)?.toString()).join(', ')}.`; - } else if (verboseErrors && channelsBlocklist) { - errorText = `This command is blocklisted in this channel. Blocklisted channels: ${permChannels.map((channel) => guild.channels.cache.get(channel)?.toString()).join(', ')}.`; - } else if (!verboseErrors && !channelsBlocklist) { - errorText = 'This command is not available in this channel.'; - } else { - errorText = 'This command is blocklisted in this channel.'; - } - await sendPermError(message, errorText); - return; - } + if (!meetsChannelRequirements) { + Logger.debug( + `Prefix Command - Message does not meet channel requirements for command "${name}" based on user command "${commandText}"`, + ); + if (quietErrors) return; + let errorText = ''; + if (verboseErrors && !channelsBlocklist) { + errorText = `This command is not available in this channel. Required channels: ${permChannels.map((channel) => guild.channels.cache.get(channel)?.toString()).join(', ')}.`; + } else if (verboseErrors && channelsBlocklist) { + errorText = `This command is blocklisted in this channel. Blocklisted channels: ${permChannels.map((channel) => guild.channels.cache.get(channel)?.toString()).join(', ')}.`; + } else if (!verboseErrors && !channelsBlocklist) { + errorText = 'This command is not available in this channel.'; + } else { + errorText = 'This command is blocklisted in this channel.'; + } + await sendPermError(message, errorText); + return; + } - let commandContentData = contents.find(({ versionId }) => versionId === commandVersionId); - let enableButtons = true; - // If the version is not found, try to find the generic version - if (!commandContentData) { - commandContentData = contents.find(({ versionId }) => versionId === 'GENERIC'); - commandVersionName = 'GENERIC'; - enableButtons = false; - } - // If the generic version is not found, drop execution - if (!commandContentData) { - Logger.debug(`Prefix Command - Version "${commandVersionName}" not found for command "${name}" based on user command "${commandText}"`); - return; - } - const { title: commandTitle, content: commandContent, image: commandImage } = commandContentData; - // If generic requested and multiple versions, show the selection - // Note that this only applies if GENERIC is the version explicitly requested - // Otherwise, the options are not shown - if (enableButtons && commandVersionName === 'GENERIC' && contents.length > 1) { - Logger.debug(`Prefix Command - Multiple versions found for command "${name}" based on user command "${commandText}", showing version selection`); - const versionSelectionButtonData: { [key: string]: ButtonBuilder } = {}; - for (const { versionId: versionIdForButton } of contents) { - // eslint-disable-next-line no-await-in-loop - const versionCached = await inMemoryCache.get(`${MemoryCachePrefix.VERSION}:${versionIdForButton}`); - if (versionCached) { - const version = PrefixCommandVersion.hydrate(versionCached); - const { emoji, enabled } = version; - if (enabled) { - versionSelectionButtonData[emoji] = new ButtonBuilder() - .setCustomId(`${versionIdForButton}`) - .setEmoji(emoji) - .setStyle(ButtonStyle.Primary); - } - } - } - const versionSelectionButtons: ButtonBuilder[] = Object.keys(versionSelectionButtonData) - .sort() - .map((key: string) => versionSelectionButtonData[key]); - const versionSelectButtonRow = new ActionRowBuilder().addComponents(versionSelectionButtons); + let commandContentData = contents.find(({ versionId }) => versionId === commandVersionId); + let enableButtons = true; + // If the version is not found, try to find the generic version + if (!commandContentData) { + commandContentData = contents.find(({ versionId }) => versionId === 'GENERIC'); + commandVersionName = 'GENERIC'; + enableButtons = false; + } + // If the generic version is not found, drop execution + if (!commandContentData) { + Logger.debug( + `Prefix Command - Version "${commandVersionName}" not found for command "${name}" based on user command "${commandText}"`, + ); + return; + } + const { title: commandTitle, content: commandContent, image: commandImage } = commandContentData; + // If generic requested and multiple versions, show the selection + // Note that this only applies if GENERIC is the version explicitly requested + // Otherwise, the options are not shown + if (enableButtons && commandVersionName === 'GENERIC' && contents.length > 1) { + Logger.debug( + `Prefix Command - Multiple versions found for command "${name}" based on user command "${commandText}", showing version selection`, + ); + const versionSelectionButtonData: { [key: string]: ButtonBuilder } = {}; + for (const { versionId: versionIdForButton } of contents) { + // eslint-disable-next-line no-await-in-loop + const versionCached = await inMemoryCache.get(`${MemoryCachePrefix.VERSION}:${versionIdForButton}`); + if (versionCached) { + const version = PrefixCommandVersion.hydrate(versionCached); + const { emoji, enabled } = version; + if (enabled) { + versionSelectionButtonData[emoji] = new ButtonBuilder() + .setCustomId(`${versionIdForButton}`) + .setEmoji(emoji) + .setStyle(ButtonStyle.Primary); + } + } + } + const versionSelectionButtons: ButtonBuilder[] = Object.keys(versionSelectionButtonData) + .sort() + .map((key: string) => versionSelectionButtonData[key]); + const versionSelectButtonRow = new ActionRowBuilder().addComponents(versionSelectionButtons); - if (versionSelectButtonRow.components.length < 1) { - Logger.debug(`Prefix Command - No enabled versions found for command "${name}" based on user command "${commandText}"`); - Logger.debug(`Prefix Command - Executing version "${commandVersionName}" for command "${name}" based on user command "${commandText}"`); - await sendReply(message, commandTitle, commandContent || '', isEmbed || false, embedColor || constantsConfig.colors.FBW_CYAN, commandImage || ''); - return; - } - const buttonMessage = await sendReply(message, commandTitle, commandContent || '', isEmbed || false, embedColor || constantsConfig.colors.FBW_CYAN, commandImage || '', versionSelectButtonRow); + if (versionSelectButtonRow.components.length < 1) { + Logger.debug( + `Prefix Command - No enabled versions found for command "${name}" based on user command "${commandText}"`, + ); + Logger.debug( + `Prefix Command - Executing version "${commandVersionName}" for command "${name}" based on user command "${commandText}"`, + ); + await sendReply( + message, + commandTitle, + commandContent || '', + isEmbed || false, + embedColor || constantsConfig.colors.FBW_CYAN, + commandImage || '', + ); + return; + } + const buttonMessage = await sendReply( + message, + commandTitle, + commandContent || '', + isEmbed || false, + embedColor || constantsConfig.colors.FBW_CYAN, + commandImage || '', + versionSelectButtonRow, + ); - const filter = (interaction: Interaction) => interaction.user.id === authorId; - const collector = buttonMessage.createMessageComponentCollector({ filter, time: 60_000 }); - let buttonClicked = false; - collector.on('collect', async (collectedInteraction: ButtonInteraction) => { - buttonClicked = true; - await collectedInteraction.deferUpdate(); - Logger.debug(`Prefix Command - User selected button "${collectedInteraction.customId}" for command "${name}" based on user command "${commandText}"`); - await buttonMessage.delete(); - const { customId: selectedVersionId } = collectedInteraction; - const commandContentData = contents.find(({ versionId }) => versionId === selectedVersionId); - if (!commandContentData) { - Logger.debug(`Prefix Command - Version ID "${selectedVersionId}" not found for command "${name}" based on user command "${commandText}"`); - return; - } - const { title: commandTitle, content: commandContent, image: commandImage } = commandContentData; - await sendReply(message, commandTitle, commandContent || '', isEmbed || false, embedColor || constantsConfig.colors.FBW_CYAN, commandImage || ''); - }); + const filter = (interaction: Interaction) => interaction.user.id === authorId; + const collector = buttonMessage.createMessageComponentCollector({ filter, time: 60_000 }); + let buttonClicked = false; + collector.on('collect', async (collectedInteraction: ButtonInteraction) => { + buttonClicked = true; + await collectedInteraction.deferUpdate(); + Logger.debug( + `Prefix Command - User selected button "${collectedInteraction.customId}" for command "${name}" based on user command "${commandText}"`, + ); + await buttonMessage.delete(); + const { customId: selectedVersionId } = collectedInteraction; + const commandContentData = contents.find(({ versionId }) => versionId === selectedVersionId); + if (!commandContentData) { + Logger.debug( + `Prefix Command - Version ID "${selectedVersionId}" not found for command "${name}" based on user command "${commandText}"`, + ); + return; + } + const { title: commandTitle, content: commandContent, image: commandImage } = commandContentData; + await sendReply( + message, + commandTitle, + commandContent || '', + isEmbed || false, + embedColor || constantsConfig.colors.FBW_CYAN, + commandImage || '', + ); + }); - collector.on('end', async (_: ButtonInteraction, reason: string) => { - if (!buttonClicked && reason === 'time') { - Logger.debug(`Prefix Command - User did not select a version for command "${name}" based on user command "${commandText}"`); - await expireChoiceReply(buttonMessage, commandTitle, commandContent || '', isEmbed || false, embedColor || constantsConfig.colors.FBW_CYAN, commandImage || ''); - } - }); - } else { - Logger.debug(`Prefix Command - Executing version "${commandVersionName}" for command "${name}" based on user command "${commandText}"`); - await sendReply(message, commandTitle, commandContent || '', isEmbed || false, embedColor || constantsConfig.colors.FBW_CYAN, commandImage || ''); - } + collector.on('end', async (_: ButtonInteraction, reason: string) => { + if (!buttonClicked && reason === 'time') { + Logger.debug( + `Prefix Command - User did not select a version for command "${name}" based on user command "${commandText}"`, + ); + await expireChoiceReply( + buttonMessage, + commandTitle, + commandContent || '', + isEmbed || false, + embedColor || constantsConfig.colors.FBW_CYAN, + commandImage || '', + ); } + }); + } else { + Logger.debug( + `Prefix Command - Executing version "${commandVersionName}" for command "${name}" based on user command "${commandText}"`, + ); + await sendReply( + message, + commandTitle, + commandContent || '', + isEmbed || false, + embedColor || constantsConfig.colors.FBW_CYAN, + commandImage || '', + ); } + } } + } }); diff --git a/src/events/ready.ts b/src/events/ready.ts index b8772b04..cc466082 100644 --- a/src/events/ready.ts +++ b/src/events/ready.ts @@ -1,19 +1,19 @@ import { ActivityType, TextChannel } from 'discord.js'; import moment from 'moment'; import { - constantsConfig, - event, - Events, - connect, - setupScheduler, - Logger, - imageBaseUrl, - getScheduler, - setupInMemoryCache, - loadAllPrefixCommandsToCache, - loadAllPrefixCommandVersionsToCache, - loadAllPrefixCommandCategoriesToCache, - loadAllPrefixCommandChannelDefaultVersionsToCache, + constantsConfig, + event, + Events, + connect, + setupScheduler, + Logger, + imageBaseUrl, + getScheduler, + setupInMemoryCache, + loadAllPrefixCommandsToCache, + loadAllPrefixCommandVersionsToCache, + loadAllPrefixCommandCategoriesToCache, + loadAllPrefixCommandChannelDefaultVersionsToCache, } from '../lib'; import { deployCommands } from '../scripts/deployCommands'; import commandArray from '../commands'; @@ -55,23 +55,23 @@ export default event(Events.ClientReady, async ({ log }, client) => { } } - // Setup cache manager - let inMemoryCacheSetup = false; - let inMemoryCacheError: Error | undefined; - await setupInMemoryCache() - .then(() => { - inMemoryCacheSetup = true; - }) - .catch((error) => { - inMemoryCacheError = error; - Logger.error(error); - }); - - // Connect to MongoDB and set up scheduler - let dbConnected = false; - let dbError: Error | undefined; - let schedulerConnected = false; - let schedulerError: Error | undefined; + // Setup cache manager + let inMemoryCacheSetup = false; + let inMemoryCacheError: Error | undefined; + await setupInMemoryCache() + .then(() => { + inMemoryCacheSetup = true; + }) + .catch((error) => { + inMemoryCacheError = error; + Logger.error(error); + }); + + // Connect to MongoDB and set up scheduler + let dbConnected = false; + let dbError: Error | undefined; + let schedulerConnected = false; + let schedulerError: Error | undefined; if (process.env.MONGODB_URL) { await connect(process.env.MONGODB_URL) @@ -156,15 +156,15 @@ export default event(Events.ClientReady, async ({ log }, client) => { logMessage += ` - DB Error: ${dbError.message}`; } - logMessage += ` - Scheduler State: ${schedulerConnected ? 'Connected' : 'Disconnected'}`; - if (!schedulerConnected && schedulerError) { - logMessage += ` - Scheduler Error: ${schedulerError.message}`; - } + logMessage += ` - Scheduler State: ${schedulerConnected ? 'Connected' : 'Disconnected'}`; + if (!schedulerConnected && schedulerError) { + logMessage += ` - Scheduler Error: ${schedulerError.message}`; + } - logMessage += ` - Cache State: ${inMemoryCacheSetup ? 'Setup' : 'Not Setup'}`; - if (!inMemoryCacheSetup && inMemoryCacheError) { - logMessage += ` - Cache Error: ${inMemoryCacheError.message}`; - } + logMessage += ` - Cache State: ${inMemoryCacheSetup ? 'Setup' : 'Not Setup'}`; + if (!inMemoryCacheSetup && inMemoryCacheError) { + logMessage += ` - Cache Error: ${inMemoryCacheError.message}`; + } await botDevChannel.send({ content: logMessage }); } else { diff --git a/src/lib/cache/cacheManager.ts b/src/lib/cache/cacheManager.ts index 84e67e91..676c025e 100644 --- a/src/lib/cache/cacheManager.ts +++ b/src/lib/cache/cacheManager.ts @@ -1,5 +1,16 @@ import { Cache, caching } from 'cache-manager'; -import { getConn, IPrefixCommand, IPrefixCommandCategory, IPrefixCommandChannelDefaultVersion, IPrefixCommandVersion, Logger, PrefixCommand, PrefixCommandCategory, PrefixCommandChannelDefaultVersion, PrefixCommandVersion } from '../index'; +import { + getConn, + IPrefixCommand, + IPrefixCommandCategory, + IPrefixCommandChannelDefaultVersion, + IPrefixCommandVersion, + Logger, + PrefixCommand, + PrefixCommandCategory, + PrefixCommandChannelDefaultVersion, + PrefixCommandVersion, +} from '../index'; let inMemoryCache: Cache; const cacheSize = 10000; @@ -11,10 +22,10 @@ const cacheTTL = cacheRefreshInterval * 2 * 1000; */ export enum MemoryCachePrefix { - COMMAND = 'PF_COMMAND', - VERSION = 'PF_VERSION', - CATEGORY = 'PF_CATEGORY', - CHANNEL_DEFAULT_VERSION = 'PF_CHANNEL_VERSION', + COMMAND = 'PF_COMMAND', + VERSION = 'PF_VERSION', + CATEGORY = 'PF_CATEGORY', + CHANNEL_DEFAULT_VERSION = 'PF_CHANNEL_VERSION', } /** @@ -22,26 +33,23 @@ export enum MemoryCachePrefix { */ export async function setupInMemoryCache(callback = Logger.error) { - try { - inMemoryCache = await caching( - 'memory', - { - ttl: cacheTTL, - max: cacheSize, - }, - ); - Logger.info('In memory cache set up'); - } catch (err) { - callback(err); - } + try { + inMemoryCache = await caching('memory', { + ttl: cacheTTL, + max: cacheSize, + }); + Logger.info('In memory cache set up'); + } catch (err) { + callback(err); + } } export function getInMemoryCache(callback = Logger.error) { - if (!inMemoryCache) { - callback(new Error('No in memory cache available.')); - return null; - } - return inMemoryCache; + if (!inMemoryCache) { + callback(new Error('No in memory cache available.')); + return null; + } + return inMemoryCache; } /** @@ -49,71 +57,75 @@ export function getInMemoryCache(callback = Logger.error) { */ export async function clearSinglePrefixCommandCache(command: IPrefixCommand) { - const inMemoryCache = getInMemoryCache(); - if (!inMemoryCache) return; + const inMemoryCache = getInMemoryCache(); + if (!inMemoryCache) return; - const { name, aliases } = command; - Logger.debug(`Clearing cache for command or alias "${name}"`); - await Promise.all(aliases.map((alias) => inMemoryCache.del(`${MemoryCachePrefix.COMMAND}:${alias.toLowerCase()}`))); - await inMemoryCache.del(`${MemoryCachePrefix.COMMAND}:${name.toLowerCase()}`); + const { name, aliases } = command; + Logger.debug(`Clearing cache for command or alias "${name}"`); + await Promise.all(aliases.map((alias) => inMemoryCache.del(`${MemoryCachePrefix.COMMAND}:${alias.toLowerCase()}`))); + await inMemoryCache.del(`${MemoryCachePrefix.COMMAND}:${name.toLowerCase()}`); } export async function loadSinglePrefixCommandToCache(command: IPrefixCommand) { - const inMemoryCache = getInMemoryCache(); - if (!inMemoryCache) return; - - const { name, aliases } = command; - Logger.debug(`Loading command ${name} to cache`); - await inMemoryCache.set(`${MemoryCachePrefix.COMMAND}:${name.toLowerCase()}`, command.toObject()); - await Promise.all(aliases.map((alias) => inMemoryCache.set(`${MemoryCachePrefix.COMMAND}:${alias.toLowerCase()}`, command.toObject()))); + const inMemoryCache = getInMemoryCache(); + if (!inMemoryCache) return; + + const { name, aliases } = command; + Logger.debug(`Loading command ${name} to cache`); + await inMemoryCache.set(`${MemoryCachePrefix.COMMAND}:${name.toLowerCase()}`, command.toObject()); + await Promise.all( + aliases.map((alias) => + inMemoryCache.set(`${MemoryCachePrefix.COMMAND}:${alias.toLowerCase()}`, command.toObject()), + ), + ); } export async function loadAllPrefixCommandsToCache() { - const conn = getConn(); - const inMemoryCache = getInMemoryCache(); - if (!conn || !inMemoryCache) return; + const conn = getConn(); + const inMemoryCache = getInMemoryCache(); + if (!conn || !inMemoryCache) return; - const prefixCommands = await PrefixCommand.find(); - await Promise.all(prefixCommands.map((command) => loadSinglePrefixCommandToCache(command))); + const prefixCommands = await PrefixCommand.find(); + await Promise.all(prefixCommands.map((command) => loadSinglePrefixCommandToCache(command))); } export async function refreshSinglePrefixCommandCache(oldCommand: IPrefixCommand, newCommand: IPrefixCommand) { - await clearSinglePrefixCommandCache(oldCommand); - await loadSinglePrefixCommandToCache(newCommand); + await clearSinglePrefixCommandCache(oldCommand); + await loadSinglePrefixCommandToCache(newCommand); } export async function refreshAllPrefixCommandsCache() { - const conn = getConn(); - const inMemoryCache = getInMemoryCache(); - if (!conn || !inMemoryCache) return; - - // Step 1: Get all commands from the database - const prefixCommands = await PrefixCommand.find(); - // Step 2: Get all commands from the cache - const cacheKeys = await inMemoryCache.store.keys(); - // Step 3: Loop over cached commands - for (const key of cacheKeys) { - if (key.startsWith(`${MemoryCachePrefix.COMMAND}:`)) { - const checkCommand = key.split(':')[1]; - // Step 3.a: Check if cached command exists in the database list - let found = false; - for (const dbCommand of prefixCommands) { - const { name: dbCommandName, aliases: dbCommandAliases } = dbCommand; - if (dbCommandName.toLowerCase() === checkCommand.toLowerCase() || dbCommandAliases.includes(checkCommand)) { - found = true; - break; - } - } - // Step 3.b: If not found, remove from cache - if (!found) { - Logger.debug(`Removing command or alias ${checkCommand} from cache`); - // eslint-disable-next-line no-await-in-loop - await inMemoryCache.del(key); - } + const conn = getConn(); + const inMemoryCache = getInMemoryCache(); + if (!conn || !inMemoryCache) return; + + // Step 1: Get all commands from the database + const prefixCommands = await PrefixCommand.find(); + // Step 2: Get all commands from the cache + const cacheKeys = await inMemoryCache.store.keys(); + // Step 3: Loop over cached commands + for (const key of cacheKeys) { + if (key.startsWith(`${MemoryCachePrefix.COMMAND}:`)) { + const checkCommand = key.split(':')[1]; + // Step 3.a: Check if cached command exists in the database list + let found = false; + for (const dbCommand of prefixCommands) { + const { name: dbCommandName, aliases: dbCommandAliases } = dbCommand; + if (dbCommandName.toLowerCase() === checkCommand.toLowerCase() || dbCommandAliases.includes(checkCommand)) { + found = true; + break; } + } + // Step 3.b: If not found, remove from cache + if (!found) { + Logger.debug(`Removing command or alias ${checkCommand} from cache`); + // eslint-disable-next-line no-await-in-loop + await inMemoryCache.del(key); + } } - // Step 4: Loop over database commands and update cache - await Promise.all(prefixCommands.map((dbCommand) => loadSinglePrefixCommandToCache(dbCommand))); + } + // Step 4: Loop over database commands and update cache + await Promise.all(prefixCommands.map((dbCommand) => loadSinglePrefixCommandToCache(dbCommand))); } /** @@ -121,71 +133,77 @@ export async function refreshAllPrefixCommandsCache() { */ export async function clearSinglePrefixCommandVersionCache(version: IPrefixCommandVersion) { - const inMemoryCache = getInMemoryCache(); - if (!inMemoryCache) return; + const inMemoryCache = getInMemoryCache(); + if (!inMemoryCache) return; - const { alias, _id: versionId } = version; - Logger.debug(`Clearing cache for command version alias "${alias}"`); - await inMemoryCache.del(`${MemoryCachePrefix.VERSION}:${alias.toLowerCase()}`); - await inMemoryCache.del(`${MemoryCachePrefix.VERSION}:${versionId}`); + const { alias, _id: versionId } = version; + Logger.debug(`Clearing cache for command version alias "${alias}"`); + await inMemoryCache.del(`${MemoryCachePrefix.VERSION}:${alias.toLowerCase()}`); + await inMemoryCache.del(`${MemoryCachePrefix.VERSION}:${versionId}`); } export async function loadSinglePrefixCommandVersionToCache(version: IPrefixCommandVersion) { - const inMemoryCache = getInMemoryCache(); - if (!inMemoryCache) return; + const inMemoryCache = getInMemoryCache(); + if (!inMemoryCache) return; - const { alias, _id: versionId } = version; - Logger.debug(`Loading version with alias ${alias} to cache`); - await inMemoryCache.set(`${MemoryCachePrefix.VERSION}:${alias.toLowerCase()}`, version.toObject()); - await inMemoryCache.set(`${MemoryCachePrefix.VERSION}:${versionId}`, version.toObject()); + const { alias, _id: versionId } = version; + Logger.debug(`Loading version with alias ${alias} to cache`); + await inMemoryCache.set(`${MemoryCachePrefix.VERSION}:${alias.toLowerCase()}`, version.toObject()); + await inMemoryCache.set(`${MemoryCachePrefix.VERSION}:${versionId}`, version.toObject()); } export async function loadAllPrefixCommandVersionsToCache() { - const conn = getConn(); - const inMemoryCache = getInMemoryCache(); - if (!conn || !inMemoryCache) return; + const conn = getConn(); + const inMemoryCache = getInMemoryCache(); + if (!conn || !inMemoryCache) return; - const prefixCommandVersions = await PrefixCommandVersion.find(); - await Promise.all(prefixCommandVersions.map((version) => loadSinglePrefixCommandVersionToCache(version))); + const prefixCommandVersions = await PrefixCommandVersion.find(); + await Promise.all(prefixCommandVersions.map((version) => loadSinglePrefixCommandVersionToCache(version))); } -export async function refreshSinglePrefixCommandVersionCache(oldVersion: IPrefixCommandVersion, newVersion: IPrefixCommandVersion) { - await clearSinglePrefixCommandVersionCache(oldVersion); - await loadSinglePrefixCommandVersionToCache(newVersion); +export async function refreshSinglePrefixCommandVersionCache( + oldVersion: IPrefixCommandVersion, + newVersion: IPrefixCommandVersion, +) { + await clearSinglePrefixCommandVersionCache(oldVersion); + await loadSinglePrefixCommandVersionToCache(newVersion); } export async function refreshAllPrefixCommandVersionsCache() { - const conn = getConn(); - const inMemoryCache = getInMemoryCache(); - if (!conn || !inMemoryCache) return; - - // Step 1: Get all versions from the database - const prefixCommandVersions = await PrefixCommandVersion.find(); - // Step 2: Get all versions from the cache - const cacheKeys = await inMemoryCache.store.keys(); - // Step 3: Loop over cached versions - for (const key of cacheKeys) { - if (key.startsWith(`${MemoryCachePrefix.VERSION}:`)) { - const checkVersion = key.split(':')[1]; - // Step 3.a: Check if cached version exists in the database list - let found = false; - for (const dbVersion of prefixCommandVersions) { - const { _id: dbVersionId, alias } = dbVersion; - if (dbVersionId.toString().toLowerCase() === checkVersion.toLowerCase() || alias.toLowerCase() === checkVersion.toLowerCase()) { - found = true; - break; - } - } - // Step 3.b: If not found, remove from cache - if (!found) { - Logger.debug(`Removing version with id ${checkVersion} from cache`); - // eslint-disable-next-line no-await-in-loop - await inMemoryCache.del(key); - } + const conn = getConn(); + const inMemoryCache = getInMemoryCache(); + if (!conn || !inMemoryCache) return; + + // Step 1: Get all versions from the database + const prefixCommandVersions = await PrefixCommandVersion.find(); + // Step 2: Get all versions from the cache + const cacheKeys = await inMemoryCache.store.keys(); + // Step 3: Loop over cached versions + for (const key of cacheKeys) { + if (key.startsWith(`${MemoryCachePrefix.VERSION}:`)) { + const checkVersion = key.split(':')[1]; + // Step 3.a: Check if cached version exists in the database list + let found = false; + for (const dbVersion of prefixCommandVersions) { + const { _id: dbVersionId, alias } = dbVersion; + if ( + dbVersionId.toString().toLowerCase() === checkVersion.toLowerCase() || + alias.toLowerCase() === checkVersion.toLowerCase() + ) { + found = true; + break; } + } + // Step 3.b: If not found, remove from cache + if (!found) { + Logger.debug(`Removing version with id ${checkVersion} from cache`); + // eslint-disable-next-line no-await-in-loop + await inMemoryCache.del(key); + } } - // Step 4: Loop over database versions and update cache - await Promise.all(prefixCommandVersions.map((dbVersion) => loadSinglePrefixCommandVersionToCache(dbVersion))); + } + // Step 4: Loop over database versions and update cache + await Promise.all(prefixCommandVersions.map((dbVersion) => loadSinglePrefixCommandVersionToCache(dbVersion))); } /** @@ -193,135 +211,150 @@ export async function refreshAllPrefixCommandVersionsCache() { */ export async function clearSinglePrefixCommandCategoryCache(category: IPrefixCommandCategory) { - const inMemoryCache = getInMemoryCache(); - if (!inMemoryCache) return; + const inMemoryCache = getInMemoryCache(); + if (!inMemoryCache) return; - const { name } = category; - Logger.debug(`Clearing cache for command category "${name}"`); - await inMemoryCache.del(`${MemoryCachePrefix.CATEGORY}:${name.toLowerCase()}`); + const { name } = category; + Logger.debug(`Clearing cache for command category "${name}"`); + await inMemoryCache.del(`${MemoryCachePrefix.CATEGORY}:${name.toLowerCase()}`); } export async function loadSinglePrefixCommandCategoryToCache(category: IPrefixCommandCategory) { - const inMemoryCache = getInMemoryCache(); - if (!inMemoryCache) return; + const inMemoryCache = getInMemoryCache(); + if (!inMemoryCache) return; - const { name } = category; - Logger.debug(`Loading category ${name} to cache`); - await inMemoryCache.set(`${MemoryCachePrefix.CATEGORY}:${name.toLowerCase()}`, category.toObject()); + const { name } = category; + Logger.debug(`Loading category ${name} to cache`); + await inMemoryCache.set(`${MemoryCachePrefix.CATEGORY}:${name.toLowerCase()}`, category.toObject()); } export async function loadAllPrefixCommandCategoriesToCache() { - const conn = getConn(); - const inMemoryCache = getInMemoryCache(); - if (!conn || !inMemoryCache) return; + const conn = getConn(); + const inMemoryCache = getInMemoryCache(); + if (!conn || !inMemoryCache) return; - const prefixCommandCategories = await PrefixCommandCategory.find(); - await Promise.all(prefixCommandCategories.map((category) => loadSinglePrefixCommandCategoryToCache(category))); + const prefixCommandCategories = await PrefixCommandCategory.find(); + await Promise.all(prefixCommandCategories.map((category) => loadSinglePrefixCommandCategoryToCache(category))); } -export async function refreshSinglePrefixCommandCategoryCache(oldCategory: IPrefixCommandCategory, newCategory: IPrefixCommandCategory) { - await clearSinglePrefixCommandCategoryCache(oldCategory); - await loadSinglePrefixCommandCategoryToCache(newCategory); +export async function refreshSinglePrefixCommandCategoryCache( + oldCategory: IPrefixCommandCategory, + newCategory: IPrefixCommandCategory, +) { + await clearSinglePrefixCommandCategoryCache(oldCategory); + await loadSinglePrefixCommandCategoryToCache(newCategory); } export async function refreshAllPrefixCommandCategoriesCache() { - const conn = getConn(); - const inMemoryCache = getInMemoryCache(); - if (!conn || !inMemoryCache) return; - - // Step 1: Get all catagories from the database - const prefixCommandCategories = await PrefixCommandCategory.find(); - // Step 2: Get all categories from the cache - const cacheKeys = await inMemoryCache.store.keys(); - // Step 3: Loop over cached categories - for (const key of cacheKeys) { - if (key.startsWith(`${MemoryCachePrefix.CATEGORY}:`)) { - const categoryName = key.split(':')[1]; - // Step 3.a: Check if cached category exists in the database list - let found = false; - for (const dbCategory of prefixCommandCategories) { - const { name: dbCategoryName } = dbCategory; - if (dbCategoryName.toLowerCase() === categoryName.toLowerCase()) { - found = true; - break; - } - } - // Step 3.b: If not found, remove from cache - if (!found) { - Logger.debug(`Removing category ${categoryName} from cache`); - // eslint-disable-next-line no-await-in-loop - await inMemoryCache.del(key); - } + const conn = getConn(); + const inMemoryCache = getInMemoryCache(); + if (!conn || !inMemoryCache) return; + + // Step 1: Get all catagories from the database + const prefixCommandCategories = await PrefixCommandCategory.find(); + // Step 2: Get all categories from the cache + const cacheKeys = await inMemoryCache.store.keys(); + // Step 3: Loop over cached categories + for (const key of cacheKeys) { + if (key.startsWith(`${MemoryCachePrefix.CATEGORY}:`)) { + const categoryName = key.split(':')[1]; + // Step 3.a: Check if cached category exists in the database list + let found = false; + for (const dbCategory of prefixCommandCategories) { + const { name: dbCategoryName } = dbCategory; + if (dbCategoryName.toLowerCase() === categoryName.toLowerCase()) { + found = true; + break; } + } + // Step 3.b: If not found, remove from cache + if (!found) { + Logger.debug(`Removing category ${categoryName} from cache`); + // eslint-disable-next-line no-await-in-loop + await inMemoryCache.del(key); + } } - // Step 4: Loop over database categories and update cache - await Promise.all(prefixCommandCategories.map((dbCategory) => loadSinglePrefixCommandCategoryToCache(dbCategory))); + } + // Step 4: Loop over database categories and update cache + await Promise.all(prefixCommandCategories.map((dbCategory) => loadSinglePrefixCommandCategoryToCache(dbCategory))); } /** * Prefix Command Channel Default Version Cache Management Functions */ -export async function clearSinglePrefixCommandChannelDefaultVersionCache(channelDefaultVersion: IPrefixCommandChannelDefaultVersion) { - const inMemoryCache = getInMemoryCache(); - if (!inMemoryCache) return; +export async function clearSinglePrefixCommandChannelDefaultVersionCache( + channelDefaultVersion: IPrefixCommandChannelDefaultVersion, +) { + const inMemoryCache = getInMemoryCache(); + if (!inMemoryCache) return; - const { channelId } = channelDefaultVersion; - Logger.debug(`Clearing cache for channel default version for channel "${channelId}"`); - await inMemoryCache.del(`${MemoryCachePrefix.CHANNEL_DEFAULT_VERSION}:${channelId}`); + const { channelId } = channelDefaultVersion; + Logger.debug(`Clearing cache for channel default version for channel "${channelId}"`); + await inMemoryCache.del(`${MemoryCachePrefix.CHANNEL_DEFAULT_VERSION}:${channelId}`); } -export async function loadSinglePrefixCommandChannelDefaultVersionToCache(channelDefaultVersion: IPrefixCommandChannelDefaultVersion) { - const inMemoryCache = getInMemoryCache(); - if (!inMemoryCache) return; - - const { channelId, versionId } = channelDefaultVersion; - const version = await PrefixCommandVersion.findById(versionId); - if (version) { - Logger.debug(`Loading default version for channel ${channelId} to cache`); - await inMemoryCache.set(`${MemoryCachePrefix.CHANNEL_DEFAULT_VERSION}:${channelId}`, version.toObject()); - } +export async function loadSinglePrefixCommandChannelDefaultVersionToCache( + channelDefaultVersion: IPrefixCommandChannelDefaultVersion, +) { + const inMemoryCache = getInMemoryCache(); + if (!inMemoryCache) return; + + const { channelId, versionId } = channelDefaultVersion; + const version = await PrefixCommandVersion.findById(versionId); + if (version) { + Logger.debug(`Loading default version for channel ${channelId} to cache`); + await inMemoryCache.set(`${MemoryCachePrefix.CHANNEL_DEFAULT_VERSION}:${channelId}`, version.toObject()); + } } export async function loadAllPrefixCommandChannelDefaultVersionsToCache() { - const conn = getConn(); - const inMemoryCache = getInMemoryCache(); - if (!conn || !inMemoryCache) return; - - const PrefixCommandChannelDefaultVersions = await PrefixCommandChannelDefaultVersion.find(); - await Promise.all(PrefixCommandChannelDefaultVersions.map((channelDefaultVersion) => loadSinglePrefixCommandChannelDefaultVersionToCache(channelDefaultVersion))); + const conn = getConn(); + const inMemoryCache = getInMemoryCache(); + if (!conn || !inMemoryCache) return; + + const PrefixCommandChannelDefaultVersions = await PrefixCommandChannelDefaultVersion.find(); + await Promise.all( + PrefixCommandChannelDefaultVersions.map((channelDefaultVersion) => + loadSinglePrefixCommandChannelDefaultVersionToCache(channelDefaultVersion), + ), + ); } export async function refreshAllPrefixCommandChannelDefaultVersionsCache() { - const conn = getConn(); - const inMemoryCache = getInMemoryCache(); - if (!conn || !inMemoryCache) return; - - // Step 1: Get all channel default versions from the database - const prefixCommandChannelDefaultVersions = await PrefixCommandChannelDefaultVersion.find(); - // Step 2: Get all channel default versions from the cache - const cacheKeys = await inMemoryCache.store.keys(); - // Step 3: Loop over cached channel default versions - for (const key of cacheKeys) { - if (key.startsWith(`${MemoryCachePrefix.CHANNEL_DEFAULT_VERSION}:`)) { - const channelId = key.split(':')[1]; - // Step 3.a: Check if cached channel default version exists in the database list - let found = false; - for (const dbChannelDefaultVersion of prefixCommandChannelDefaultVersions) { - const { channelId: dbChannelId } = dbChannelDefaultVersion; - if (dbChannelId.toString().toLowerCase() === channelId.toLowerCase()) { - found = true; - break; - } - } - // Step 3.b: If not found, remove from cache - if (!found) { - Logger.debug(`Removing channel default version for channel ${channelId} from cache`); - // eslint-disable-next-line no-await-in-loop - await inMemoryCache.del(key); - } + const conn = getConn(); + const inMemoryCache = getInMemoryCache(); + if (!conn || !inMemoryCache) return; + + // Step 1: Get all channel default versions from the database + const prefixCommandChannelDefaultVersions = await PrefixCommandChannelDefaultVersion.find(); + // Step 2: Get all channel default versions from the cache + const cacheKeys = await inMemoryCache.store.keys(); + // Step 3: Loop over cached channel default versions + for (const key of cacheKeys) { + if (key.startsWith(`${MemoryCachePrefix.CHANNEL_DEFAULT_VERSION}:`)) { + const channelId = key.split(':')[1]; + // Step 3.a: Check if cached channel default version exists in the database list + let found = false; + for (const dbChannelDefaultVersion of prefixCommandChannelDefaultVersions) { + const { channelId: dbChannelId } = dbChannelDefaultVersion; + if (dbChannelId.toString().toLowerCase() === channelId.toLowerCase()) { + found = true; + break; } + } + // Step 3.b: If not found, remove from cache + if (!found) { + Logger.debug(`Removing channel default version for channel ${channelId} from cache`); + // eslint-disable-next-line no-await-in-loop + await inMemoryCache.del(key); + } } - // Step 4: Loop over database channel default versions and update cache - await Promise.all(prefixCommandChannelDefaultVersions.map((dbChannelDefaultVersion) => loadSinglePrefixCommandChannelDefaultVersionToCache(dbChannelDefaultVersion))); + } + // Step 4: Loop over database channel default versions and update cache + await Promise.all( + prefixCommandChannelDefaultVersions.map((dbChannelDefaultVersion) => + loadSinglePrefixCommandChannelDefaultVersionToCache(dbChannelDefaultVersion), + ), + ); } diff --git a/src/lib/schedulerJobs/refreshInMemoryCache.ts b/src/lib/schedulerJobs/refreshInMemoryCache.ts index 3c4462f4..ad4fcd31 100644 --- a/src/lib/schedulerJobs/refreshInMemoryCache.ts +++ b/src/lib/schedulerJobs/refreshInMemoryCache.ts @@ -1,38 +1,46 @@ import { Job } from '@hokify/agenda'; -import { Logger, getInMemoryCache, getScheduler, refreshAllPrefixCommandCategoriesCache, refreshAllPrefixCommandChannelDefaultVersionsCache, refreshAllPrefixCommandVersionsCache, refreshAllPrefixCommandsCache } from '../index'; +import { + Logger, + getInMemoryCache, + getScheduler, + refreshAllPrefixCommandCategoriesCache, + refreshAllPrefixCommandChannelDefaultVersionsCache, + refreshAllPrefixCommandVersionsCache, + refreshAllPrefixCommandsCache, +} from '../index'; export async function refreshInMemoryCache(job: Job) { - const scheduler = getScheduler(); - if (!scheduler) { - Logger.error('Failed to get scheduler instance'); - return; - } + const scheduler = getScheduler(); + if (!scheduler) { + Logger.error('Failed to get scheduler instance'); + return; + } - const inMemoryCache = getInMemoryCache(); - if (!inMemoryCache) { - Logger.error('Failed to get in-memory cache instance'); - return; - } + const inMemoryCache = getInMemoryCache(); + if (!inMemoryCache) { + Logger.error('Failed to get in-memory cache instance'); + return; + } - // Needed because of https://github.com/agenda/agenda/issues/401 - // eslint-disable-next-line no-underscore-dangle - const matchingJobs = await scheduler.jobs({ _id: job.attrs._id }); - if (matchingJobs.length !== 1) { - Logger.debug('Job has been deleted already, skipping execution.'); - return; - } + // Needed because of https://github.com/agenda/agenda/issues/401 + // eslint-disable-next-line no-underscore-dangle + const matchingJobs = await scheduler.jobs({ _id: job.attrs._id }); + if (matchingJobs.length !== 1) { + Logger.debug('Job has been deleted already, skipping execution.'); + return; + } - const start = new Date().getTime(); - try { - await Promise.all([ - refreshAllPrefixCommandVersionsCache(), - refreshAllPrefixCommandCategoriesCache(), - refreshAllPrefixCommandsCache(), - refreshAllPrefixCommandChannelDefaultVersionsCache(), - ]); - } catch (error) { - Logger.error('Failed to refresh the in memory cache:', error); - } - const duration = ((new Date().getTime() - start) / 1000).toFixed(2); - Logger.info(`In memory cache refreshed successfully, duration: ${duration}s`); + const start = new Date().getTime(); + try { + await Promise.all([ + refreshAllPrefixCommandVersionsCache(), + refreshAllPrefixCommandCategoriesCache(), + refreshAllPrefixCommandsCache(), + refreshAllPrefixCommandChannelDefaultVersionsCache(), + ]); + } catch (error) { + Logger.error('Failed to refresh the in memory cache:', error); + } + const duration = ((new Date().getTime() - start) / 1000).toFixed(2); + Logger.info(`In memory cache refreshed successfully, duration: ${duration}s`); } diff --git a/src/lib/schemas/prefixCommandSchemas.ts b/src/lib/schemas/prefixCommandSchemas.ts index c4dee8b5..3ccf06c6 100644 --- a/src/lib/schemas/prefixCommandSchemas.ts +++ b/src/lib/schemas/prefixCommandSchemas.ts @@ -1,136 +1,145 @@ import mongoose, { Schema, Document } from 'mongoose'; export interface IPrefixCommandCategory extends Document { - categoryId: mongoose.Schema.Types.ObjectId; - name: string; - emoji: string; + categoryId: mongoose.Schema.Types.ObjectId; + name: string; + emoji: string; } const prefixCommandCategorySchema = new Schema({ - categoryId: mongoose.Schema.Types.ObjectId, - name: { - type: String, - required: true, - unique: true, - }, - emoji: String, + categoryId: mongoose.Schema.Types.ObjectId, + name: { + type: String, + required: true, + unique: true, + }, + emoji: String, }); export interface IPrefixCommandVersion extends Document { - versionId: mongoose.Schema.Types.ObjectId; - name: string; - emoji: string; - alias: string; - enabled: boolean; + versionId: mongoose.Schema.Types.ObjectId; + name: string; + emoji: string; + alias: string; + enabled: boolean; } const prefixCommandVersionSchema = new Schema({ - versionId: mongoose.Schema.Types.ObjectId, - name: { - type: String, - required: true, - unique: true, - }, - emoji: { - type: String, - required: true, - unique: true, - }, - alias: { - type: String, - required: true, - unique: true, - }, - enabled: Boolean, + versionId: mongoose.Schema.Types.ObjectId, + name: { + type: String, + required: true, + unique: true, + }, + emoji: { + type: String, + required: true, + unique: true, + }, + alias: { + type: String, + required: true, + unique: true, + }, + enabled: Boolean, }); export interface IPrefixCommandChannelDefaultVersion extends Document { - channelId: string; - versionId: string; + channelId: string; + versionId: string; } const prefixCommandChannelDefaultVersionSchema = new Schema({ - channelId: { - type: String, - required: true, - unique: true, - }, - versionId: { - type: String, - required: true, - }, + channelId: { + type: String, + required: true, + unique: true, + }, + versionId: { + type: String, + required: true, + }, }); -export interface IPrefixCommandContent extends Document{ - versionId: string; - title: string; - content?: string; - image?: string; +export interface IPrefixCommandContent extends Document { + versionId: string; + title: string; + content?: string; + image?: string; } -const prefixCommandContentSchema = new Schema({ +const prefixCommandContentSchema = new Schema( + { versionId: { - type: String, - required: true, + type: String, + required: true, }, title: String, content: String, image: String, -}, { autoCreate: false }); + }, + { autoCreate: false }, +); export interface IPrefixCommandPermissions extends Document { - roles?: string[], - rolesBlocklist?: boolean, - channels?: string[], - channelsBlocklist?: boolean, - quietErrors?: boolean, - verboseErrors?: boolean, + roles?: string[]; + rolesBlocklist?: boolean; + channels?: string[]; + channelsBlocklist?: boolean; + quietErrors?: boolean; + verboseErrors?: boolean; } -const prefixCommandPermissionsSchema = new Schema({ +const prefixCommandPermissionsSchema = new Schema( + { roles: [String], rolesBlocklist: Boolean, channels: [String], channelsBlocklist: Boolean, quietErrors: Boolean, verboseErrors: Boolean, -}, { autoCreate: false }); + }, + { autoCreate: false }, +); export interface IPrefixCommand extends Document { - commandId: mongoose.Schema.Types.ObjectId; - categoryId: mongoose.Schema.Types.ObjectId; - name: string; - description: string; - aliases: string[]; - isEmbed: boolean; - embedColor?: string; - contents: IPrefixCommandContent[]; - permissions: IPrefixCommandPermissions; + commandId: mongoose.Schema.Types.ObjectId; + categoryId: mongoose.Schema.Types.ObjectId; + name: string; + description: string; + aliases: string[]; + isEmbed: boolean; + embedColor?: string; + contents: IPrefixCommandContent[]; + permissions: IPrefixCommandPermissions; } const prefixCommandSchema = new Schema({ - commandId: mongoose.Schema.Types.ObjectId, - categoryId: { - type: mongoose.Schema.Types.ObjectId, - ref: 'PrefixCommandCategory', - required: true, - }, - name: { - type: String, - required: true, - unique: true, - }, - description: String, - aliases: [{ type: String }], - isEmbed: Boolean, - embedColor: String, - contents: [prefixCommandContentSchema], - permissions: prefixCommandPermissionsSchema, + commandId: mongoose.Schema.Types.ObjectId, + categoryId: { + type: mongoose.Schema.Types.ObjectId, + ref: 'PrefixCommandCategory', + required: true, + }, + name: { + type: String, + required: true, + unique: true, + }, + description: String, + aliases: [{ type: String }], + isEmbed: Boolean, + embedColor: String, + contents: [prefixCommandContentSchema], + permissions: prefixCommandPermissionsSchema, }); export const PrefixCommandCategory = mongoose.model('PrefixCommandCategory', prefixCommandCategorySchema); export const PrefixCommandVersion = mongoose.model('PrefixCommandVersion', prefixCommandVersionSchema); export const PrefixCommandContent = mongoose.model('PrefixCommandContent', prefixCommandContentSchema); export const PrefixCommandPermissions = mongoose.model('PrefixCommandPermissions', prefixCommandPermissionsSchema); -export const PrefixCommandChannelDefaultVersion = mongoose.model('PrefixCommandChannelDefaultVersion', prefixCommandChannelDefaultVersionSchema); +export const PrefixCommandChannelDefaultVersion = mongoose.model( + 'PrefixCommandChannelDefaultVersion', + prefixCommandChannelDefaultVersionSchema, +); export const PrefixCommand = mongoose.model('PrefixCommand', prefixCommandSchema); From 3ecbac2230da9c7a7f2823d75ae612c039c89d2f Mon Sep 17 00:00:00 2001 From: ExampleWasTaken <58574351+ExampleWasTaken@users.noreply.github.com> Date: Thu, 31 Oct 2024 13:07:20 +0100 Subject: [PATCH 77/82] partial prefix cmd lint fix --- eslint.config.mjs | 8 +++++--- .../functions/addChannelPermission.ts | 6 +++--- .../prefixCommands/functions/addCommand.ts | 2 +- .../functions/addRolePermission.ts | 6 +++--- .../prefixCommands/functions/addVersion.ts | 6 +++--- .../functions/deleteCategory.ts | 6 +++--- .../functions/deleteChannelDefaultVersion.ts | 6 +++--- .../prefixCommands/functions/deleteCommand.ts | 6 +++--- .../prefixCommands/functions/deleteContent.ts | 6 +++--- .../prefixCommands/functions/deleteVersion.ts | 6 +++--- .../functions/listCategories.ts | 2 +- .../prefixCommands/functions/listCommands.ts | 2 +- .../prefixCommands/functions/listVersions.ts | 2 +- .../functions/modifyCategory.ts | 6 +++--- .../prefixCommands/functions/modifyCommand.ts | 6 +++--- .../prefixCommands/functions/modifyVersion.ts | 6 +++--- .../functions/removeChannelPermission.ts | 6 +++--- .../functions/removeRolePermission.ts | 6 +++--- .../functions/setChannelDefaultVersion.ts | 8 +++----- .../functions/setCommandPermissionSettings.ts | 6 +++--- .../prefixCommands/functions/setContent.ts | 10 ++++++---- .../functions/showChannelDefaultVersion.ts | 5 ++++- .../prefixCommandCacheUpdate.ts | 8 +++++--- .../prefixCommandPermissions.ts | 3 ++- .../prefixCommands/prefixCommands.ts | 9 ++++++--- src/events/ready.ts | 20 ++++++++----------- src/lib/schedulerJobs/refreshInMemoryCache.ts | 1 - src/lib/schemas/prefixCommandSchemas.ts | 2 +- 28 files changed, 86 insertions(+), 80 deletions(-) diff --git a/eslint.config.mjs b/eslint.config.mjs index 971a5faa..e378eae1 100644 --- a/eslint.config.mjs +++ b/eslint.config.mjs @@ -23,14 +23,16 @@ export default tseslint.config( { varsIgnorePattern: '^_', argsIgnorePattern: '^_', + caughtErrorsIgnorePattern: '^_', + destructuredArrayIgnorePattern: '^_', }, ], // The rules below are proposed to best leverage eslint's capabilities and reduce work during code review. 'no-await-in-loop': 'error', // possible performance impact - see: https://eslint.org/docs/latest/rules/no-await-in-loop - 'no-constructor-return': 'error', // Returing values from constructors is bad practice and can be confusing as constructors always return the object they instantiated (this). - 'no-self-compare': 'error', // Saves time during code review .(https://eslint.org/docs/latest/rules/no-self-compare) - 'no-unreachable-loop': 'error', // Saves time during code review by preventing unecessary one-time-loops. (https://eslint.org/docs/latest/rules/no-unreachable-loop) + 'no-constructor-return': 'error', // Returning values from constructors is bad practice and can be confusing as constructors always return the object they instantiated (this). + 'no-self-compare': 'error', // Saves time during code review. (https://eslint.org/docs/latest/rules/no-self-compare) + 'no-unreachable-loop': 'error', // Saves time during code review by preventing unnecessary one-time-loops. (https://eslint.org/docs/latest/rules/no-unreachable-loop) 'no-console': 'warn', // Using winston should be preferred over direct console.log statements. }, }, diff --git a/src/commands/moderation/prefixCommands/functions/addChannelPermission.ts b/src/commands/moderation/prefixCommands/functions/addChannelPermission.ts index 6d388787..9c92537b 100644 --- a/src/commands/moderation/prefixCommands/functions/addChannelPermission.ts +++ b/src/commands/moderation/prefixCommands/functions/addChannelPermission.ts @@ -55,7 +55,7 @@ const modLogEmbed = (moderator: User, command: string, channel: string) => }, { name: 'Moderator', - value: `${moderator}`, + value: `${moderator.toString()}`, }, ], color: Colors.Green, @@ -112,11 +112,11 @@ export async function handleAddPrefixCommandChannelPermission(interaction: ChatI try { await modLogsChannel.send({ embeds: [modLogEmbed(moderator, command, channelId)] }); } catch (error) { - Logger.error(`Failed to post a message to the mod logs channel: ${error}`); + Logger.error('Failed to post a message to the mod logs channel:', error); } } } catch (error) { - Logger.error(`Failed to add prefix command channel <#${channel}> for command ${command}: ${error}`); + Logger.error(`Failed to add prefix command channel <#${channel.id}> for command ${command}:`, error); await interaction.followUp({ embeds: [failedEmbed(command, channelId)], ephemeral: true }); } } else { diff --git a/src/commands/moderation/prefixCommands/functions/addCommand.ts b/src/commands/moderation/prefixCommands/functions/addCommand.ts index ddd33a68..57795e79 100644 --- a/src/commands/moderation/prefixCommands/functions/addCommand.ts +++ b/src/commands/moderation/prefixCommands/functions/addCommand.ts @@ -68,7 +68,7 @@ const modLogEmbed = ( }, { name: 'Moderator', - value: `${moderator}`, + value: `${moderator.toString()}`, }, { name: 'Aliases', diff --git a/src/commands/moderation/prefixCommands/functions/addRolePermission.ts b/src/commands/moderation/prefixCommands/functions/addRolePermission.ts index a40682c0..458c9ab5 100644 --- a/src/commands/moderation/prefixCommands/functions/addRolePermission.ts +++ b/src/commands/moderation/prefixCommands/functions/addRolePermission.ts @@ -55,7 +55,7 @@ const modLogEmbed = (moderator: User, command: string, roleName: string) => }, { name: 'Moderator', - value: `${moderator}`, + value: `${moderator.toString()}`, }, ], color: Colors.Green, @@ -112,11 +112,11 @@ export async function handleAddPrefixCommandRolePermission(interaction: ChatInpu try { await modLogsChannel.send({ embeds: [modLogEmbed(moderator, command, roleName)] }); } catch (error) { - Logger.error(`Failed to post a message to the mod logs role: ${error}`); + Logger.error('Failed to post a message to the mod logs role:', error); } } } catch (error) { - Logger.error(`Failed to add prefix command role ${roleName} for command ${command}: ${error}`); + Logger.error(`Failed to add prefix command role ${roleName} for command ${command}:`, error); await interaction.followUp({ embeds: [failedEmbed(command, roleName)], ephemeral: true }); } } else { diff --git a/src/commands/moderation/prefixCommands/functions/addVersion.ts b/src/commands/moderation/prefixCommands/functions/addVersion.ts index 85dd623b..2922e79e 100644 --- a/src/commands/moderation/prefixCommands/functions/addVersion.ts +++ b/src/commands/moderation/prefixCommands/functions/addVersion.ts @@ -59,7 +59,7 @@ const modLogEmbed = ( }, { name: 'Moderator', - value: `${moderator}`, + value: `${moderator.toString()}`, }, { name: 'Emoji', @@ -154,11 +154,11 @@ export async function handleAddPrefixCommandVersion(interaction: ChatInputComman embeds: [modLogEmbed(moderator, name, emoji, alias, enabled, prefixCommandVersion.id)], }); } catch (error) { - Logger.error(`Failed to post a message to the mod logs channel: ${error}`); + Logger.error('Failed to post a message to the mod logs channel:', error); } } } catch (error) { - Logger.error(`Failed to add a prefix command category ${name}: ${error}`); + Logger.error(`Failed to add a prefix command category ${name}:`, error); await interaction.followUp({ embeds: [failedEmbed(name)], ephemeral: true }); } } diff --git a/src/commands/moderation/prefixCommands/functions/deleteCategory.ts b/src/commands/moderation/prefixCommands/functions/deleteCategory.ts index f564c7ce..09fe259c 100644 --- a/src/commands/moderation/prefixCommands/functions/deleteCategory.ts +++ b/src/commands/moderation/prefixCommands/functions/deleteCategory.ts @@ -44,7 +44,7 @@ const modLogEmbed = (moderator: User, category: string, emoji: string, categoryI }, { name: 'Moderator', - value: `${moderator}`, + value: `${moderator.toString()}`, }, { name: 'Emoji', @@ -92,11 +92,11 @@ export async function handleDeletePrefixCommandCategory(interaction: ChatInputCo try { await modLogsChannel.send({ embeds: [modLogEmbed(moderator, name || '', emoji || '', categoryId)] }); } catch (error) { - Logger.error(`Failed to post a message to the mod logs channel: ${error}`); + Logger.error('Failed to post a message to the mod logs channel:', error); } } } catch (error) { - Logger.error(`Failed to delete a prefix command category with id ${categoryId}: ${error}`); + Logger.error(`Failed to delete a prefix command category with id ${categoryId}:`, error); await interaction.followUp({ embeds: [failedEmbed(categoryId)], ephemeral: true }); } } else { diff --git a/src/commands/moderation/prefixCommands/functions/deleteChannelDefaultVersion.ts b/src/commands/moderation/prefixCommands/functions/deleteChannelDefaultVersion.ts index 807eddb8..854b1033 100644 --- a/src/commands/moderation/prefixCommands/functions/deleteChannelDefaultVersion.ts +++ b/src/commands/moderation/prefixCommands/functions/deleteChannelDefaultVersion.ts @@ -44,7 +44,7 @@ const modLogEmbed = (moderator: User, channel: string) => }, { name: 'Moderator', - value: `${moderator}`, + value: `${moderator.toString()}`, }, ], color: Colors.Red, @@ -89,11 +89,11 @@ export async function handleDeletePrefixCommandChannelDefaultVersion( try { await modLogsChannel.send({ embeds: [modLogEmbed(moderator, channelName)] }); } catch (error) { - Logger.error(`Failed to post a message to the mod logs channel: ${error}`); + Logger.error('Failed to post a message to the mod logs channel:', error); } } } catch (error) { - Logger.error(`Failed to unset a default channel version for channel ${channelName}: ${error}`); + Logger.error(`Failed to unset a default channel version for channel ${channelName}:`, error); await interaction.followUp({ embeds: [failedEmbed(channelName)], ephemeral: true }); } } else { diff --git a/src/commands/moderation/prefixCommands/functions/deleteCommand.ts b/src/commands/moderation/prefixCommands/functions/deleteCommand.ts index 31135bb4..4f9a185a 100644 --- a/src/commands/moderation/prefixCommands/functions/deleteCommand.ts +++ b/src/commands/moderation/prefixCommands/functions/deleteCommand.ts @@ -52,7 +52,7 @@ const modLogEmbed = ( }, { name: 'Moderator', - value: `${moderator}`, + value: `${moderator.toString()}`, }, { name: 'Aliases', @@ -116,11 +116,11 @@ export async function handleDeletePrefixCommand(interaction: ChatInputCommandInt ], }); } catch (error) { - Logger.error(`Failed to post a message to the mod logs channel: ${error}`); + Logger.error('Failed to post a message to the mod logs channel:', error); } } } catch (error) { - Logger.error(`Failed to delete a prefix command command with id ${commandId}: ${error}`); + Logger.error(`Failed to delete a prefix command command with id ${commandId}:`, error); await interaction.followUp({ embeds: [failedEmbed(commandId)], ephemeral: true }); } } else { diff --git a/src/commands/moderation/prefixCommands/functions/deleteContent.ts b/src/commands/moderation/prefixCommands/functions/deleteContent.ts index c33f5a99..56843531 100644 --- a/src/commands/moderation/prefixCommands/functions/deleteContent.ts +++ b/src/commands/moderation/prefixCommands/functions/deleteContent.ts @@ -82,7 +82,7 @@ const modLogEmbed = ( }, { name: 'Moderator', - value: `${moderator}`, + value: `${moderator.toString()}`, }, ], color: Colors.Red, @@ -158,11 +158,11 @@ export async function handleDeletePrefixCommandContent(interaction: ChatInputCom embeds: [modLogEmbed(moderator, `${commandName}`, `${versionName}`, `${title}`, `${content}`, `${image}`)], }); } catch (error) { - Logger.error(`Failed to post a message to the mod logs channel: ${error}`); + Logger.error('Failed to post a message to the mod logs channel:', error); } } } catch (error) { - Logger.error(`Failed to delete a prefix command content with version ${version}: ${error}`); + Logger.error(`Failed to delete a prefix command content with version ${version}:`, error); await interaction.followUp({ embeds: [failedEmbed(version)], ephemeral: true }); } } else { diff --git a/src/commands/moderation/prefixCommands/functions/deleteVersion.ts b/src/commands/moderation/prefixCommands/functions/deleteVersion.ts index 9e1eb26b..d494ddfb 100644 --- a/src/commands/moderation/prefixCommands/functions/deleteVersion.ts +++ b/src/commands/moderation/prefixCommands/functions/deleteVersion.ts @@ -69,7 +69,7 @@ const modLogEmbed = ( }, { name: 'Moderator', - value: `${moderator}`, + value: `${moderator.toString()}`, }, { name: 'Emoji', @@ -167,11 +167,11 @@ export async function handleDeletePrefixCommandVersion(interaction: ChatInputCom embeds: [modLogEmbed(moderator, name || '', emoji || '', alias || '', enabled || false, versionId)], }); } catch (error) { - Logger.error(`Failed to post a message to the mod logs channel: ${error}`); + Logger.error('Failed to post a message to the mod logs channel:', error); } } } catch (error) { - Logger.error(`Failed to delete a prefix command version with id ${versionId}: ${error}`); + Logger.error(`Failed to delete a prefix command version with id ${versionId}:`, error); await interaction.followUp({ embeds: [failedEmbed(versionId)], ephemeral: true }); } } else { diff --git a/src/commands/moderation/prefixCommands/functions/listCategories.ts b/src/commands/moderation/prefixCommands/functions/listCategories.ts index 0a74a503..46c12f8b 100644 --- a/src/commands/moderation/prefixCommands/functions/listCategories.ts +++ b/src/commands/moderation/prefixCommands/functions/listCategories.ts @@ -53,7 +53,7 @@ export async function handleListPrefixCommandCategories(interaction: ChatInputCo try { await interaction.followUp({ embeds: [successEmbed(searchText, embedFields)], ephemeral: false }); } catch (error) { - Logger.error(`Failed to list prefix command categories with search ${searchText}: ${error}`); + Logger.error(`Failed to list prefix command categories with search ${searchText}:`, error); await interaction.followUp({ embeds: [failedEmbed(searchText)], ephemeral: true }); } } else { diff --git a/src/commands/moderation/prefixCommands/functions/listCommands.ts b/src/commands/moderation/prefixCommands/functions/listCommands.ts index 34848205..d03e717e 100644 --- a/src/commands/moderation/prefixCommands/functions/listCommands.ts +++ b/src/commands/moderation/prefixCommands/functions/listCommands.ts @@ -53,7 +53,7 @@ export async function handleListPrefixCommands(interaction: ChatInputCommandInte try { await interaction.followUp({ embeds: [successEmbed(searchText, embedFields)], ephemeral: false }); } catch (error) { - Logger.error(`Failed to list prefix command commands with search ${searchText}: ${error}`); + Logger.error(`Failed to list prefix command commands with search ${searchText}:`, error); await interaction.followUp({ embeds: [failedEmbed(searchText)], ephemeral: true }); } } else { diff --git a/src/commands/moderation/prefixCommands/functions/listVersions.ts b/src/commands/moderation/prefixCommands/functions/listVersions.ts index 922daf5f..12d3e31e 100644 --- a/src/commands/moderation/prefixCommands/functions/listVersions.ts +++ b/src/commands/moderation/prefixCommands/functions/listVersions.ts @@ -53,7 +53,7 @@ export async function handleListPrefixCommandVersions(interaction: ChatInputComm try { await interaction.followUp({ embeds: [successEmbed(searchText, embedFields)], ephemeral: false }); } catch (error) { - Logger.error(`Failed to list prefix command versions with search ${searchText}: ${error}`); + Logger.error(`Failed to list prefix command versions with search ${searchText}:`, error); await interaction.followUp({ embeds: [failedEmbed(searchText)], ephemeral: true }); } } else { diff --git a/src/commands/moderation/prefixCommands/functions/modifyCategory.ts b/src/commands/moderation/prefixCommands/functions/modifyCategory.ts index 972c49fc..93adc2b8 100644 --- a/src/commands/moderation/prefixCommands/functions/modifyCategory.ts +++ b/src/commands/moderation/prefixCommands/functions/modifyCategory.ts @@ -44,7 +44,7 @@ const modLogEmbed = (moderator: User, category: string, emoji: string, categoryI }, { name: 'Moderator', - value: `${moderator}`, + value: `${moderator.toString()}`, }, { name: 'Emoji', @@ -98,11 +98,11 @@ export async function handleModifyPrefixCommandCategory(interaction: ChatInputCo try { await modLogsChannel.send({ embeds: [modLogEmbed(moderator, name, emoji || '', categoryId)] }); } catch (error) { - Logger.error(`Failed to post a message to the mod logs channel: ${error}`); + Logger.error(`Failed to post a message to the mod logs channel:`, error); } } } catch (error) { - Logger.error(`Failed to modify a prefix command category with id ${categoryId}: ${error}`); + Logger.error(`Failed to modify a prefix command category with id ${categoryId}:`, error); await interaction.followUp({ embeds: [failedEmbed(categoryId)], ephemeral: true }); } } else { diff --git a/src/commands/moderation/prefixCommands/functions/modifyCommand.ts b/src/commands/moderation/prefixCommands/functions/modifyCommand.ts index 53a05fe9..543a6628 100644 --- a/src/commands/moderation/prefixCommands/functions/modifyCommand.ts +++ b/src/commands/moderation/prefixCommands/functions/modifyCommand.ts @@ -75,7 +75,7 @@ const modLogEmbed = ( }, { name: 'Moderator', - value: `${moderator}`, + value: `${moderator.toString()}`, }, { name: 'Aliases', @@ -237,11 +237,11 @@ export async function handleModifyPrefixCommand(interaction: ChatInputCommandInt ], }); } catch (error) { - Logger.error(`Failed to post a message to the mod logs channel: ${error}`); + Logger.error(`Failed to post a message to the mod logs channel:`, error); } } } catch (error) { - Logger.error(`Failed to modify a prefix command command with id ${commandId}: ${error}`); + Logger.error(`Failed to modify a prefix command command with id ${commandId}:`, error); await interaction.followUp({ embeds: [failedEmbed(commandId)], ephemeral: true }); } } else { diff --git a/src/commands/moderation/prefixCommands/functions/modifyVersion.ts b/src/commands/moderation/prefixCommands/functions/modifyVersion.ts index 7eac49e5..869474f4 100644 --- a/src/commands/moderation/prefixCommands/functions/modifyVersion.ts +++ b/src/commands/moderation/prefixCommands/functions/modifyVersion.ts @@ -66,7 +66,7 @@ const modLogEmbed = ( }, { name: 'Moderator', - value: `${moderator}`, + value: `${moderator.toString()}`, }, { name: 'Emoji', @@ -182,11 +182,11 @@ export async function handleModifyPrefixCommandVersion(interaction: ChatInputCom embeds: [modLogEmbed(moderator, name, emoji, alias, enabled || false, versionId)], }); } catch (error) { - Logger.error(`Failed to post a message to the mod logs channel: ${error}`); + Logger.error(`Failed to post a message to the mod logs channel:`, error); } } } catch (error) { - Logger.error(`Failed to modify a prefix command version with id ${versionId}: ${error}`); + Logger.error(`Failed to modify a prefix command version with id ${versionId}:`, error); await interaction.followUp({ embeds: [failedEmbed(versionId)], ephemeral: true }); } } else { diff --git a/src/commands/moderation/prefixCommands/functions/removeChannelPermission.ts b/src/commands/moderation/prefixCommands/functions/removeChannelPermission.ts index 7a7444cb..ee97fa3e 100644 --- a/src/commands/moderation/prefixCommands/functions/removeChannelPermission.ts +++ b/src/commands/moderation/prefixCommands/functions/removeChannelPermission.ts @@ -55,7 +55,7 @@ const modLogEmbed = (moderator: User, command: string, channel: string) => }, { name: 'Moderator', - value: `${moderator}`, + value: `${moderator.toString()}`, }, ], color: Colors.Red, @@ -109,11 +109,11 @@ export async function handleRemovePrefixCommandChannelPermission(interaction: Ch try { await modLogsChannel.send({ embeds: [modLogEmbed(moderator, command, channelId)] }); } catch (error) { - Logger.error(`Failed to post a message to the mod logs channel: ${error}`); + Logger.error(`Failed to post a message to the mod logs channel:`, error); } } } catch (error) { - Logger.error(`Failed to remove prefix command channel <#${channel}> for command ${command}: ${error}`); + Logger.error(`Failed to remove prefix command channel <#${channel.id}> for command ${command}`, error); await interaction.followUp({ embeds: [failedEmbed(command, channelId)], ephemeral: true }); } } else { diff --git a/src/commands/moderation/prefixCommands/functions/removeRolePermission.ts b/src/commands/moderation/prefixCommands/functions/removeRolePermission.ts index fcbfa5c2..b6157ac0 100644 --- a/src/commands/moderation/prefixCommands/functions/removeRolePermission.ts +++ b/src/commands/moderation/prefixCommands/functions/removeRolePermission.ts @@ -55,7 +55,7 @@ const modLogEmbed = (moderator: User, command: string, roleName: string) => }, { name: 'Moderator', - value: `${moderator}`, + value: `${moderator.toString()}`, }, ], color: Colors.Green, @@ -109,11 +109,11 @@ export async function handleRemovePrefixCommandRolePermission(interaction: ChatI try { await modLogsChannel.send({ embeds: [modLogEmbed(moderator, command, roleName)] }); } catch (error) { - Logger.error(`Failed to post a message to the mod logs role: ${error}`); + Logger.error(`Failed to post a message to the mod logs role:`, error); } } } catch (error) { - Logger.error(`Failed to remove prefix command role ${roleName} for command ${command}: ${error}`); + Logger.error(`Failed to remove prefix command role ${roleName} for command ${command}:`, error); await interaction.followUp({ embeds: [failedEmbed(command, roleName)], ephemeral: true }); } } else { diff --git a/src/commands/moderation/prefixCommands/functions/setChannelDefaultVersion.ts b/src/commands/moderation/prefixCommands/functions/setChannelDefaultVersion.ts index 48ef9979..9e123471 100644 --- a/src/commands/moderation/prefixCommands/functions/setChannelDefaultVersion.ts +++ b/src/commands/moderation/prefixCommands/functions/setChannelDefaultVersion.ts @@ -49,7 +49,7 @@ const modLogEmbed = (moderator: User, channel: string, version: string, emoji: s }, { name: 'Moderator', - value: `${moderator}`, + value: `${moderator.toString()}`, }, ], color: Colors.Green, @@ -109,13 +109,11 @@ export async function handleSetPrefixCommandChannelDefaultVersion(interaction: C try { await modLogsChannel.send({ embeds: [modLogEmbed(moderator, channelName, version, emoji)] }); } catch (error) { - Logger.error(`Failed to post a message to the mod logs channel: ${error}`); + Logger.error(`Failed to post a message to the mod logs channel:`, error); } } } catch (error) { - Logger.error( - `Failed to set the default channel version for channel ${channelName} to version ${version}: ${error}`, - ); + Logger.error(`Failed to set the default channel version for channel ${channelName} to version ${version}`, error); await interaction.followUp({ embeds: [failedEmbed(channelName)], ephemeral: true }); } } else { diff --git a/src/commands/moderation/prefixCommands/functions/setCommandPermissionSettings.ts b/src/commands/moderation/prefixCommands/functions/setCommandPermissionSettings.ts index 110babfb..c2ce32e6 100644 --- a/src/commands/moderation/prefixCommands/functions/setCommandPermissionSettings.ts +++ b/src/commands/moderation/prefixCommands/functions/setCommandPermissionSettings.ts @@ -68,7 +68,7 @@ const modLogEmbed = ( }, { name: 'Moderator', - value: `${moderator}`, + value: `${moderator.toString()}`, }, ], color: Colors.Green, @@ -131,11 +131,11 @@ export async function handleSetPrefixCommandPermissionSettings(interaction: Chat embeds: [modLogEmbed(moderator, command, rolesBlocklist, channelsBlocklist, quietErrors, verboseErrors)], }); } catch (error) { - Logger.error(`Failed to post a message to the mod logs channel: ${error}`); + Logger.error('Failed to post a message to the mod logs channel:', error); } } } catch (error) { - Logger.error(`Failed to set the permission settings for command ${command}: ${error}`); + Logger.error(`Failed to set the permission settings for command ${command}:`, error); await interaction.followUp({ embeds: [failedEmbed(command)], ephemeral: true }); } } else { diff --git a/src/commands/moderation/prefixCommands/functions/setContent.ts b/src/commands/moderation/prefixCommands/functions/setContent.ts index 9377b7b6..bbb65040 100644 --- a/src/commands/moderation/prefixCommands/functions/setContent.ts +++ b/src/commands/moderation/prefixCommands/functions/setContent.ts @@ -87,7 +87,7 @@ const modLogEmbed = ( }, { name: 'Moderator', - value: `${moderator}`, + value: `${moderator.toString()}`, }, ], footer: { text: `Command ID: ${commandId} - Version ID: ${versionId}` }, @@ -232,7 +232,9 @@ export async function handleSetPrefixCommandContent(interaction: ChatInputComman try { await foundData?.deleteOne(); } catch (error) { - Logger.error(`Failed to delete existing content for prefix command ${command} and version ${version}: ${error}`); + Logger.error( + `Failed to delete existing content for prefix command ${command} and version ${version}${error instanceof Error && `: ${error}`} `, + ); await interaction.followUp({ embeds: [failedEmbed(command, version)], ephemeral: true }); return; } @@ -255,11 +257,11 @@ export async function handleSetPrefixCommandContent(interaction: ChatInputComman embeds: [modLogEmbed(moderator, command, version, title, content, image, commandId, versionId)], }); } catch (error) { - Logger.error(`Failed to post a message to the mod logs channel: ${error}`); + Logger.error('Failed to post a message to the mod logs channel:', error); } } } catch (error) { - Logger.error(`Failed to set prefix command content for command ${command} and version ${version}: ${error}`); + Logger.error(`Failed to set prefix command content for command ${command} and version ${version}`, error); await interaction.followUp({ embeds: [failedEmbed(command, version)], ephemeral: true }); } } diff --git a/src/commands/moderation/prefixCommands/functions/showChannelDefaultVersion.ts b/src/commands/moderation/prefixCommands/functions/showChannelDefaultVersion.ts index a8fcef88..51fa630b 100644 --- a/src/commands/moderation/prefixCommands/functions/showChannelDefaultVersion.ts +++ b/src/commands/moderation/prefixCommands/functions/showChannelDefaultVersion.ts @@ -81,7 +81,10 @@ export async function handleShowPrefixCommandChannelDefaultVersion(interaction: ephemeral: false, }); } catch (error) { - Logger.error(`Failed to show the channel default version for channel ${channel} and version ${version}: ${error}`); + Logger.error( + `Failed to show the channel default version for channel ${channel.toString()} and version ${version}`, + error, + ); await interaction.followUp({ embeds: [failedEmbed(channelName)], ephemeral: true }); } } diff --git a/src/commands/moderation/prefixCommands/prefixCommandCacheUpdate.ts b/src/commands/moderation/prefixCommands/prefixCommandCacheUpdate.ts index 35eebfd4..5e1d2d6e 100644 --- a/src/commands/moderation/prefixCommands/prefixCommandCacheUpdate.ts +++ b/src/commands/moderation/prefixCommands/prefixCommandCacheUpdate.ts @@ -36,7 +36,7 @@ const noChannelEmbed = (channelName: string) => const cacheUpdateEmbedField = (moderator: User, duration: string): EmbedField[] => [ { name: 'Moderator', - value: `${moderator}`, + value: `${moderator.toString()}`, inline: true, }, { @@ -59,7 +59,9 @@ export default slashCommand(data, async ({ interaction }) => { refreshAllPrefixCommandChannelDefaultVersionsCache(), ]); } catch (error) { - await interaction.editReply({ content: `An error occurred while updating the cache: ${error}` }); + await interaction.editReply({ + content: `An error occurred while updating the cache${error instanceof Error && `: ${error}`}`, + }); return; } @@ -73,7 +75,7 @@ export default slashCommand(data, async ({ interaction }) => { await modLogsChannel.send({ embeds: [cacheUpdateEmbed(cacheUpdateEmbedField(interaction.user, duration), Colors.Green)], }); - } catch (error) { + } catch { await interaction.followUp({ embeds: [noChannelEmbed('mod-log')] }); } }); diff --git a/src/commands/moderation/prefixCommands/prefixCommandPermissions.ts b/src/commands/moderation/prefixCommands/prefixCommandPermissions.ts index a508b507..8792fba5 100644 --- a/src/commands/moderation/prefixCommands/prefixCommandPermissions.ts +++ b/src/commands/moderation/prefixCommands/prefixCommandPermissions.ts @@ -184,7 +184,7 @@ const autocompleteCallback: AutocompleteCallback = async ({ interaction }) => { const conn = getConn(); switch (optionName) { - case 'command': + case 'command': { if (!conn) { return interaction.respond(choices); } @@ -197,6 +197,7 @@ const autocompleteCallback: AutocompleteCallback = async ({ interaction }) => { choices.push({ name, value: name }); } break; + } default: choices = []; } diff --git a/src/commands/moderation/prefixCommands/prefixCommands.ts b/src/commands/moderation/prefixCommands/prefixCommands.ts index ff1f616b..f7c647a5 100644 --- a/src/commands/moderation/prefixCommands/prefixCommands.ts +++ b/src/commands/moderation/prefixCommands/prefixCommands.ts @@ -532,7 +532,7 @@ const autocompleteCallback: AutocompleteCallback = async ({ interaction }) => { const conn = getConn(); switch (optionName) { - case 'category': + case 'category': { if (!conn) { return interaction.respond(choices); } @@ -545,7 +545,8 @@ const autocompleteCallback: AutocompleteCallback = async ({ interaction }) => { choices.push({ name, value: name }); } break; - case 'command': + } + case 'command': { if (!conn) { return interaction.respond(choices); } @@ -558,7 +559,8 @@ const autocompleteCallback: AutocompleteCallback = async ({ interaction }) => { choices.push({ name, value: name }); } break; - case 'version': + } + case 'version': { choices.push({ name: 'GENERIC', value: 'GENERIC' }); if (!conn) { return interaction.respond(choices); @@ -572,6 +574,7 @@ const autocompleteCallback: AutocompleteCallback = async ({ interaction }) => { choices.push({ name, value: name }); } break; + } default: break; } diff --git a/src/events/ready.ts b/src/events/ready.ts index cc466082..41285d66 100644 --- a/src/events/ready.ts +++ b/src/events/ready.ts @@ -1,23 +1,19 @@ import { ActivityType, TextChannel } from 'discord.js'; import moment from 'moment'; +import commandArray from '../commands'; +import contextArray from '../commands/context'; import { - constantsConfig, - event, Events, - connect, - setupScheduler, Logger, - imageBaseUrl, + connect, + constantsConfig, + event, getScheduler, + imageBaseUrl, setupInMemoryCache, - loadAllPrefixCommandsToCache, - loadAllPrefixCommandVersionsToCache, - loadAllPrefixCommandCategoriesToCache, - loadAllPrefixCommandChannelDefaultVersionsToCache, + setupScheduler, } from '../lib'; import { deployCommands } from '../scripts/deployCommands'; -import commandArray from '../commands'; -import contextArray from '../commands/context'; export default event(Events.ClientReady, async ({ log }, client) => { log(`Logged in as ${client.user.username}!`); @@ -63,7 +59,7 @@ export default event(Events.ClientReady, async ({ log }, client) => { inMemoryCacheSetup = true; }) .catch((error) => { - inMemoryCacheError = error; + inMemoryCacheError = error instanceof Error ? error : undefined; Logger.error(error); }); diff --git a/src/lib/schedulerJobs/refreshInMemoryCache.ts b/src/lib/schedulerJobs/refreshInMemoryCache.ts index ad4fcd31..3e2285ce 100644 --- a/src/lib/schedulerJobs/refreshInMemoryCache.ts +++ b/src/lib/schedulerJobs/refreshInMemoryCache.ts @@ -23,7 +23,6 @@ export async function refreshInMemoryCache(job: Job) { } // Needed because of https://github.com/agenda/agenda/issues/401 - // eslint-disable-next-line no-underscore-dangle const matchingJobs = await scheduler.jobs({ _id: job.attrs._id }); if (matchingJobs.length !== 1) { Logger.debug('Job has been deleted already, skipping execution.'); diff --git a/src/lib/schemas/prefixCommandSchemas.ts b/src/lib/schemas/prefixCommandSchemas.ts index 3ccf06c6..f0a35e00 100644 --- a/src/lib/schemas/prefixCommandSchemas.ts +++ b/src/lib/schemas/prefixCommandSchemas.ts @@ -17,7 +17,7 @@ const prefixCommandCategorySchema = new Schema({ }); export interface IPrefixCommandVersion extends Document { - versionId: mongoose.Schema.Types.ObjectId; + versionId: { type: mongoose.Schema.Types.ObjectId; ref: 'PrefixCommandVersion' }; name: string; emoji: string; alias: string; From 7927cacca630b6dfb4d8061717cf116e561d0494 Mon Sep 17 00:00:00 2001 From: ExampleWasTaken <58574351+ExampleWasTaken@users.noreply.github.com> Date: Thu, 31 Oct 2024 13:29:59 +0100 Subject: [PATCH 78/82] refactor prefix message handler --- src/events/messageCreateHandler.ts | 492 +++++++++++++++-------------- 1 file changed, 254 insertions(+), 238 deletions(-) diff --git a/src/events/messageCreateHandler.ts b/src/events/messageCreateHandler.ts index 4f864a33..7a582518 100644 --- a/src/events/messageCreateHandler.ts +++ b/src/events/messageCreateHandler.ts @@ -3,8 +3,8 @@ import { ButtonBuilder, ButtonInteraction, ButtonStyle, + ComponentType, EmbedBuilder, - Interaction, Message, } from 'discord.js'; import { @@ -151,10 +151,10 @@ async function sendPermError(message: Message, errorText: string) { if (constantsConfig.prefixCommandPermissionDelay > 0) { setTimeout(() => { try { - permReply.delete(); - message.delete(); + void permReply.delete(); + void message.delete(); } catch (error) { - Logger.error(`Error while deleting permission error message for command: ${error}`); + Logger.error('Error while deleting permission error message for command:', error); } }, constantsConfig.prefixCommandPermissionDelay); } @@ -170,255 +170,271 @@ export default event(Events.MessageCreate, async (_, message) => { Logger.debug(`Processing message ${messageId} from user ${authorId} in channel ${channelId} of server ${guildId}.`); const inMemoryCache = getInMemoryCache(); - if (inMemoryCache && content.startsWith(constantsConfig.prefixCommandPrefix)) { - const commandTextMatch = content.match( - `^\\${constantsConfig.prefixCommandPrefix}([\\w\\d-_]+)[^\\w\\d-_]*([\\w\\d-_]+)?`, + // Return if either the memory-cache is null or the message doesn't start with the defined prefix-command prefix. + if (!inMemoryCache || !content.startsWith(constantsConfig.prefixCommandPrefix)) { + return; + } + + const commandTextMatch = content.match( + `^\\${constantsConfig.prefixCommandPrefix}([\\w\\d-_]+)[^\\w\\d-_]*([\\w\\d-_]+)?`, + ); + // Return if the message doesn't match the regex. + if (!commandTextMatch) { + Logger.debug('no match'); + return; + } + + let [commandText] = commandTextMatch.slice(1); + const commandVersionExplicitGeneric = commandText.toLowerCase() === 'generic'; + + // Step 1: Check if the command is actually a version alias + const commandCachedVersion = await inMemoryCache.get(`${MemoryCachePrefix.VERSION}:${commandText.toLowerCase()}`); + let commandVersionId: string; + let commandVersionName: string; + let commandVersionEnabled: boolean; + if (commandCachedVersion) { + const commandVersion = PrefixCommandVersion.hydrate(commandCachedVersion); + ({ id: commandVersionId, name: commandVersionName, enabled: commandVersionEnabled } = commandVersion); + } else { + commandVersionId = 'GENERIC'; + commandVersionName = 'GENERIC'; + commandVersionEnabled = true; + } + + // Step 2: Check if there's a default version for the channel if commandVersionName is GENERIC + let channelDefaultVersionUsed = false; + if (commandVersionName === 'GENERIC' && !commandVersionExplicitGeneric) { + const channelDefaultVersionCached = await inMemoryCache.get( + `${MemoryCachePrefix.CHANNEL_DEFAULT_VERSION}:${channelId}`, ); - if (commandTextMatch) { - let [commandText] = commandTextMatch.slice(1); - const commandVersionExplicitGeneric = commandText.toLowerCase() === 'generic'; + if (channelDefaultVersionCached) { + const channelDefaultVersion = PrefixCommandVersion.hydrate(channelDefaultVersionCached); + ({ id: commandVersionId, name: commandVersionName, enabled: commandVersionEnabled } = channelDefaultVersion); + channelDefaultVersionUsed = true; + } + } - // Step 1: Check if the command is actually a version alias - const commandCachedVersion = await inMemoryCache.get(`${MemoryCachePrefix.VERSION}:${commandText.toLowerCase()}`); - let commandVersionId: string; - let commandVersionName: string; - let commandVersionEnabled: boolean; - if (commandCachedVersion) { - const commandVersion = PrefixCommandVersion.hydrate(commandCachedVersion); - ({ id: commandVersionId, name: commandVersionName, enabled: commandVersionEnabled } = commandVersion); - } else { - commandVersionId = 'GENERIC'; - commandVersionName = 'GENERIC'; - commandVersionEnabled = true; - } + // Drop execution if the version is disabled and we aren't using the default version for a channel + if (!commandVersionEnabled && !channelDefaultVersionUsed) { + if ((commandCachedVersion || commandVersionExplicitGeneric) && commandTextMatch[2]) { + [commandText] = commandTextMatch.slice(2); + } + Logger.debug( + `Prefix Command - Version "${commandVersionName}" is disabled - Not executing command "${commandText}"`, + ); + return; + } + // If the version is disabled and we are using the default version for a channel, switch to the generic version + if (!commandVersionEnabled && channelDefaultVersionUsed) { + commandVersionId = 'GENERIC'; + commandVersionName = 'GENERIC'; + commandVersionEnabled = true; + } - // Step 2: Check if there's a default version for the channel if commandVersionName is GENERIC - let channelDefaultVersionUsed = false; - if (commandVersionName === 'GENERIC' && !commandVersionExplicitGeneric) { - const channelDefaultVersionCached = await inMemoryCache.get( - `${MemoryCachePrefix.CHANNEL_DEFAULT_VERSION}:${channelId}`, - ); - if (channelDefaultVersionCached) { - const channelDefaultVersion = PrefixCommandVersion.hydrate(channelDefaultVersionCached); - ({ id: commandVersionId, name: commandVersionName, enabled: commandVersionEnabled } = channelDefaultVersion); - channelDefaultVersionUsed = true; - } - } + // Step 2.5: If the first command was actually a version alias, take the actual command as CommandText + if ((commandCachedVersion || commandVersionExplicitGeneric) && commandTextMatch[2]) { + [commandText] = commandTextMatch.slice(2); + } - // Drop execution if the version is disabled and we aren't using the default version for a channel - if (!commandVersionEnabled && !channelDefaultVersionUsed) { - if ((commandCachedVersion || commandVersionExplicitGeneric) && commandTextMatch[2]) { - [commandText] = commandTextMatch.slice(2); - } - Logger.debug( - `Prefix Command - Version "${commandVersionName}" is disabled - Not executing command "${commandText}"`, - ); - return; - } - // If the version is disabled and we are using the default version for a channel, switch to the generic version - if (!commandVersionEnabled && channelDefaultVersionUsed) { - commandVersionId = 'GENERIC'; - commandVersionName = 'GENERIC'; - commandVersionEnabled = true; - } + // Step 3: Check if the command exists itself and process it, otherwise return. + const cachedCommandDetails = await inMemoryCache.get(`${MemoryCachePrefix.COMMAND}:${commandText.toLowerCase()}`); + if (!cachedCommandDetails) { + Logger.debug('No command details found. Returning...'); + return; + } - // Step 2.5: If the first command was actually a version alias, take the actual command as CommandText - if ((commandCachedVersion || commandVersionExplicitGeneric) && commandTextMatch[2]) { - [commandText] = commandTextMatch.slice(2); - } + const commandDetails = PrefixCommand.hydrate(cachedCommandDetails); + const { name, contents, isEmbed, embedColor, permissions } = commandDetails; + const { + roles: permRoles, + rolesBlocklist, + channels: permChannels, + channelsBlocklist, + quietErrors, + verboseErrors, + } = permissions ?? new PrefixCommandPermissions(); + const authorMember = await guild.members.fetch(authorId); - // Step 3: Check if the command exists itself and process it - const cachedCommandDetails = await inMemoryCache.get(`${MemoryCachePrefix.COMMAND}:${commandText.toLowerCase()}`); - if (cachedCommandDetails) { - const commandDetails = PrefixCommand.hydrate(cachedCommandDetails); - const { name, contents, isEmbed, embedColor, permissions } = commandDetails; - const { - roles: permRoles, - rolesBlocklist, - channels: permChannels, - channelsBlocklist, - quietErrors, - verboseErrors, - } = permissions ?? new PrefixCommandPermissions(); - const authorMember = await guild.members.fetch(authorId); + // Check permissions + const hasAnyRole = permRoles && permRoles.some((role) => authorMember.roles.cache.has(role)); + const isInChannel = permChannels && permChannels.includes(channelId); + const meetsRoleRequirements = + !permRoles || permRoles.length === 0 || (hasAnyRole && !rolesBlocklist) || (!hasAnyRole && rolesBlocklist); + const meetsChannelRequirements = + !permChannels || + permChannels.length === 0 || + (isInChannel && !channelsBlocklist) || + (!isInChannel && channelsBlocklist); - // Check permissions - const hasAnyRole = permRoles && permRoles.some((role) => authorMember.roles.cache.has(role)); - const isInChannel = permChannels && permChannels.includes(channelId); - const meetsRoleRequirements = - !permRoles || permRoles.length === 0 || (hasAnyRole && !rolesBlocklist) || (!hasAnyRole && rolesBlocklist); - const meetsChannelRequirements = - !permChannels || - permChannels.length === 0 || - (isInChannel && !channelsBlocklist) || - (!isInChannel && channelsBlocklist); + if (!meetsRoleRequirements) { + Logger.debug( + `Prefix Command - User does not meet role requirements for command "${name}" based on user command "${commandText}"`, + ); + if (quietErrors) return; + let errorText = ''; + if (verboseErrors && !rolesBlocklist) { + errorText = `You do not have the required role to execute this command. Required roles: ${permRoles.map((role) => guild.roles.cache.get(role)?.name).join(', ')}.`; + } else if (verboseErrors && rolesBlocklist) { + errorText = `You have a blocklisted role for this command. Blocklisted roles: ${permRoles.map((role) => guild.roles.cache.get(role)?.name).join(', ')}.`; + } else if (!verboseErrors && !rolesBlocklist) { + errorText = 'You do not have the required role to execute this command.'; + } else { + errorText = 'You have a blocklisted role for this command.'; + } + await sendPermError(message, errorText); + return; + } - if (!meetsRoleRequirements) { - Logger.debug( - `Prefix Command - User does not meet role requirements for command "${name}" based on user command "${commandText}"`, - ); - if (quietErrors) return; - let errorText = ''; - if (verboseErrors && !rolesBlocklist) { - errorText = `You do not have the required role to execute this command. Required roles: ${permRoles.map((role) => guild.roles.cache.get(role)?.name).join(', ')}.`; - } else if (verboseErrors && rolesBlocklist) { - errorText = `You have a blocklisted role for this command. Blocklisted roles: ${permRoles.map((role) => guild.roles.cache.get(role)?.name).join(', ')}.`; - } else if (!verboseErrors && !rolesBlocklist) { - errorText = 'You do not have the required role to execute this command.'; - } else { - errorText = 'You have a blocklisted role for this command.'; - } - await sendPermError(message, errorText); - return; - } + if (!meetsChannelRequirements) { + Logger.debug( + `Prefix Command - Message does not meet channel requirements for command "${name}" based on user command "${commandText}"`, + ); + if (quietErrors) return; + let errorText = ''; + if (verboseErrors && !channelsBlocklist) { + errorText = `This command is not available in this channel. Required channels: ${permChannels.map((channel) => guild.channels.cache.get(channel)?.toString()).join(', ')}.`; + } else if (verboseErrors && channelsBlocklist) { + errorText = `This command is blocklisted in this channel. Blocklisted channels: ${permChannels.map((channel) => guild.channels.cache.get(channel)?.toString()).join(', ')}.`; + } else if (!verboseErrors && !channelsBlocklist) { + errorText = 'This command is not available in this channel.'; + } else { + errorText = 'This command is blocklisted in this channel.'; + } + await sendPermError(message, errorText); + return; + } - if (!meetsChannelRequirements) { - Logger.debug( - `Prefix Command - Message does not meet channel requirements for command "${name}" based on user command "${commandText}"`, - ); - if (quietErrors) return; - let errorText = ''; - if (verboseErrors && !channelsBlocklist) { - errorText = `This command is not available in this channel. Required channels: ${permChannels.map((channel) => guild.channels.cache.get(channel)?.toString()).join(', ')}.`; - } else if (verboseErrors && channelsBlocklist) { - errorText = `This command is blocklisted in this channel. Blocklisted channels: ${permChannels.map((channel) => guild.channels.cache.get(channel)?.toString()).join(', ')}.`; - } else if (!verboseErrors && !channelsBlocklist) { - errorText = 'This command is not available in this channel.'; - } else { - errorText = 'This command is blocklisted in this channel.'; - } - await sendPermError(message, errorText); - return; + let commandContentData = contents.find(({ versionId }) => versionId === commandVersionId); + let enableButtons = true; + // If the version is not found, try to find the generic version + if (!commandContentData) { + commandContentData = contents.find(({ versionId }) => versionId === 'GENERIC'); + commandVersionName = 'GENERIC'; + enableButtons = false; + } + // If the generic version is not found, drop execution + if (!commandContentData) { + Logger.debug( + `Prefix Command - Version "${commandVersionName}" not found for command "${name}" based on user command "${commandText}"`, + ); + return; + } + const { title: commandTitle, content: commandContent, image: commandImage } = commandContentData; + // If generic requested and multiple versions, show the selection + // Note that this only applies if GENERIC is the version explicitly requested + // Otherwise, the options are not shown + if (enableButtons && commandVersionName === 'GENERIC' && contents.length > 1) { + Logger.debug( + `Prefix Command - Multiple versions found for command "${name}" based on user command "${commandText}", showing version selection`, + ); + const versionSelectionButtonData: { [key: string]: ButtonBuilder } = {}; + for (const { versionId: versionIdForButton } of contents) { + // eslint-disable-next-line no-await-in-loop + const versionCached = await inMemoryCache.get(`${MemoryCachePrefix.VERSION}:${versionIdForButton}`); + if (versionCached) { + const version = PrefixCommandVersion.hydrate(versionCached); + const { emoji, enabled } = version; + if (enabled) { + versionSelectionButtonData[emoji] = new ButtonBuilder() + .setCustomId(`${versionIdForButton}`) + .setEmoji(emoji) + .setStyle(ButtonStyle.Primary); } + } + } + const versionSelectionButtons: ButtonBuilder[] = Object.keys(versionSelectionButtonData) + .sort() + .map((key: string) => versionSelectionButtonData[key]); + const versionSelectButtonRow = new ActionRowBuilder().addComponents(versionSelectionButtons); - let commandContentData = contents.find(({ versionId }) => versionId === commandVersionId); - let enableButtons = true; - // If the version is not found, try to find the generic version - if (!commandContentData) { - commandContentData = contents.find(({ versionId }) => versionId === 'GENERIC'); - commandVersionName = 'GENERIC'; - enableButtons = false; - } - // If the generic version is not found, drop execution - if (!commandContentData) { - Logger.debug( - `Prefix Command - Version "${commandVersionName}" not found for command "${name}" based on user command "${commandText}"`, - ); - return; - } - const { title: commandTitle, content: commandContent, image: commandImage } = commandContentData; - // If generic requested and multiple versions, show the selection - // Note that this only applies if GENERIC is the version explicitly requested - // Otherwise, the options are not shown - if (enableButtons && commandVersionName === 'GENERIC' && contents.length > 1) { - Logger.debug( - `Prefix Command - Multiple versions found for command "${name}" based on user command "${commandText}", showing version selection`, - ); - const versionSelectionButtonData: { [key: string]: ButtonBuilder } = {}; - for (const { versionId: versionIdForButton } of contents) { - // eslint-disable-next-line no-await-in-loop - const versionCached = await inMemoryCache.get(`${MemoryCachePrefix.VERSION}:${versionIdForButton}`); - if (versionCached) { - const version = PrefixCommandVersion.hydrate(versionCached); - const { emoji, enabled } = version; - if (enabled) { - versionSelectionButtonData[emoji] = new ButtonBuilder() - .setCustomId(`${versionIdForButton}`) - .setEmoji(emoji) - .setStyle(ButtonStyle.Primary); - } - } - } - const versionSelectionButtons: ButtonBuilder[] = Object.keys(versionSelectionButtonData) - .sort() - .map((key: string) => versionSelectionButtonData[key]); - const versionSelectButtonRow = new ActionRowBuilder().addComponents(versionSelectionButtons); + if (versionSelectButtonRow.components.length < 1) { + Logger.debug( + `Prefix Command - No enabled versions found for command "${name}" based on user command "${commandText}"`, + ); + Logger.debug( + `Prefix Command - Executing version "${commandVersionName}" for command "${name}" based on user command "${commandText}"`, + ); + await sendReply( + message, + commandTitle, + commandContent || '', + isEmbed || false, + embedColor || constantsConfig.colors.FBW_CYAN, + commandImage || '', + ); + return; + } - if (versionSelectButtonRow.components.length < 1) { - Logger.debug( - `Prefix Command - No enabled versions found for command "${name}" based on user command "${commandText}"`, - ); - Logger.debug( - `Prefix Command - Executing version "${commandVersionName}" for command "${name}" based on user command "${commandText}"`, - ); - await sendReply( - message, - commandTitle, - commandContent || '', - isEmbed || false, - embedColor || constantsConfig.colors.FBW_CYAN, - commandImage || '', - ); - return; - } - const buttonMessage = await sendReply( - message, - commandTitle, - commandContent || '', - isEmbed || false, - embedColor || constantsConfig.colors.FBW_CYAN, - commandImage || '', - versionSelectButtonRow, - ); + const buttonMessage = await sendReply( + message, + commandTitle, + commandContent || '', + isEmbed || false, + embedColor || constantsConfig.colors.FBW_CYAN, + commandImage || '', + versionSelectButtonRow, + ); - const filter = (interaction: Interaction) => interaction.user.id === authorId; - const collector = buttonMessage.createMessageComponentCollector({ filter, time: 60_000 }); - let buttonClicked = false; - collector.on('collect', async (collectedInteraction: ButtonInteraction) => { - buttonClicked = true; - await collectedInteraction.deferUpdate(); - Logger.debug( - `Prefix Command - User selected button "${collectedInteraction.customId}" for command "${name}" based on user command "${commandText}"`, - ); - await buttonMessage.delete(); - const { customId: selectedVersionId } = collectedInteraction; - const commandContentData = contents.find(({ versionId }) => versionId === selectedVersionId); - if (!commandContentData) { - Logger.debug( - `Prefix Command - Version ID "${selectedVersionId}" not found for command "${name}" based on user command "${commandText}"`, - ); - return; - } - const { title: commandTitle, content: commandContent, image: commandImage } = commandContentData; - await sendReply( - message, - commandTitle, - commandContent || '', - isEmbed || false, - embedColor || constantsConfig.colors.FBW_CYAN, - commandImage || '', - ); - }); + const filter = (interaction: ButtonInteraction) => { + return interaction.user.id === authorId; + }; - collector.on('end', async (_: ButtonInteraction, reason: string) => { - if (!buttonClicked && reason === 'time') { - Logger.debug( - `Prefix Command - User did not select a version for command "${name}" based on user command "${commandText}"`, - ); - await expireChoiceReply( - buttonMessage, - commandTitle, - commandContent || '', - isEmbed || false, - embedColor || constantsConfig.colors.FBW_CYAN, - commandImage || '', - ); - } - }); - } else { - Logger.debug( - `Prefix Command - Executing version "${commandVersionName}" for command "${name}" based on user command "${commandText}"`, - ); - await sendReply( - message, - commandTitle, - commandContent || '', - isEmbed || false, - embedColor || constantsConfig.colors.FBW_CYAN, - commandImage || '', - ); - } + try { + const buttonInteraction = await buttonMessage.awaitMessageComponent({ + filter, + time: 60_000, + componentType: ComponentType.Button, + }); + + void buttonInteraction.deferUpdate(); + + Logger.debug( + `Prefix Command - User selected button "${buttonInteraction.customId}" for command "${name}" based on user command "${commandText}"`, + ); + void buttonMessage.delete(); + const { customId: selectedVersionId } = buttonInteraction; + const commandContentData = contents.find(({ versionId }) => versionId === selectedVersionId); + if (!commandContentData) { + Logger.debug( + `Prefix Command - Version ID "${selectedVersionId}" not found for command "${name}" based on user command "${commandText}"`, + ); + return; } + const { title: commandTitle, content: commandContent, image: commandImage } = commandContentData; + await sendReply( + message, + commandTitle, + commandContent || '', + isEmbed || false, + embedColor || constantsConfig.colors.FBW_CYAN, + commandImage || '', + ); + return; + } catch { + Logger.debug( + `Prefix Command - User did not select a version for command "${name}" based on user command "${commandText}"`, + ); + await expireChoiceReply( + buttonMessage, + commandTitle, + commandContent || '', + isEmbed || false, + embedColor || constantsConfig.colors.FBW_CYAN, + commandImage || '', + ); + return; } + } else { + Logger.debug( + `Prefix Command - Executing version "${commandVersionName}" for command "${name}" based on user command "${commandText}"`, + ); + await sendReply( + message, + commandTitle, + commandContent || '', + isEmbed || false, + embedColor || constantsConfig.colors.FBW_CYAN, + commandImage || '', + ); } }); From 3c93ed2953e42bf14b5270e411695910291775fb Mon Sep 17 00:00:00 2001 From: ExampleWasTaken <58574351+ExampleWasTaken@users.noreply.github.com> Date: Thu, 31 Oct 2024 14:02:01 +0100 Subject: [PATCH 79/82] fix lint issue in showContent cmd --- src/commands/moderation/prefixCommands/functions/showContent.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/commands/moderation/prefixCommands/functions/showContent.ts b/src/commands/moderation/prefixCommands/functions/showContent.ts index d6c532fd..f8ebbd62 100644 --- a/src/commands/moderation/prefixCommands/functions/showContent.ts +++ b/src/commands/moderation/prefixCommands/functions/showContent.ts @@ -124,7 +124,7 @@ export async function handleShowPrefixCommandContent(interaction: ChatInputComma ephemeral: false, }); } catch (error) { - Logger.error(`Failed to show prefix command content for command ${command} and version ${version}: ${error}`); + Logger.error(`Failed to show prefix command content for command ${command} and version ${version}:`, error); await interaction.followUp({ embeds: [failedEmbed(command, version)], ephemeral: true }); } } From 0ad600303a07105404a7560cfaa1a8852e2e88bc Mon Sep 17 00:00:00 2001 From: ExampleWasTaken <58574351+ExampleWasTaken@users.noreply.github.com> Date: Thu, 31 Oct 2024 14:15:57 +0100 Subject: [PATCH 80/82] remove unnecessary template strings in error logs --- .../moderation/prefixCommands/functions/addCategory.ts | 6 +++--- .../moderation/prefixCommands/functions/addCommand.ts | 4 ++-- .../prefixCommands/functions/showCommandPermissions.ts | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/commands/moderation/prefixCommands/functions/addCategory.ts b/src/commands/moderation/prefixCommands/functions/addCategory.ts index 03d84fd2..490c7f8b 100644 --- a/src/commands/moderation/prefixCommands/functions/addCategory.ts +++ b/src/commands/moderation/prefixCommands/functions/addCategory.ts @@ -44,7 +44,7 @@ const modLogEmbed = (moderator: User, category: string, emoji: string, categoryI }, { name: 'Moderator', - value: `${moderator}`, + value: `${moderator.toString()}`, }, { name: 'Emoji', @@ -96,11 +96,11 @@ export async function handleAddPrefixCommandCategory(interaction: ChatInputComma try { await modLogsChannel.send({ embeds: [modLogEmbed(moderator, name, emoji, prefixCommandCategory.id)] }); } catch (error) { - Logger.error(`Failed to post a message to the mod logs channel: ${error}`); + Logger.error('Failed to post a message to the mod logs channel:', error); } } } catch (error) { - Logger.error(`Failed to add a prefix command category ${name}: ${error}`); + Logger.error(`Failed to add a prefix command category ${name}:`, error); await interaction.followUp({ embeds: [failedEmbed(name)], ephemeral: true }); } } else { diff --git a/src/commands/moderation/prefixCommands/functions/addCommand.ts b/src/commands/moderation/prefixCommands/functions/addCommand.ts index 57795e79..493137ac 100644 --- a/src/commands/moderation/prefixCommands/functions/addCommand.ts +++ b/src/commands/moderation/prefixCommands/functions/addCommand.ts @@ -202,11 +202,11 @@ export async function handleAddPrefixCommand(interaction: ChatInputCommandIntera embeds: [modLogEmbed(moderator, name, aliases, description, isEmbed, embedColor, prefixCommand.id)], }); } catch (error) { - Logger.error(`Failed to post a message to the mod logs channel: ${error}`); + Logger.error('Failed to post a message to the mod logs channel:', error); } } } catch (error) { - Logger.error(`Failed to add a prefix command ${name}: ${error}`); + Logger.error(`Failed to add a prefix command ${name}:`, error); await interaction.followUp({ embeds: [failedEmbed(name)], ephemeral: true }); } } diff --git a/src/commands/moderation/prefixCommands/functions/showCommandPermissions.ts b/src/commands/moderation/prefixCommands/functions/showCommandPermissions.ts index 73dcad84..19dd52eb 100644 --- a/src/commands/moderation/prefixCommands/functions/showCommandPermissions.ts +++ b/src/commands/moderation/prefixCommands/functions/showCommandPermissions.ts @@ -122,7 +122,7 @@ export async function handleShowPrefixCommandPermissions(interaction: ChatInputC ephemeral: false, }); } catch (error) { - Logger.error(`Failed to show prefix command content for command ${command}: ${error}`); + Logger.error(`Failed to show prefix command content for command ${command}:`, error); await interaction.followUp({ embeds: [failedEmbed(command)], ephemeral: true }); } } From 45f3b071c130e820ca58bbf5358aeda7bcaaf038 Mon Sep 17 00:00:00 2001 From: ExampleWasTaken <58574351+ExampleWasTaken@users.noreply.github.com> Date: Thu, 31 Oct 2024 14:54:03 +0100 Subject: [PATCH 81/82] fix regression that wouldn't load prefix cmds on startup --- src/events/ready.ts | 75 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 75 insertions(+) diff --git a/src/events/ready.ts b/src/events/ready.ts index 41285d66..c6de1e87 100644 --- a/src/events/ready.ts +++ b/src/events/ready.ts @@ -10,6 +10,10 @@ import { event, getScheduler, imageBaseUrl, + loadAllPrefixCommandCategoriesToCache, + loadAllPrefixCommandChannelDefaultVersionsToCache, + loadAllPrefixCommandVersionsToCache, + loadAllPrefixCommandsToCache, setupInMemoryCache, setupScheduler, } from '../lib'; @@ -140,6 +144,77 @@ export default event(Events.ClientReady, async ({ log }, client) => { } } + const cacheRefreshInterval = process.env.CACHE_REFRESH_INTERVAL ? Number(process.env.CACHE_REFRESH_INTERVAL) : 1800; + // Set in memory cache refresh handler + if (schedulerConnected && cacheRefreshInterval) { + const scheduler = getScheduler(); + if (scheduler) { + const cacheJobList = await scheduler.jobs({ name: 'refreshInMemoryCache' }); + if (cacheJobList.length === 0) { + await scheduler.every(`${cacheRefreshInterval} seconds`, 'refreshInMemoryCache', { + interval: cacheRefreshInterval, + }); + Logger.info(`Cache refresh job scheduled with interval ${cacheRefreshInterval}`); + } else { + const cacheJob = cacheJobList[0]; + const { interval } = cacheJob.attrs.data as { interval: number }; + if (interval !== cacheRefreshInterval) { + await scheduler.cancel({ name: 'refreshInMemoryCache' }); + await scheduler.every(`${cacheRefreshInterval} seconds`, 'refreshInMemoryCache', { + interval: cacheRefreshInterval, + }); + Logger.info(`Cache refresh job rescheduled with new interval ${cacheRefreshInterval}`); + } else { + Logger.info('Cache refresh job already scheduled'); + } + } + } + } + + // Loading in-memory cache with prefix commands + if (inMemoryCacheSetup && dbConnected) { + loadAllPrefixCommandsToCache() + .then(() => { + Logger.info('Loaded prefix commands to cache.'); + }) + .catch((error) => { + Logger.error(`Failed to load prefix commands to cache: ${error}`); + }); + } + + // Loading in-memory cache with prefix command versions + if (inMemoryCacheSetup && dbConnected) { + await loadAllPrefixCommandVersionsToCache() + .then(() => { + Logger.info('Loaded prefix command versions to cache.'); + }) + .catch((error) => { + Logger.error(`Failed to load prefix command versions to cache: ${error}`); + }); + } + + // Loading in-memory cache with prefix command categories + if (inMemoryCacheSetup && dbConnected) { + await loadAllPrefixCommandCategoriesToCache() + .then(() => { + Logger.info('Loaded prefix command categories to cache.'); + }) + .catch((error) => { + Logger.error(`Failed to load prefix command categories to cache: ${error}`); + }); + } + + // Loading in-memory cache with prefix command channel default versions + if (inMemoryCacheSetup && dbConnected) { + await loadAllPrefixCommandChannelDefaultVersionsToCache() + .then(() => { + Logger.info('Loaded prefix command channel default versions to cache.'); + }) + .catch((error) => { + Logger.error(`Failed to load prefix command channel default versions to cache: ${error}`); + }); + } + // Send bot status message to bot-dev channel const botDevChannel = client.channels.resolve(constantsConfig.channels.MOD_LOGS) as TextChannel; if (botDevChannel) { From a48e9bae93cbed998bb67868c2d97e150edb5e47 Mon Sep 17 00:00:00 2001 From: ExampleWasTaken <58574351+ExampleWasTaken@users.noreply.github.com> Date: Fri, 1 Nov 2024 11:13:20 +0100 Subject: [PATCH 82/82] revert schema change --- src/lib/schemas/prefixCommandSchemas.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib/schemas/prefixCommandSchemas.ts b/src/lib/schemas/prefixCommandSchemas.ts index f0a35e00..3ccf06c6 100644 --- a/src/lib/schemas/prefixCommandSchemas.ts +++ b/src/lib/schemas/prefixCommandSchemas.ts @@ -17,7 +17,7 @@ const prefixCommandCategorySchema = new Schema({ }); export interface IPrefixCommandVersion extends Document { - versionId: { type: mongoose.Schema.Types.ObjectId; ref: 'PrefixCommandVersion' }; + versionId: mongoose.Schema.Types.ObjectId; name: string; emoji: string; alias: string;