From f8cc7628a6fd6781cd668f789ae5db9acb6bb934 Mon Sep 17 00:00:00 2001 From: Mestery Date: Sun, 11 Jul 2021 23:14:52 +0200 Subject: [PATCH 1/5] chore: update to discord.js v13 --- package-lock.json | 1338 ++++++++++++++++++-------------- package.json | 5 +- src/crons/CommitStrip.ts | 14 +- src/crons/EpicGames.ts | 37 +- src/framework/Bot.ts | 7 +- src/framework/Cron.ts | 20 +- src/framework/FormatChecker.ts | 4 +- src/framework/helpers.ts | 5 +- 8 files changed, 804 insertions(+), 626 deletions(-) diff --git a/package-lock.json b/package-lock.json index fe7f231..ac651b8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -5,11 +5,12 @@ "requires": true, "packages": { "": { + "name": "esc-bot", "version": "0.0.0", "license": "MIT", "dependencies": { "cron": "^1.8.2", - "discord.js": "^12.5.3", + "discord.js": "^13.0.0", "dotenv": "^10.0.0", "emoji-regex": "^9.2.2", "got": "^11.8.2", @@ -22,7 +23,6 @@ "@types/jest": "^26.0.24", "@types/node": "^16.4.13", "@types/pino": "^6.3.9", - "@types/ws": "^7.4.6", "@typescript-eslint/eslint-plugin": "^4.28.2", "@typescript-eslint/parser": "^4.28.2", "eslint": "^7.30.0", @@ -35,7 +35,7 @@ "typescript": "^4.3.5" }, "engines": { - "node": "16.x" + "node": ">=16.6.0" } }, "node_modules/@babel/code-frame": { @@ -48,29 +48,29 @@ } }, "node_modules/@babel/compat-data": { - "version": "7.14.7", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.14.7.tgz", - "integrity": "sha512-nS6dZaISCXJ3+518CWiBfEr//gHyMO02uDxBkXTKZDN5POruCnOZ1N4YBRZDCabwF8nZMWBpRxIicmXtBs+fvw==", + "version": "7.15.0", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.15.0.tgz", + "integrity": "sha512-0NqAC1IJE0S0+lL1SWFMxMkz1pKCNCjI4tr2Zx4LJSXxCLAdr6KyArnY+sno5m3yH9g737ygOyPABDsnXkpxiA==", "dev": true, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/core": { - "version": "7.14.6", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.14.6.tgz", - "integrity": "sha512-gJnOEWSqTk96qG5BoIrl5bVtc23DCycmIePPYnamY9RboYdI4nFy5vAQMSl81O5K/W0sLDWfGysnOECC+KUUCA==", + "version": "7.15.0", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.15.0.tgz", + "integrity": "sha512-tXtmTminrze5HEUPn/a0JtOzzfp0nk+UEXQ/tqIJo3WDGypl/2OFQEMll/zSFU8f/lfmfLXvTaORHF3cfXIQMw==", "dev": true, "dependencies": { "@babel/code-frame": "^7.14.5", - "@babel/generator": "^7.14.5", - "@babel/helper-compilation-targets": "^7.14.5", - "@babel/helper-module-transforms": "^7.14.5", - "@babel/helpers": "^7.14.6", - "@babel/parser": "^7.14.6", + "@babel/generator": "^7.15.0", + "@babel/helper-compilation-targets": "^7.15.0", + "@babel/helper-module-transforms": "^7.15.0", + "@babel/helpers": "^7.14.8", + "@babel/parser": "^7.15.0", "@babel/template": "^7.14.5", - "@babel/traverse": "^7.14.5", - "@babel/types": "^7.14.5", + "@babel/traverse": "^7.15.0", + "@babel/types": "^7.15.0", "convert-source-map": "^1.7.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.2", @@ -117,12 +117,12 @@ } }, "node_modules/@babel/generator": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.14.5.tgz", - "integrity": "sha512-y3rlP+/G25OIX3mYKKIOlQRcqj7YgrvHxOLbVmyLJ9bPmi5ttvUmpydVjcFjZphOktWuA7ovbx91ECloWTfjIA==", + "version": "7.15.0", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.15.0.tgz", + "integrity": "sha512-eKl4XdMrbpYvuB505KTta4AV9g+wWzmVBW69tX0H2NwKVKd2YJbKgyK6M8j/rgLbmHOYJn6rUklV677nOyJrEQ==", "dev": true, "dependencies": { - "@babel/types": "^7.14.5", + "@babel/types": "^7.15.0", "jsesc": "^2.5.1", "source-map": "^0.5.0" }, @@ -140,12 +140,12 @@ } }, "node_modules/@babel/helper-compilation-targets": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.14.5.tgz", - "integrity": "sha512-v+QtZqXEiOnpO6EYvlImB6zCD2Lel06RzOPzmkz/D/XgQiUu3C/Jb1LOqSt/AIA34TYi/Q+KlT8vTQrgdxkbLw==", + "version": "7.15.0", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.15.0.tgz", + "integrity": "sha512-h+/9t0ncd4jfZ8wsdAsoIxSa61qhBYlycXiHWqJaQBCXAhDCMbPRSMTGnZIkkmt1u4ag+UQmuqcILwqKzZ4N2A==", "dev": true, "dependencies": { - "@babel/compat-data": "^7.14.5", + "@babel/compat-data": "^7.15.0", "@babel/helper-validator-option": "^7.14.5", "browserslist": "^4.16.6", "semver": "^6.3.0" @@ -205,12 +205,12 @@ } }, "node_modules/@babel/helper-member-expression-to-functions": { - "version": "7.14.7", - "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.14.7.tgz", - "integrity": "sha512-TMUt4xKxJn6ccjcOW7c4hlwyJArizskAhoSTOCkA0uZ+KghIaci0Qg9R043kUMWI9mtQfgny+NQ5QATnZ+paaA==", + "version": "7.15.0", + "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.15.0.tgz", + "integrity": "sha512-Jq8H8U2kYiafuj2xMTPQwkTBnEEdGKpT35lJEQsRRjnG0LW3neucsaMWLgKcwu3OHKNeYugfw+Z20BXBSEs2Lg==", "dev": true, "dependencies": { - "@babel/types": "^7.14.5" + "@babel/types": "^7.15.0" }, "engines": { "node": ">=6.9.0" @@ -229,19 +229,19 @@ } }, "node_modules/@babel/helper-module-transforms": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.14.5.tgz", - "integrity": "sha512-iXpX4KW8LVODuAieD7MzhNjmM6dzYY5tfRqT+R9HDXWl0jPn/djKmA+G9s/2C2T9zggw5tK1QNqZ70USfedOwA==", + "version": "7.15.0", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.15.0.tgz", + "integrity": "sha512-RkGiW5Rer7fpXv9m1B3iHIFDZdItnO2/BLfWVW/9q7+KqQSDY5kUfQEbzdXM1MVhJGcugKV7kRrNVzNxmk7NBg==", "dev": true, "dependencies": { "@babel/helper-module-imports": "^7.14.5", - "@babel/helper-replace-supers": "^7.14.5", - "@babel/helper-simple-access": "^7.14.5", + "@babel/helper-replace-supers": "^7.15.0", + "@babel/helper-simple-access": "^7.14.8", "@babel/helper-split-export-declaration": "^7.14.5", - "@babel/helper-validator-identifier": "^7.14.5", + "@babel/helper-validator-identifier": "^7.14.9", "@babel/template": "^7.14.5", - "@babel/traverse": "^7.14.5", - "@babel/types": "^7.14.5" + "@babel/traverse": "^7.15.0", + "@babel/types": "^7.15.0" }, "engines": { "node": ">=6.9.0" @@ -269,27 +269,27 @@ } }, "node_modules/@babel/helper-replace-supers": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.14.5.tgz", - "integrity": "sha512-3i1Qe9/8x/hCHINujn+iuHy+mMRLoc77b2nI9TB0zjH1hvn9qGlXjWlggdwUcju36PkPCy/lpM7LLUdcTyH4Ow==", + "version": "7.15.0", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.15.0.tgz", + "integrity": "sha512-6O+eWrhx+HEra/uJnifCwhwMd6Bp5+ZfZeJwbqUTuqkhIT6YcRhiZCOOFChRypOIe0cV46kFrRBlm+t5vHCEaA==", "dev": true, "dependencies": { - "@babel/helper-member-expression-to-functions": "^7.14.5", + "@babel/helper-member-expression-to-functions": "^7.15.0", "@babel/helper-optimise-call-expression": "^7.14.5", - "@babel/traverse": "^7.14.5", - "@babel/types": "^7.14.5" + "@babel/traverse": "^7.15.0", + "@babel/types": "^7.15.0" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-simple-access": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.14.5.tgz", - "integrity": "sha512-nfBN9xvmCt6nrMZjfhkl7i0oTV3yxR4/FztsbOASyTvVcoYd0TRHh7eMLdlEcCqobydC0LAF3LtC92Iwxo0wyw==", + "version": "7.14.8", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.14.8.tgz", + "integrity": "sha512-TrFN4RHh9gnWEU+s7JloIho2T76GPwRHhdzOWLqTrMnlas8T9O7ec+oEDNsRXndOmru9ymH9DFrEOxpzPoSbdg==", "dev": true, "dependencies": { - "@babel/types": "^7.14.5" + "@babel/types": "^7.14.8" }, "engines": { "node": ">=6.9.0" @@ -308,9 +308,9 @@ } }, "node_modules/@babel/helper-validator-identifier": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.14.5.tgz", - "integrity": "sha512-5lsetuxCLilmVGyiLEfoHBRX8UCFD+1m2x3Rj97WrW3V7H3u4RWRXA4evMjImCsin2J2YT0QaVDGf+z8ondbAg==", + "version": "7.14.9", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.14.9.tgz", + "integrity": "sha512-pQYxPY0UP6IHISRitNe8bsijHex4TWZXi2HwKVsjPiltzlhse2znVcm9Ace510VT1kxIHjGJCZZQBX2gJDbo0g==", "dev": true, "engines": { "node": ">=6.9.0" @@ -326,14 +326,14 @@ } }, "node_modules/@babel/helpers": { - "version": "7.14.6", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.14.6.tgz", - "integrity": "sha512-yesp1ENQBiLI+iYHSJdoZKUtRpfTlL1grDIX9NRlAVppljLw/4tTyYupIB7uIYmC3stW/imAv8EqaKaS/ibmeA==", + "version": "7.14.8", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.14.8.tgz", + "integrity": "sha512-ZRDmI56pnV+p1dH6d+UN6GINGz7Krps3+270qqI9UJ4wxYThfAIcI5i7j5vXC4FJ3Wap+S9qcebxeYiqn87DZw==", "dev": true, "dependencies": { "@babel/template": "^7.14.5", - "@babel/traverse": "^7.14.5", - "@babel/types": "^7.14.5" + "@babel/traverse": "^7.14.8", + "@babel/types": "^7.14.8" }, "engines": { "node": ">=6.9.0" @@ -425,9 +425,9 @@ } }, "node_modules/@babel/parser": { - "version": "7.14.7", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.14.7.tgz", - "integrity": "sha512-X67Z5y+VBJuHB/RjwECp8kSl5uYi0BvRbNeWqkaJCVh+LiTPl19WBUfG627psSgp9rSf6ojuXghQM3ha6qHHdA==", + "version": "7.15.2", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.15.2.tgz", + "integrity": "sha512-bMJXql1Ss8lFnvr11TZDH4ArtwlAS5NG9qBmdiFW2UHHm6MVoR+GDc5XE2b9K938cyjc9O6/+vjjcffLDtfuDg==", "dev": true, "bin": { "parser": "bin/babel-parser.js" @@ -625,18 +625,18 @@ } }, "node_modules/@babel/traverse": { - "version": "7.14.7", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.14.7.tgz", - "integrity": "sha512-9vDr5NzHu27wgwejuKL7kIOm4bwEtaPQ4Z6cpCmjSuaRqpH/7xc4qcGEscwMqlkwgcXl6MvqoAjZkQ24uSdIZQ==", + "version": "7.15.0", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.15.0.tgz", + "integrity": "sha512-392d8BN0C9eVxVWd8H6x9WfipgVH5IaIoLp23334Sc1vbKKWINnvwRpb4us0xtPaCumlwbTtIYNA0Dv/32sVFw==", "dev": true, "dependencies": { "@babel/code-frame": "^7.14.5", - "@babel/generator": "^7.14.5", + "@babel/generator": "^7.15.0", "@babel/helper-function-name": "^7.14.5", "@babel/helper-hoist-variables": "^7.14.5", "@babel/helper-split-export-declaration": "^7.14.5", - "@babel/parser": "^7.14.7", - "@babel/types": "^7.14.5", + "@babel/parser": "^7.15.0", + "@babel/types": "^7.15.0", "debug": "^4.1.0", "globals": "^11.1.0" }, @@ -666,12 +666,12 @@ } }, "node_modules/@babel/types": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.14.5.tgz", - "integrity": "sha512-M/NzBpEL95I5Hh4dwhin5JlE7EzO5PHMAuzjxss3tiOBD46KfQvVedN/3jEPZvdRvtsK2222XfdHogNIttFgcg==", + "version": "7.15.0", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.15.0.tgz", + "integrity": "sha512-OBvfqnllOIdX4ojTHpwZbpvz4j3EWyjkZEdmjH0/cgsd6QOdSgU8rLSk6ard/pcW7rlmjdVSX/AWOaORR1uNOQ==", "dev": true, "dependencies": { - "@babel/helper-validator-identifier": "^7.14.5", + "@babel/helper-validator-identifier": "^7.14.9", "to-fast-properties": "^2.0.0" }, "engines": { @@ -684,10 +684,42 @@ "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==", "dev": true }, - "node_modules/@discordjs/collection": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/@discordjs/collection/-/collection-0.1.6.tgz", - "integrity": "sha512-utRNxnd9kSS2qhyivo9lMlt5qgAUasH2gb7BEOn6p0efFh24gjGomHzWKMAPn2hEReOPQZCJaRKoURwRotKucQ==" + "node_modules/@cspotcode/source-map-consumer": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/@cspotcode/source-map-consumer/-/source-map-consumer-0.8.0.tgz", + "integrity": "sha512-41qniHzTU8yAGbCp04ohlmSrZf8bkf/iJsl3V0dRGsQN/5GFfx+LbCSsCpp2gqrqjTVg/K6O8ycoV35JIwAzAg==", + "dev": true, + "engines": { + "node": ">= 12" + } + }, + "node_modules/@cspotcode/source-map-support": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.6.1.tgz", + "integrity": "sha512-DX3Z+T5dt1ockmPdobJS/FAsQPW4V4SrWEhD2iYQT2Cb2tQsiMnYxrcUH9By/Z3B+v0S5LMBkQtV/XOBbpLEOg==", + "dev": true, + "dependencies": { + "@cspotcode/source-map-consumer": "0.8.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@discordjs/builders": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/@discordjs/builders/-/builders-0.4.0.tgz", + "integrity": "sha512-EiwLltKph6TSaPJIzJYdzNc1PnA2ZNaaE0t0ODg3ghnpVHqfgd0YX9/srsleYHW2cw1sfIq+kbM+h0etf7GWLA==", + "dependencies": { + "@sindresorhus/is": "^4.0.1", + "discord-api-types": "^0.22.0", + "ow": "^0.27.0", + "ts-mixer": "^6.0.0", + "tslib": "^2.3.0" + }, + "engines": { + "node": ">=14.0.0", + "npm": ">=7.0.0" + } }, "node_modules/@discordjs/form-data": { "version": "3.0.1", @@ -703,9 +735,9 @@ } }, "node_modules/@eslint/eslintrc": { - "version": "0.4.2", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-0.4.2.tgz", - "integrity": "sha512-8nmGq/4ycLpIwzvhI4tNDmQztZ8sp+hI7cyG8i1nQDhkAbRzHpXPidRAHlNvCZQpJTKw5ItIpMw9RSToGF00mg==", + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-0.4.3.tgz", + "integrity": "sha512-J6KFFz5QCYUJq3pf0mjEcCJVERbzv71PUIDczuh9JkwGEzced6CO5ADLHB1rbf/+oPBtoPfMYNOpGDzCANlbXw==", "dev": true, "dependencies": { "ajv": "^6.12.4", @@ -1057,6 +1089,15 @@ "node": ">= 8" } }, + "node_modules/@sapphire/async-queue": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/@sapphire/async-queue/-/async-queue-1.1.4.tgz", + "integrity": "sha512-fFrlF/uWpGOX5djw5Mu2Hnnrunao75WGey0sP0J3jnhmrJ5TAPzHYOmytD5iN/+pMxS+f+u/gezqHa9tPhRHEA==", + "engines": { + "node": ">=14", + "npm": ">=6" + } + }, "node_modules/@sindresorhus/is": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-4.0.1.tgz", @@ -1087,9 +1128,9 @@ } }, "node_modules/@szmarczak/http-timer": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-4.0.5.tgz", - "integrity": "sha512-PyRA9sm1Yayuj5OIoJ1hGt2YISX45w9WcFbh6ddT0Z/0yaFxOtGLInr4jUfU1EAFVs0Yfyfev4RNwBlUaHdlDQ==", + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-4.0.6.tgz", + "integrity": "sha512-4BAffykYOgO+5nzBWYwE3W90sBgLJoUPRWWcL8wlyiM8IB8ipJz3UMJ9KXQd1RKQXpKp8Tutn80HZtWsu2u76w==", "dependencies": { "defer-to-connect": "^2.0.0" }, @@ -1125,9 +1166,9 @@ "dev": true }, "node_modules/@tsconfig/node16": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.1.tgz", - "integrity": "sha512-FTgBI767POY/lKNDNbIzgAX6miIDBs6NTCbdlDb8TrWovHsSvaVIZDlTqym29C6UqhzwcJx4CYr+AlrMywA0cA==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.2.tgz", + "integrity": "sha512-eZxlbI8GZscaGS7kkc/trHTT5xgrjH3/1n2JDwusC9iahPKWMRvRjJSAN5mCXviuTGQ/lHnhvv8Q1YTpnfz9gA==", "dev": true }, "node_modules/@types/babel__core": { @@ -1247,9 +1288,9 @@ } }, "node_modules/@types/json-schema": { - "version": "7.0.8", - "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.8.tgz", - "integrity": "sha512-YSBPTLTVm2e2OoQIDYx8HaeWJ5tTToLH67kXR7zYNGupXMEHa2++G8k+DczX2cFVgalypqtyZIcU19AFcmOpmg==", + "version": "7.0.9", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.9.tgz", + "integrity": "sha512-qcUXuemtEu+E5wZSJHNxUXeCZhAfXKQ41D+duX+VYPde7xyEVZci+/oXKJL13tnRs9lR2pr4fod59GT6/X1/yQ==", "dev": true }, "node_modules/@types/keyv": { @@ -1266,15 +1307,15 @@ "integrity": "sha512-bLL69sKtd25w7p1nvg9pigE4gtKVpGTPojBFLMkGHXuUgap2sLqQt2qUnqmVCDfzGUL0DRNZP+1prIZJbMeAXg==" }, "node_modules/@types/pino": { - "version": "6.3.9", - "resolved": "https://registry.npmjs.org/@types/pino/-/pino-6.3.9.tgz", - "integrity": "sha512-2/XV6adNNCLWnT2lJqcSn/OXrCxRFOY6yXYoofrLy5Ts5e8RHTJP1M4XEcCarQQMa6H6JISaa4GkrlGZwIP5aQ==", + "version": "6.3.11", + "resolved": "https://registry.npmjs.org/@types/pino/-/pino-6.3.11.tgz", + "integrity": "sha512-S7+fLONqSpHeW9d7TApUqO6VN47KYgOXhCNKwGBVLHObq8HhaAYlVqUNdfnvoXjCMiwE5xcPm/5R2ZUh8bgaXQ==", "dev": true, "dependencies": { "@types/node": "*", "@types/pino-pretty": "*", "@types/pino-std-serializers": "*", - "@types/sonic-boom": "*" + "sonic-boom": "^2.1.0" } }, "node_modules/@types/pino-pretty": { @@ -1309,15 +1350,6 @@ "@types/node": "*" } }, - "node_modules/@types/sonic-boom": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/@types/sonic-boom/-/sonic-boom-0.7.0.tgz", - "integrity": "sha512-AfqR0fZMoUXUNwusgXKxcE9DPlHNDHQp6nKYUd4PSRpLobF5CCevSpyTEBcVZreqaWKCnGBr9KI1fHMTttoB7A==", - "dev": true, - "dependencies": { - "@types/node": "*" - } - }, "node_modules/@types/stack-utils": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.1.tgz", @@ -1325,10 +1357,9 @@ "dev": true }, "node_modules/@types/ws": { - "version": "7.4.6", - "resolved": "https://registry.npmjs.org/@types/ws/-/ws-7.4.6.tgz", - "integrity": "sha512-ijZ1vzRawI7QoWnTNL8KpHixd2b2XVb9I9HAqI3triPsh1EC0xH0Eg6w2O3TKbDCgiNNlJqfrof6j4T2I+l9vw==", - "dev": true, + "version": "7.4.7", + "resolved": "https://registry.npmjs.org/@types/ws/-/ws-7.4.7.tgz", + "integrity": "sha512-JQbbmxZTZehdc2iszGKs5oC3NFnjeay7mtAWrdt7qNtAVK0g19muApzAy4bm9byz79xa2ZnO/BOBC2R8RC5Lww==", "dependencies": { "@types/node": "*" } @@ -1349,13 +1380,13 @@ "dev": true }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "4.28.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.28.2.tgz", - "integrity": "sha512-PGqpLLzHSxq956rzNGasO3GsAPf2lY9lDUBXhS++SKonglUmJypaUtcKzRtUte8CV7nruwnDxtLUKpVxs0wQBw==", + "version": "4.29.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.29.1.tgz", + "integrity": "sha512-AHqIU+SqZZgBEiWOrtN94ldR3ZUABV5dUG94j8Nms9rQnHFc8fvDOue/58K4CFz6r8OtDDc35Pw9NQPWo0Ayrw==", "dev": true, "dependencies": { - "@typescript-eslint/experimental-utils": "4.28.2", - "@typescript-eslint/scope-manager": "4.28.2", + "@typescript-eslint/experimental-utils": "4.29.1", + "@typescript-eslint/scope-manager": "4.29.1", "debug": "^4.3.1", "functional-red-black-tree": "^1.0.1", "regexpp": "^3.1.0", @@ -1380,15 +1411,15 @@ } }, "node_modules/@typescript-eslint/experimental-utils": { - "version": "4.28.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-4.28.2.tgz", - "integrity": "sha512-MwHPsL6qo98RC55IoWWP8/opTykjTp4JzfPu1VfO2Z0MshNP0UZ1GEV5rYSSnZSUI8VD7iHvtIPVGW5Nfh7klQ==", + "version": "4.29.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-4.29.1.tgz", + "integrity": "sha512-kl6QG6qpzZthfd2bzPNSJB2YcZpNOrP6r9jueXupcZHnL74WiuSjaft7WSu17J9+ae9zTlk0KJMXPUj0daBxMw==", "dev": true, "dependencies": { "@types/json-schema": "^7.0.7", - "@typescript-eslint/scope-manager": "4.28.2", - "@typescript-eslint/types": "4.28.2", - "@typescript-eslint/typescript-estree": "4.28.2", + "@typescript-eslint/scope-manager": "4.29.1", + "@typescript-eslint/types": "4.29.1", + "@typescript-eslint/typescript-estree": "4.29.1", "eslint-scope": "^5.1.1", "eslint-utils": "^3.0.0" }, @@ -1404,14 +1435,14 @@ } }, "node_modules/@typescript-eslint/parser": { - "version": "4.28.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-4.28.2.tgz", - "integrity": "sha512-Q0gSCN51eikAgFGY+gnd5p9bhhCUAl0ERMiDKrTzpSoMYRubdB8MJrTTR/BBii8z+iFwz8oihxd0RAdP4l8w8w==", + "version": "4.29.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-4.29.1.tgz", + "integrity": "sha512-3fL5iN20hzX3Q4OkG7QEPFjZV2qsVGiDhEwwh+EkmE/w7oteiOvUNzmpu5eSwGJX/anCryONltJ3WDmAzAoCMg==", "dev": true, "dependencies": { - "@typescript-eslint/scope-manager": "4.28.2", - "@typescript-eslint/types": "4.28.2", - "@typescript-eslint/typescript-estree": "4.28.2", + "@typescript-eslint/scope-manager": "4.29.1", + "@typescript-eslint/types": "4.29.1", + "@typescript-eslint/typescript-estree": "4.29.1", "debug": "^4.3.1" }, "engines": { @@ -1431,13 +1462,13 @@ } }, "node_modules/@typescript-eslint/scope-manager": { - "version": "4.28.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-4.28.2.tgz", - "integrity": "sha512-MqbypNjIkJFEFuOwPWNDjq0nqXAKZvDNNs9yNseoGBB1wYfz1G0WHC2AVOy4XD7di3KCcW3+nhZyN6zruqmp2A==", + "version": "4.29.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-4.29.1.tgz", + "integrity": "sha512-Hzv/uZOa9zrD/W5mftZa54Jd5Fed3tL6b4HeaOpwVSabJK8CJ+2MkDasnX/XK4rqP5ZTWngK1ZDeCi6EnxPQ7A==", "dev": true, "dependencies": { - "@typescript-eslint/types": "4.28.2", - "@typescript-eslint/visitor-keys": "4.28.2" + "@typescript-eslint/types": "4.29.1", + "@typescript-eslint/visitor-keys": "4.29.1" }, "engines": { "node": "^8.10.0 || ^10.13.0 || >=11.10.1" @@ -1448,9 +1479,9 @@ } }, "node_modules/@typescript-eslint/types": { - "version": "4.28.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-4.28.2.tgz", - "integrity": "sha512-Gr15fuQVd93uD9zzxbApz3wf7ua3yk4ZujABZlZhaxxKY8ojo448u7XTm/+ETpy0V0dlMtj6t4VdDvdc0JmUhA==", + "version": "4.29.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-4.29.1.tgz", + "integrity": "sha512-Jj2yu78IRfw4nlaLtKjVaGaxh/6FhofmQ/j8v3NXmAiKafbIqtAPnKYrf0sbGjKdj0hS316J8WhnGnErbJ4RCA==", "dev": true, "engines": { "node": "^8.10.0 || ^10.13.0 || >=11.10.1" @@ -1461,13 +1492,13 @@ } }, "node_modules/@typescript-eslint/typescript-estree": { - "version": "4.28.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-4.28.2.tgz", - "integrity": "sha512-86lLstLvK6QjNZjMoYUBMMsULFw0hPHJlk1fzhAVoNjDBuPVxiwvGuPQq3fsBMCxuDJwmX87tM/AXoadhHRljg==", + "version": "4.29.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-4.29.1.tgz", + "integrity": "sha512-lIkkrR9E4lwZkzPiRDNq0xdC3f2iVCUjw/7WPJ4S2Sl6C3nRWkeE1YXCQ0+KsiaQRbpY16jNaokdWnm9aUIsfw==", "dev": true, "dependencies": { - "@typescript-eslint/types": "4.28.2", - "@typescript-eslint/visitor-keys": "4.28.2", + "@typescript-eslint/types": "4.29.1", + "@typescript-eslint/visitor-keys": "4.29.1", "debug": "^4.3.1", "globby": "^11.0.3", "is-glob": "^4.0.1", @@ -1488,12 +1519,12 @@ } }, "node_modules/@typescript-eslint/visitor-keys": { - "version": "4.28.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-4.28.2.tgz", - "integrity": "sha512-aT2B4PLyyRDUVUafXzpZFoc0C9t0za4BJAKP5sgWIhG+jHECQZUEjuQSCIwZdiJJ4w4cgu5r3Kh20SOdtEBl0w==", + "version": "4.29.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-4.29.1.tgz", + "integrity": "sha512-zLqtjMoXvgdZY/PG6gqA73V8BjqPs4af1v2kiiETBObp+uC6gRYnJLmJHxC0QyUrrHDLJPIWNYxoBV3wbcRlag==", "dev": true, "dependencies": { - "@typescript-eslint/types": "4.28.2", + "@typescript-eslint/types": "4.29.1", "eslint-visitor-keys": "^2.0.0" }, "engines": { @@ -1516,17 +1547,6 @@ "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", "dev": true }, - "node_modules/abort-controller": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz", - "integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==", - "dependencies": { - "event-target-shim": "^5.0.0" - }, - "engines": { - "node": ">=6.5" - } - }, "node_modules/acorn": { "version": "7.4.1", "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", @@ -2057,16 +2077,16 @@ "dev": true }, "node_modules/browserslist": { - "version": "4.16.6", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.16.6.tgz", - "integrity": "sha512-Wspk/PqO+4W9qp5iUTJsa1B/QrYn1keNCcEP5OvP7WBwT4KaDly0uONYmC6Xa3Z5IqnUgS0KcgLYu1l74x0ZXQ==", + "version": "4.16.7", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.16.7.tgz", + "integrity": "sha512-7I4qVwqZltJ7j37wObBe3SoTz+nS8APaNcrBOlgoirb6/HbEU2XxW/LpUDTCngM6iauwFqmRTuOMfyKnFGY5JA==", "dev": true, "dependencies": { - "caniuse-lite": "^1.0.30001219", + "caniuse-lite": "^1.0.30001248", "colorette": "^1.2.2", - "electron-to-chromium": "^1.3.723", + "electron-to-chromium": "^1.3.793", "escalade": "^3.1.1", - "node-releases": "^1.1.71" + "node-releases": "^1.1.73" }, "bin": { "browserslist": "cli.js" @@ -2101,9 +2121,9 @@ } }, "node_modules/buffer-from": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz", - "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==", + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", "dev": true }, "node_modules/cacheable-lookup": { @@ -2135,7 +2155,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" } @@ -2150,9 +2169,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001243", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001243.tgz", - "integrity": "sha512-vNxw9mkTBtkmLFnJRv/2rhs1yufpDfCkBZexG3Y0xdOH2Z/eE/85E4Dl5j1YUN34nZVsSp6vVRFQRrez9wJMRA==", + "version": "1.0.30001249", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001249.tgz", + "integrity": "sha512-vcX4U8lwVXPdqzPWi6cAJ3FnQaqXbBqy/GZseKNQzRj37J7qZdGcBtxq/QLFNLLlfsoXLUdHw8Iwenri86Tagw==", "dev": true, "funding": { "type": "opencollective", @@ -2160,9 +2179,9 @@ } }, "node_modules/chalk": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.1.tgz", - "integrity": "sha512-diHzdDKxcU+bAsUboHLPEDQiw0qEe0qd7SYUn3HgcFlWgbDcfLGswOHYeGrHKzG9z6UYf01d9VFMfZxPM1xZSg==", + "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", @@ -2212,9 +2231,9 @@ "dev": true }, "node_modules/cjs-module-lexer": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-1.2.1.tgz", - "integrity": "sha512-jVamGdJPDeuQilKhvVn1h3knuMOZzr8QDnpk+M9aMlCaMkTDd6fBWPhiDqFvFZ07pL0liqabAiuy8SY4jGHeaw==", + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-1.2.2.tgz", + "integrity": "sha512-cOU9usZw8/dXIXKtwa8pM0OTJQuJkxMN6w30csNRUerHfeQ5R6U3kkU/FtJeIf3M202OHfY2U8ccInBG7/xogA==", "dev": true }, "node_modules/cli-boxes": { @@ -2283,9 +2302,9 @@ "dev": true }, "node_modules/colorette": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/colorette/-/colorette-1.2.2.tgz", - "integrity": "sha512-MKGMzyfeuutC/ZJ1cba9NqcNpfeqMUcYmyF1ZFY6/Cn7CNSAKx6a+s48sqLqyAiZuaP2TcqMhoo+dlwFnVxT9w==", + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/colorette/-/colorette-1.3.0.tgz", + "integrity": "sha512-ecORCqbSFP7Wm8Y6lyqMJjexBQqXSF7SSeaTyGGphogUjBlFP9m9o08wy86HL2uB7fMTxtOUzLMk7ogKcxMg1w==", "dev": true }, "node_modules/combined-stream": { @@ -2322,6 +2341,18 @@ "node": ">=8" } }, + "node_modules/configstore/node_modules/dot-prop": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-5.3.0.tgz", + "integrity": "sha512-QM8q3zDe58hqUqjraQOmzZ1LIH9SWQJTlEKCH4kJ2oQvLZk7RbQXvtDM2XEq3fwkV9CCvvH4LA0AV+ogFsBM2Q==", + "dev": true, + "dependencies": { + "is-obj": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/convert-source-map": { "version": "1.8.0", "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.8.0.tgz", @@ -2548,22 +2579,39 @@ "node": ">=8" } }, + "node_modules/discord-api-types": { + "version": "0.22.0", + "resolved": "https://registry.npmjs.org/discord-api-types/-/discord-api-types-0.22.0.tgz", + "integrity": "sha512-l8yD/2zRbZItUQpy7ZxBJwaLX/Bs2TGaCthRppk8Sw24LOIWg12t9JEreezPoYD0SQcC2htNNo27kYEpYW/Srg==", + "engines": { + "node": ">=12" + } + }, "node_modules/discord.js": { - "version": "12.5.3", - "resolved": "https://registry.npmjs.org/discord.js/-/discord.js-12.5.3.tgz", - "integrity": "sha512-D3nkOa/pCkNyn6jLZnAiJApw2N9XrIsXUAdThf01i7yrEuqUmDGc7/CexVWwEcgbQR97XQ+mcnqJpmJ/92B4Aw==", + "version": "13.0.1", + "resolved": "https://registry.npmjs.org/discord.js/-/discord.js-13.0.1.tgz", + "integrity": "sha512-pEODCFfxypBnGEYpSgjkn1jt70raCS1um7Zp0AXEfW1DcR29wISzQ/WeWdnjP5KTXGi0LTtkRiUjOsMgSoukxA==", "dependencies": { - "@discordjs/collection": "^0.1.6", + "@discordjs/builders": "^0.4.0", + "@discordjs/collection": "^0.2.1", "@discordjs/form-data": "^3.0.1", - "abort-controller": "^3.0.0", + "@sapphire/async-queue": "^1.1.4", + "@types/ws": "^7.4.7", + "discord-api-types": "^0.22.0", "node-fetch": "^2.6.1", - "prism-media": "^1.2.9", - "setimmediate": "^1.0.5", - "tweetnacl": "^1.0.3", - "ws": "^7.4.4" + "ws": "^7.5.1" }, "engines": { - "node": ">=12.0.0" + "node": ">=16.6.0", + "npm": ">=7.0.0" + } + }, + "node_modules/discord.js/node_modules/@discordjs/collection": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/@discordjs/collection/-/collection-0.2.1.tgz", + "integrity": "sha512-vhxqzzM8gkomw0TYRF3tgx7SwElzUlXT/Aa41O7mOcyN6wIJfj5JmDWaO5XGKsGSsNx7F3i5oIlrucCCWV1Nog==", + "engines": { + "node": ">=14.0.0" } }, "node_modules/doctrine": { @@ -2600,15 +2648,17 @@ } }, "node_modules/dot-prop": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-5.3.0.tgz", - "integrity": "sha512-QM8q3zDe58hqUqjraQOmzZ1LIH9SWQJTlEKCH4kJ2oQvLZk7RbQXvtDM2XEq3fwkV9CCvvH4LA0AV+ogFsBM2Q==", - "dev": true, + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-6.0.1.tgz", + "integrity": "sha512-tE7ztYzXHIeyvc7N+hR3oi7FIbf/NIjVP9hmAt3yMXzrQ072/fpjGLx2GxNxGxUl5V73MEqYzioOMoVhGMJ5cA==", "dependencies": { "is-obj": "^2.0.0" }, "engines": { - "node": ">=8" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/dotenv": { @@ -2626,9 +2676,9 @@ "dev": true }, "node_modules/electron-to-chromium": { - "version": "1.3.772", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.772.tgz", - "integrity": "sha512-X/6VRCXWALzdX+RjCtBU6cyg8WZgoxm9YA02COmDOiNJEZ59WkQggDbWZ4t/giHi/3GS+cvdrP6gbLISANAGYA==", + "version": "1.3.801", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.801.tgz", + "integrity": "sha512-xapG8ekC+IAHtJrGBMQSImNuN+dm+zl7UP1YbhvTkwQn8zf/yYuoxfTSAEiJ9VDD+kjvXaAhNDPSxJ+VImtAJA==", "dev": true }, "node_modules/emittery": { @@ -2781,13 +2831,13 @@ } }, "node_modules/eslint": { - "version": "7.30.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-7.30.0.tgz", - "integrity": "sha512-VLqz80i3as3NdloY44BQSJpFw534L9Oh+6zJOUaViV4JPd+DaHwutqP7tcpkW3YiXbK6s05RZl7yl7cQn+lijg==", + "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.2", + "@eslint/eslintrc": "^0.4.3", "@humanwhocodes/config-array": "^0.5.0", "ajv": "^6.10.0", "chalk": "^4.0.0", @@ -2997,14 +3047,6 @@ "node": ">=0.10.0" } }, - "node_modules/event-target-shim": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz", - "integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==", - "engines": { - "node": ">=6" - } - }, "node_modules/execa": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", @@ -3199,45 +3241,17 @@ "integrity": "sha512-4zPxDyhCyiN2wIAtSLI6gc82/EjqZc1onI4Mz/l0pWrAlsSfYH/2ZIcU+e3oA2wDwbzIWNKwa23F8rh6+DRWkw==" }, "node_modules/flatted": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.1.tgz", - "integrity": "sha512-OMQjaErSFHmHqZe+PSidH5n8j3O0F2DdnVh8JB4j4eUQ2k6KvB0qGfrKIhapvez5JerBbmWkaLYUYWISaESoXg==", + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.2.tgz", + "integrity": "sha512-JaTY/wtrcSyvXJl4IMFHPKyFur1sE9AUqc0QnhOaJ0CxHtAoIV8pYDzeEfAaNEtGkOfq4gr3LBFmdXW5mOQFnA==", "dev": true }, - "node_modules/form-data": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-3.0.1.tgz", - "integrity": "sha512-RHkBKtLWUVwd7SqRIvCZMEvAMoGUp0XU+seQiZejj0COz3RI3hWP4sCv3gZWWLjJTd7rGwcsF5eKZGii0r/hbg==", - "dev": true, - "dependencies": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.8", - "mime-types": "^2.1.12" - }, - "engines": { - "node": ">= 6" - } - }, "node_modules/fs.realpath": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", "dev": true }, - "node_modules/fsevents": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", - "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", - "dev": true, - "hasInstallScript": true, - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^8.16.0 || ^10.6.0 || >=11.0.0" - } - }, "node_modules/function-bind": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", @@ -3407,9 +3421,9 @@ } }, "node_modules/graceful-fs": { - "version": "4.2.6", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.6.tgz", - "integrity": "sha512-nTnJ528pbqxYanhpDYsi4Rd8MAeaBA67+RZ10CM1m3bTAVFEDcd5AuA4a6W5YkGZ1iNXHzZz8T6TBKLeBuNriQ==", + "version": "4.2.8", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.8.tgz", + "integrity": "sha512-qkIilPUYcNhJpd33n0GBXTB1MMPp14TxEsEs0pTrsSVucApsYzW5V+Q8Qxhik6KU3evy+qkAAowTByymK0avdg==", "dev": true }, "node_modules/has": { @@ -3642,9 +3656,9 @@ } }, "node_modules/is-core-module": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.4.0.tgz", - "integrity": "sha512-6A2fkfq1rfeQZjxrZJGerpLCTHRNEBiSgnu0+obeJpEPZRUooHgsizvzv0ZjJwOz3iWIHdJtVWJ/tmPr3D21/A==", + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.5.0.tgz", + "integrity": "sha512-TXCMSDsEHMEEZ6eCA8rwRDbLu55MRGmrctljsBX/2v1d9/GzqHOxW5c5oPSgrUt2vBFXebu9rGqckXGPWOlYpg==", "dev": true, "dependencies": { "has": "^1.0.3" @@ -3730,7 +3744,6 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-2.0.0.tgz", "integrity": "sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==", - "dev": true, "engines": { "node": ">=8" } @@ -3751,12 +3764,15 @@ "dev": true }, "node_modules/is-stream": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.0.tgz", - "integrity": "sha512-XCoy+WlUr7d1+Z8GgSuXmpuUFC9fOhRXglJMx+dwLKTkL44Cjd4W1Z5P+BQZpr+cR93aGP4S/s7Ftw6Nd/kiEw==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", "dev": true, "engines": { "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/is-typedarray": { @@ -4818,9 +4834,9 @@ } }, "node_modules/jsdom": { - "version": "16.6.0", - "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-16.6.0.tgz", - "integrity": "sha512-Ty1vmF4NHJkolaEmdjtxTfSfkdb8Ywarwf63f+F8/mDD1uLSSWDxDuMiZxiPhwunLrn9LOSVItWj4bLYsLN3Dg==", + "version": "16.7.0", + "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-16.7.0.tgz", + "integrity": "sha512-u9Smc2G1USStM+s/x1ru5Sxrl6mPYCbByG1U/hUmqaVsm4tbNyS7CicOSRyuGQYZhTu0h84qkZZQ/I+dzizSVw==", "dev": true, "dependencies": { "abab": "^2.0.5", @@ -4848,7 +4864,7 @@ "whatwg-encoding": "^1.0.5", "whatwg-mimetype": "^2.3.0", "whatwg-url": "^8.5.0", - "ws": "^7.4.5", + "ws": "^7.4.6", "xml-name-validator": "^3.0.0" }, "engines": { @@ -4875,6 +4891,20 @@ "node": ">=0.4.0" } }, + "node_modules/jsdom/node_modules/form-data": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-3.0.1.tgz", + "integrity": "sha512-RHkBKtLWUVwd7SqRIvCZMEvAMoGUp0XU+seQiZejj0COz3RI3hWP4sCv3gZWWLjJTd7rGwcsF5eKZGii0r/hbg==", + "dev": true, + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/jsesc": { "version": "2.5.2", "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", @@ -4994,6 +5024,11 @@ "integrity": "sha1-4j8/nE+Pvd6HJSnBBxhXoIblzO8=", "dev": true }, + "node_modules/lodash.isequal": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.isequal/-/lodash.isequal-4.5.0.tgz", + "integrity": "sha1-QVxEePK8wwEgwizhDtMib30+GOA=" + }, "node_modules/lodash.merge": { "version": "4.6.2", "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", @@ -5094,19 +5129,19 @@ } }, "node_modules/mime-db": { - "version": "1.48.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.48.0.tgz", - "integrity": "sha512-FM3QwxV+TnZYQ2aRqhlKBMHxk10lTbMt3bBkMAp54ddrNeVSfcQYOOKuGuy3Ddrm38I04If834fOUSq1yzslJQ==", + "version": "1.49.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.49.0.tgz", + "integrity": "sha512-CIc8j9URtOVApSFCQIF+VBkX1RwXp/oMMOrqdyXSBXq5RWNEsRfyj1kiRnQgmNXmHxPoFIxOroKA3zcU9P+nAA==", "engines": { "node": ">= 0.6" } }, "node_modules/mime-types": { - "version": "2.1.31", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.31.tgz", - "integrity": "sha512-XGZnNzm3QvgKxa8dpzyhFTHmpP3l5YNusmne07VUOXxou9CqUqYa/HBy124RqtVh/O2pECas/MOcsDgpilPOPg==", + "version": "2.1.32", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.32.tgz", + "integrity": "sha512-hJGaVS4G4c9TSMYh2n6SQAGrC4RnfU+daP8G7cSCmaqNjiOoUY0VHCMS42pxnQmVF1GWwFhbHWn3RIxCqTmZ9A==", "dependencies": { - "mime-db": "1.48.0" + "mime-db": "1.49.0" }, "engines": { "node": ">= 0.6" @@ -5389,6 +5424,36 @@ "node": ">= 0.8.0" } }, + "node_modules/ow": { + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/ow/-/ow-0.27.0.tgz", + "integrity": "sha512-SGnrGUbhn4VaUGdU0EJLMwZWSupPmF46hnTRII7aCLCrqixTAC5eKo8kI4/XXf1eaaI8YEVT+3FeGNJI9himAQ==", + "dependencies": { + "@sindresorhus/is": "^4.0.1", + "callsites": "^3.1.0", + "dot-prop": "^6.0.1", + "lodash.isequal": "^4.5.0", + "type-fest": "^1.2.1", + "vali-date": "^1.0.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ow/node_modules/type-fest": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-1.4.0.tgz", + "integrity": "sha512-yGSza74xk0UG8k+pLh5oeoYirvIiWo5t0/o3zHHAO2tRDiZcxWP7fywNlXhqb6/r6sWvwi+RsyQMWhVLe4BVuA==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/p-cancelable": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-2.1.1.tgz", @@ -5693,9 +5758,9 @@ } }, "node_modules/pino": { - "version": "6.12.0", - "resolved": "https://registry.npmjs.org/pino/-/pino-6.12.0.tgz", - "integrity": "sha512-5NGopOcUusGuklGHVVv9az0Hv/Dj3urHhD3G+zhl5pBGIRYAeGCi/Ej6YCl16Q2ko28cmYiJz+/qRoJiwy62Rw==", + "version": "6.13.0", + "resolved": "https://registry.npmjs.org/pino/-/pino-6.13.0.tgz", + "integrity": "sha512-mRXSTfa34tbfrWqCIp1sUpZLqBhcoaGapoyxfEwaWwJGMpLijlRdDKIQUyvq4M3DUfFH5vEglwSw8POZYwbThA==", "dependencies": { "fast-redact": "^3.0.0", "fast-safe-stringify": "^2.0.8", @@ -5709,9 +5774,9 @@ } }, "node_modules/pino-pretty": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/pino-pretty/-/pino-pretty-5.1.1.tgz", - "integrity": "sha512-bG8a6A2QcZYJXD/ZL7PXn8CDNIUP5TKyQwR9Yjzn5dpGyQ7Wbyl707Dxhx+tPT3BG6YpsXF93Hhe9EUnx0SsPw==", + "version": "5.1.3", + "resolved": "https://registry.npmjs.org/pino-pretty/-/pino-pretty-5.1.3.tgz", + "integrity": "sha512-Zj+0TVdYKkAAIx9EUCL5e4TttwgsaFvJh2ceIMQeFCY8ak9tseEZQGSgpvyjEj1/iIVGIh5tdhkGEQWSMILKHA==", "dev": true, "dependencies": { "@hapi/bourne": "^2.0.0", @@ -5736,6 +5801,15 @@ "resolved": "https://registry.npmjs.org/pino-std-serializers/-/pino-std-serializers-3.2.0.tgz", "integrity": "sha512-EqX4pwDPrt3MuOAAUBMU0Tk5kR/YcCM5fNPEzgCO2zJ5HfX0vbiH9HbJglnyeQsN96Kznae6MWD47pZB5avTrg==" }, + "node_modules/pino/node_modules/sonic-boom": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/sonic-boom/-/sonic-boom-1.4.1.tgz", + "integrity": "sha512-LRHh/A8tpW7ru89lrlkU4AszXt1dbwSjVWguGrmlxE7tawVmDBlI1PILMkXAxJTwqhgsEeTHzj36D5CmHgQmNg==", + "dependencies": { + "atomic-sleep": "^1.0.0", + "flatstr": "^1.0.12" + } + }, "node_modules/pirates": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.1.tgz", @@ -5830,31 +5904,6 @@ "@types/yargs-parser": "*" } }, - "node_modules/prism-media": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/prism-media/-/prism-media-1.3.1.tgz", - "integrity": "sha512-nyYAa3KB4qteJIqdguKmwxTJgy55xxUtkJ3uRnOvO5jO+frci+9zpRXw6QZVcfDeva3S654fU9+26P2OSTzjHw==", - "peerDependencies": { - "@discordjs/opus": "^0.5.0", - "ffmpeg-static": "^4.2.7 || ^3.0.0 || ^2.4.0", - "node-opus": "^0.3.3", - "opusscript": "^0.0.8" - }, - "peerDependenciesMeta": { - "@discordjs/opus": { - "optional": true - }, - "ffmpeg-static": { - "optional": true - }, - "node-opus": { - "optional": true - }, - "opusscript": { - "optional": true - } - } - }, "node_modules/progress": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", @@ -6079,9 +6128,9 @@ } }, "node_modules/resolve-alpn": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/resolve-alpn/-/resolve-alpn-1.1.2.tgz", - "integrity": "sha512-8OyfzhAtA32LVUsJSke3auIyINcwdh5l3cvYKdKO0nvsYSKuiLfTM5i78PJswFPT8y6cPW+L1v6/hE95chcpDA==" + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/resolve-alpn/-/resolve-alpn-1.2.0.tgz", + "integrity": "sha512-e4FNQs+9cINYMO5NMFc6kOUCdohjqFPSgMuwuZAOUWqrfWsen+Yjy5qZFkV5K7VO7tFSLKcUL97olkED7sCBHA==" }, "node_modules/resolve-cwd": { "version": "3.0.0", @@ -6235,11 +6284,6 @@ "semver": "bin/semver.js" } }, - "node_modules/setimmediate": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", - "integrity": "sha1-KQy7Iy4waULX1+qbg3Mqt4VvgoU=" - }, "node_modules/shebang-command": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", @@ -6300,12 +6344,12 @@ } }, "node_modules/sonic-boom": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/sonic-boom/-/sonic-boom-1.4.1.tgz", - "integrity": "sha512-LRHh/A8tpW7ru89lrlkU4AszXt1dbwSjVWguGrmlxE7tawVmDBlI1PILMkXAxJTwqhgsEeTHzj36D5CmHgQmNg==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/sonic-boom/-/sonic-boom-2.1.0.tgz", + "integrity": "sha512-x2j9LXx27EDlyZEC32gBM+scNVMdPutU7FIKV2BOTKCnPrp7bY5BsplCMQ4shYYR3IhDSIrEXoqb6GlS+z7KyQ==", + "dev": true, "dependencies": { - "atomic-sleep": "^1.0.0", - "flatstr": "^1.0.12" + "atomic-sleep": "^1.0.0" } }, "node_modules/source-map": { @@ -6516,9 +6560,9 @@ } }, "node_modules/table/node_modules/ajv": { - "version": "8.6.1", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.6.1.tgz", - "integrity": "sha512-42VLtQUOLefAvKFAQIxIZDaThq6om/PrfP0CYk3/vn+y4BMNkKnbli8ON2QCiHov4KkzOSJ/xSoBJdayiiYvVQ==", + "version": "8.6.2", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.6.2.tgz", + "integrity": "sha512-9807RlWAgT564wT+DjeyU5OFMPjmzxVobvDFmNAhY+5zD6A2ly3jDp6sgnfyDtlIQ+7H97oc/DGCzzfu9rjw9w==", "dev": true, "dependencies": { "fast-deep-equal": "^3.1.1", @@ -6666,9 +6710,9 @@ } }, "node_modules/ts-jest": { - "version": "27.0.3", - "resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-27.0.3.tgz", - "integrity": "sha512-U5rdMjnYam9Ucw+h0QvtNDbc5+88nxt7tbIvqaZUhFrfG4+SkWhMXjejCLVGcpILTPuV+H3W/GZDZrnZFpPeXw==", + "version": "27.0.4", + "resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-27.0.4.tgz", + "integrity": "sha512-c4E1ECy9Xz2WGfTMyHbSaArlIva7Wi2p43QOMmCqjSSjHP06KXv+aT+eSY+yZMuqsMi3k7pyGsGj2q5oSl5WfQ==", "dev": true, "dependencies": { "bs-logger": "0.x", @@ -6689,25 +6733,46 @@ "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" }, "peerDependencies": { + "@babel/core": ">=7.0.0-beta.0 <8", + "@types/jest": "^26.0.0", + "babel-jest": ">=27.0.0 <28", "jest": "^27.0.0", "typescript": ">=3.8 <5.0" + }, + "peerDependenciesMeta": { + "@babel/core": { + "optional": true + }, + "@types/jest": { + "optional": true + }, + "babel-jest": { + "optional": true + } } }, + "node_modules/ts-mixer": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/ts-mixer/-/ts-mixer-6.0.0.tgz", + "integrity": "sha512-nXIb1fvdY5CBSrDIblLn73NW0qRDk5yJ0Sk1qPBF560OdJfQp9jhl+0tzcY09OZ9U+6GpeoI9RjwoIKFIoB9MQ==" + }, "node_modules/ts-node": { - "version": "10.1.0", - "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.1.0.tgz", - "integrity": "sha512-6szn3+J9WyG2hE+5W8e0ruZrzyk1uFLYye6IGMBadnOzDh8aP7t8CbFpsfCiEx2+wMixAhjFt7lOZC4+l+WbEA==", + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.2.0.tgz", + "integrity": "sha512-FstYHtQz6isj8rBtYMN4bZdnXN1vq4HCbqn9vdNQcInRqtB86PePJQIxE6es0PhxKWhj2PHuwbG40H+bxkZPmg==", "dev": true, "dependencies": { + "@cspotcode/source-map-support": "0.6.1", "@tsconfig/node10": "^1.0.7", "@tsconfig/node12": "^1.0.7", "@tsconfig/node14": "^1.0.0", - "@tsconfig/node16": "^1.0.1", + "@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", - "source-map-support": "^0.5.17", "yn": "3.1.1" }, "bin": { @@ -6735,11 +6800,31 @@ } } }, + "node_modules/ts-node/node_modules/acorn": { + "version": "8.4.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.4.1.tgz", + "integrity": "sha512-asabaBSkEKosYKMITunzX177CXxQ4Q8BSSzMTKD+FefUhipQC70gfW5SiUDhYQ3vk8G+81HqQk7Fv9OXwwn9KA==", + "dev": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/ts-node/node_modules/acorn-walk": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.1.1.tgz", + "integrity": "sha512-FbJdceMlPHEAWJOILDk1fXD8lnTlEIWFkqtfk+MvmL5q/qlHfN7GEHcsFZWt/Tea9jRNPWUZG4G976nqAAmU9w==", + "dev": true, + "engines": { + "node": ">=0.4.0" + } + }, "node_modules/tslib": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", - "dev": true + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.0.tgz", + "integrity": "sha512-N82ooyxVNm6h1riLCoyS9e3fuJ3AMG2zIZs2Gd1ATcSFjSA23Q0fzjjZeh0jbJvWVDZ0cJT8yaNNaaXHzueNjg==" }, "node_modules/tsutils": { "version": "3.21.0", @@ -6756,10 +6841,11 @@ "typescript": ">=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta" } }, - "node_modules/tweetnacl": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-1.0.3.tgz", - "integrity": "sha512-6rt+RN7aOi1nGMyC4Xa5DdYiukl2UWCbcJft7YhxReBGQD7OAM8Pbxw6YMo4r2diNEA8FEmu32YOn9rhaiE5yw==" + "node_modules/tsutils/node_modules/tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true }, "node_modules/type-check": { "version": "0.4.0", @@ -6975,6 +7061,14 @@ "node": ">= 8" } }, + "node_modules/vali-date": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/vali-date/-/vali-date-1.0.0.tgz", + "integrity": "sha1-G5BKWWCfsyjvB4E4Qgk09rhnCaY=", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/w3c-hr-time": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/w3c-hr-time/-/w3c-hr-time-1.0.2.tgz", @@ -7217,26 +7311,26 @@ } }, "@babel/compat-data": { - "version": "7.14.7", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.14.7.tgz", - "integrity": "sha512-nS6dZaISCXJ3+518CWiBfEr//gHyMO02uDxBkXTKZDN5POruCnOZ1N4YBRZDCabwF8nZMWBpRxIicmXtBs+fvw==", + "version": "7.15.0", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.15.0.tgz", + "integrity": "sha512-0NqAC1IJE0S0+lL1SWFMxMkz1pKCNCjI4tr2Zx4LJSXxCLAdr6KyArnY+sno5m3yH9g737ygOyPABDsnXkpxiA==", "dev": true }, "@babel/core": { - "version": "7.14.6", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.14.6.tgz", - "integrity": "sha512-gJnOEWSqTk96qG5BoIrl5bVtc23DCycmIePPYnamY9RboYdI4nFy5vAQMSl81O5K/W0sLDWfGysnOECC+KUUCA==", + "version": "7.15.0", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.15.0.tgz", + "integrity": "sha512-tXtmTminrze5HEUPn/a0JtOzzfp0nk+UEXQ/tqIJo3WDGypl/2OFQEMll/zSFU8f/lfmfLXvTaORHF3cfXIQMw==", "dev": true, "requires": { "@babel/code-frame": "^7.14.5", - "@babel/generator": "^7.14.5", - "@babel/helper-compilation-targets": "^7.14.5", - "@babel/helper-module-transforms": "^7.14.5", - "@babel/helpers": "^7.14.6", - "@babel/parser": "^7.14.6", + "@babel/generator": "^7.15.0", + "@babel/helper-compilation-targets": "^7.15.0", + "@babel/helper-module-transforms": "^7.15.0", + "@babel/helpers": "^7.14.8", + "@babel/parser": "^7.15.0", "@babel/template": "^7.14.5", - "@babel/traverse": "^7.14.5", - "@babel/types": "^7.14.5", + "@babel/traverse": "^7.15.0", + "@babel/types": "^7.15.0", "convert-source-map": "^1.7.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.2", @@ -7269,12 +7363,12 @@ } }, "@babel/generator": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.14.5.tgz", - "integrity": "sha512-y3rlP+/G25OIX3mYKKIOlQRcqj7YgrvHxOLbVmyLJ9bPmi5ttvUmpydVjcFjZphOktWuA7ovbx91ECloWTfjIA==", + "version": "7.15.0", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.15.0.tgz", + "integrity": "sha512-eKl4XdMrbpYvuB505KTta4AV9g+wWzmVBW69tX0H2NwKVKd2YJbKgyK6M8j/rgLbmHOYJn6rUklV677nOyJrEQ==", "dev": true, "requires": { - "@babel/types": "^7.14.5", + "@babel/types": "^7.15.0", "jsesc": "^2.5.1", "source-map": "^0.5.0" }, @@ -7288,12 +7382,12 @@ } }, "@babel/helper-compilation-targets": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.14.5.tgz", - "integrity": "sha512-v+QtZqXEiOnpO6EYvlImB6zCD2Lel06RzOPzmkz/D/XgQiUu3C/Jb1LOqSt/AIA34TYi/Q+KlT8vTQrgdxkbLw==", + "version": "7.15.0", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.15.0.tgz", + "integrity": "sha512-h+/9t0ncd4jfZ8wsdAsoIxSa61qhBYlycXiHWqJaQBCXAhDCMbPRSMTGnZIkkmt1u4ag+UQmuqcILwqKzZ4N2A==", "dev": true, "requires": { - "@babel/compat-data": "^7.14.5", + "@babel/compat-data": "^7.15.0", "@babel/helper-validator-option": "^7.14.5", "browserslist": "^4.16.6", "semver": "^6.3.0" @@ -7337,12 +7431,12 @@ } }, "@babel/helper-member-expression-to-functions": { - "version": "7.14.7", - "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.14.7.tgz", - "integrity": "sha512-TMUt4xKxJn6ccjcOW7c4hlwyJArizskAhoSTOCkA0uZ+KghIaci0Qg9R043kUMWI9mtQfgny+NQ5QATnZ+paaA==", + "version": "7.15.0", + "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.15.0.tgz", + "integrity": "sha512-Jq8H8U2kYiafuj2xMTPQwkTBnEEdGKpT35lJEQsRRjnG0LW3neucsaMWLgKcwu3OHKNeYugfw+Z20BXBSEs2Lg==", "dev": true, "requires": { - "@babel/types": "^7.14.5" + "@babel/types": "^7.15.0" } }, "@babel/helper-module-imports": { @@ -7355,19 +7449,19 @@ } }, "@babel/helper-module-transforms": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.14.5.tgz", - "integrity": "sha512-iXpX4KW8LVODuAieD7MzhNjmM6dzYY5tfRqT+R9HDXWl0jPn/djKmA+G9s/2C2T9zggw5tK1QNqZ70USfedOwA==", + "version": "7.15.0", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.15.0.tgz", + "integrity": "sha512-RkGiW5Rer7fpXv9m1B3iHIFDZdItnO2/BLfWVW/9q7+KqQSDY5kUfQEbzdXM1MVhJGcugKV7kRrNVzNxmk7NBg==", "dev": true, "requires": { "@babel/helper-module-imports": "^7.14.5", - "@babel/helper-replace-supers": "^7.14.5", - "@babel/helper-simple-access": "^7.14.5", + "@babel/helper-replace-supers": "^7.15.0", + "@babel/helper-simple-access": "^7.14.8", "@babel/helper-split-export-declaration": "^7.14.5", - "@babel/helper-validator-identifier": "^7.14.5", + "@babel/helper-validator-identifier": "^7.14.9", "@babel/template": "^7.14.5", - "@babel/traverse": "^7.14.5", - "@babel/types": "^7.14.5" + "@babel/traverse": "^7.15.0", + "@babel/types": "^7.15.0" } }, "@babel/helper-optimise-call-expression": { @@ -7386,24 +7480,24 @@ "dev": true }, "@babel/helper-replace-supers": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.14.5.tgz", - "integrity": "sha512-3i1Qe9/8x/hCHINujn+iuHy+mMRLoc77b2nI9TB0zjH1hvn9qGlXjWlggdwUcju36PkPCy/lpM7LLUdcTyH4Ow==", + "version": "7.15.0", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.15.0.tgz", + "integrity": "sha512-6O+eWrhx+HEra/uJnifCwhwMd6Bp5+ZfZeJwbqUTuqkhIT6YcRhiZCOOFChRypOIe0cV46kFrRBlm+t5vHCEaA==", "dev": true, "requires": { - "@babel/helper-member-expression-to-functions": "^7.14.5", + "@babel/helper-member-expression-to-functions": "^7.15.0", "@babel/helper-optimise-call-expression": "^7.14.5", - "@babel/traverse": "^7.14.5", - "@babel/types": "^7.14.5" + "@babel/traverse": "^7.15.0", + "@babel/types": "^7.15.0" } }, "@babel/helper-simple-access": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.14.5.tgz", - "integrity": "sha512-nfBN9xvmCt6nrMZjfhkl7i0oTV3yxR4/FztsbOASyTvVcoYd0TRHh7eMLdlEcCqobydC0LAF3LtC92Iwxo0wyw==", + "version": "7.14.8", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.14.8.tgz", + "integrity": "sha512-TrFN4RHh9gnWEU+s7JloIho2T76GPwRHhdzOWLqTrMnlas8T9O7ec+oEDNsRXndOmru9ymH9DFrEOxpzPoSbdg==", "dev": true, "requires": { - "@babel/types": "^7.14.5" + "@babel/types": "^7.14.8" } }, "@babel/helper-split-export-declaration": { @@ -7416,9 +7510,9 @@ } }, "@babel/helper-validator-identifier": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.14.5.tgz", - "integrity": "sha512-5lsetuxCLilmVGyiLEfoHBRX8UCFD+1m2x3Rj97WrW3V7H3u4RWRXA4evMjImCsin2J2YT0QaVDGf+z8ondbAg==", + "version": "7.14.9", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.14.9.tgz", + "integrity": "sha512-pQYxPY0UP6IHISRitNe8bsijHex4TWZXi2HwKVsjPiltzlhse2znVcm9Ace510VT1kxIHjGJCZZQBX2gJDbo0g==", "dev": true }, "@babel/helper-validator-option": { @@ -7428,14 +7522,14 @@ "dev": true }, "@babel/helpers": { - "version": "7.14.6", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.14.6.tgz", - "integrity": "sha512-yesp1ENQBiLI+iYHSJdoZKUtRpfTlL1grDIX9NRlAVppljLw/4tTyYupIB7uIYmC3stW/imAv8EqaKaS/ibmeA==", + "version": "7.14.8", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.14.8.tgz", + "integrity": "sha512-ZRDmI56pnV+p1dH6d+UN6GINGz7Krps3+270qqI9UJ4wxYThfAIcI5i7j5vXC4FJ3Wap+S9qcebxeYiqn87DZw==", "dev": true, "requires": { "@babel/template": "^7.14.5", - "@babel/traverse": "^7.14.5", - "@babel/types": "^7.14.5" + "@babel/traverse": "^7.14.8", + "@babel/types": "^7.14.8" } }, "@babel/highlight": { @@ -7508,9 +7602,9 @@ } }, "@babel/parser": { - "version": "7.14.7", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.14.7.tgz", - "integrity": "sha512-X67Z5y+VBJuHB/RjwECp8kSl5uYi0BvRbNeWqkaJCVh+LiTPl19WBUfG627psSgp9rSf6ojuXghQM3ha6qHHdA==", + "version": "7.15.2", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.15.2.tgz", + "integrity": "sha512-bMJXql1Ss8lFnvr11TZDH4ArtwlAS5NG9qBmdiFW2UHHm6MVoR+GDc5XE2b9K938cyjc9O6/+vjjcffLDtfuDg==", "dev": true }, "@babel/plugin-syntax-async-generators": { @@ -7653,18 +7747,18 @@ } }, "@babel/traverse": { - "version": "7.14.7", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.14.7.tgz", - "integrity": "sha512-9vDr5NzHu27wgwejuKL7kIOm4bwEtaPQ4Z6cpCmjSuaRqpH/7xc4qcGEscwMqlkwgcXl6MvqoAjZkQ24uSdIZQ==", + "version": "7.15.0", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.15.0.tgz", + "integrity": "sha512-392d8BN0C9eVxVWd8H6x9WfipgVH5IaIoLp23334Sc1vbKKWINnvwRpb4us0xtPaCumlwbTtIYNA0Dv/32sVFw==", "dev": true, "requires": { "@babel/code-frame": "^7.14.5", - "@babel/generator": "^7.14.5", + "@babel/generator": "^7.15.0", "@babel/helper-function-name": "^7.14.5", "@babel/helper-hoist-variables": "^7.14.5", "@babel/helper-split-export-declaration": "^7.14.5", - "@babel/parser": "^7.14.7", - "@babel/types": "^7.14.5", + "@babel/parser": "^7.15.0", + "@babel/types": "^7.15.0", "debug": "^4.1.0", "globals": "^11.1.0" }, @@ -7687,12 +7781,12 @@ } }, "@babel/types": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.14.5.tgz", - "integrity": "sha512-M/NzBpEL95I5Hh4dwhin5JlE7EzO5PHMAuzjxss3tiOBD46KfQvVedN/3jEPZvdRvtsK2222XfdHogNIttFgcg==", + "version": "7.15.0", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.15.0.tgz", + "integrity": "sha512-OBvfqnllOIdX4ojTHpwZbpvz4j3EWyjkZEdmjH0/cgsd6QOdSgU8rLSk6ard/pcW7rlmjdVSX/AWOaORR1uNOQ==", "dev": true, "requires": { - "@babel/helper-validator-identifier": "^7.14.5", + "@babel/helper-validator-identifier": "^7.14.9", "to-fast-properties": "^2.0.0" } }, @@ -7702,10 +7796,32 @@ "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==", "dev": true }, - "@discordjs/collection": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/@discordjs/collection/-/collection-0.1.6.tgz", - "integrity": "sha512-utRNxnd9kSS2qhyivo9lMlt5qgAUasH2gb7BEOn6p0efFh24gjGomHzWKMAPn2hEReOPQZCJaRKoURwRotKucQ==" + "@cspotcode/source-map-consumer": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/@cspotcode/source-map-consumer/-/source-map-consumer-0.8.0.tgz", + "integrity": "sha512-41qniHzTU8yAGbCp04ohlmSrZf8bkf/iJsl3V0dRGsQN/5GFfx+LbCSsCpp2gqrqjTVg/K6O8ycoV35JIwAzAg==", + "dev": true + }, + "@cspotcode/source-map-support": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.6.1.tgz", + "integrity": "sha512-DX3Z+T5dt1ockmPdobJS/FAsQPW4V4SrWEhD2iYQT2Cb2tQsiMnYxrcUH9By/Z3B+v0S5LMBkQtV/XOBbpLEOg==", + "dev": true, + "requires": { + "@cspotcode/source-map-consumer": "0.8.0" + } + }, + "@discordjs/builders": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/@discordjs/builders/-/builders-0.4.0.tgz", + "integrity": "sha512-EiwLltKph6TSaPJIzJYdzNc1PnA2ZNaaE0t0ODg3ghnpVHqfgd0YX9/srsleYHW2cw1sfIq+kbM+h0etf7GWLA==", + "requires": { + "@sindresorhus/is": "^4.0.1", + "discord-api-types": "^0.22.0", + "ow": "^0.27.0", + "ts-mixer": "^6.0.0", + "tslib": "^2.3.0" + } }, "@discordjs/form-data": { "version": "3.0.1", @@ -7718,9 +7834,9 @@ } }, "@eslint/eslintrc": { - "version": "0.4.2", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-0.4.2.tgz", - "integrity": "sha512-8nmGq/4ycLpIwzvhI4tNDmQztZ8sp+hI7cyG8i1nQDhkAbRzHpXPidRAHlNvCZQpJTKw5ItIpMw9RSToGF00mg==", + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-0.4.3.tgz", + "integrity": "sha512-J6KFFz5QCYUJq3pf0mjEcCJVERbzv71PUIDczuh9JkwGEzced6CO5ADLHB1rbf/+oPBtoPfMYNOpGDzCANlbXw==", "dev": true, "requires": { "ajv": "^6.12.4", @@ -8001,6 +8117,11 @@ "fastq": "^1.6.0" } }, + "@sapphire/async-queue": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/@sapphire/async-queue/-/async-queue-1.1.4.tgz", + "integrity": "sha512-fFrlF/uWpGOX5djw5Mu2Hnnrunao75WGey0sP0J3jnhmrJ5TAPzHYOmytD5iN/+pMxS+f+u/gezqHa9tPhRHEA==" + }, "@sindresorhus/is": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-4.0.1.tgz", @@ -8025,9 +8146,9 @@ } }, "@szmarczak/http-timer": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-4.0.5.tgz", - "integrity": "sha512-PyRA9sm1Yayuj5OIoJ1hGt2YISX45w9WcFbh6ddT0Z/0yaFxOtGLInr4jUfU1EAFVs0Yfyfev4RNwBlUaHdlDQ==", + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-4.0.6.tgz", + "integrity": "sha512-4BAffykYOgO+5nzBWYwE3W90sBgLJoUPRWWcL8wlyiM8IB8ipJz3UMJ9KXQd1RKQXpKp8Tutn80HZtWsu2u76w==", "requires": { "defer-to-connect": "^2.0.0" } @@ -8057,9 +8178,9 @@ "dev": true }, "@tsconfig/node16": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.1.tgz", - "integrity": "sha512-FTgBI767POY/lKNDNbIzgAX6miIDBs6NTCbdlDb8TrWovHsSvaVIZDlTqym29C6UqhzwcJx4CYr+AlrMywA0cA==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.2.tgz", + "integrity": "sha512-eZxlbI8GZscaGS7kkc/trHTT5xgrjH3/1n2JDwusC9iahPKWMRvRjJSAN5mCXviuTGQ/lHnhvv8Q1YTpnfz9gA==", "dev": true }, "@types/babel__core": { @@ -8179,9 +8300,9 @@ } }, "@types/json-schema": { - "version": "7.0.8", - "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.8.tgz", - "integrity": "sha512-YSBPTLTVm2e2OoQIDYx8HaeWJ5tTToLH67kXR7zYNGupXMEHa2++G8k+DczX2cFVgalypqtyZIcU19AFcmOpmg==", + "version": "7.0.9", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.9.tgz", + "integrity": "sha512-qcUXuemtEu+E5wZSJHNxUXeCZhAfXKQ41D+duX+VYPde7xyEVZci+/oXKJL13tnRs9lR2pr4fod59GT6/X1/yQ==", "dev": true }, "@types/keyv": { @@ -8198,15 +8319,15 @@ "integrity": "sha512-bLL69sKtd25w7p1nvg9pigE4gtKVpGTPojBFLMkGHXuUgap2sLqQt2qUnqmVCDfzGUL0DRNZP+1prIZJbMeAXg==" }, "@types/pino": { - "version": "6.3.9", - "resolved": "https://registry.npmjs.org/@types/pino/-/pino-6.3.9.tgz", - "integrity": "sha512-2/XV6adNNCLWnT2lJqcSn/OXrCxRFOY6yXYoofrLy5Ts5e8RHTJP1M4XEcCarQQMa6H6JISaa4GkrlGZwIP5aQ==", + "version": "6.3.11", + "resolved": "https://registry.npmjs.org/@types/pino/-/pino-6.3.11.tgz", + "integrity": "sha512-S7+fLONqSpHeW9d7TApUqO6VN47KYgOXhCNKwGBVLHObq8HhaAYlVqUNdfnvoXjCMiwE5xcPm/5R2ZUh8bgaXQ==", "dev": true, "requires": { "@types/node": "*", "@types/pino-pretty": "*", "@types/pino-std-serializers": "*", - "@types/sonic-boom": "*" + "sonic-boom": "^2.1.0" } }, "@types/pino-pretty": { @@ -8241,15 +8362,6 @@ "@types/node": "*" } }, - "@types/sonic-boom": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/@types/sonic-boom/-/sonic-boom-0.7.0.tgz", - "integrity": "sha512-AfqR0fZMoUXUNwusgXKxcE9DPlHNDHQp6nKYUd4PSRpLobF5CCevSpyTEBcVZreqaWKCnGBr9KI1fHMTttoB7A==", - "dev": true, - "requires": { - "@types/node": "*" - } - }, "@types/stack-utils": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.1.tgz", @@ -8257,10 +8369,9 @@ "dev": true }, "@types/ws": { - "version": "7.4.6", - "resolved": "https://registry.npmjs.org/@types/ws/-/ws-7.4.6.tgz", - "integrity": "sha512-ijZ1vzRawI7QoWnTNL8KpHixd2b2XVb9I9HAqI3triPsh1EC0xH0Eg6w2O3TKbDCgiNNlJqfrof6j4T2I+l9vw==", - "dev": true, + "version": "7.4.7", + "resolved": "https://registry.npmjs.org/@types/ws/-/ws-7.4.7.tgz", + "integrity": "sha512-JQbbmxZTZehdc2iszGKs5oC3NFnjeay7mtAWrdt7qNtAVK0g19muApzAy4bm9byz79xa2ZnO/BOBC2R8RC5Lww==", "requires": { "@types/node": "*" } @@ -8281,13 +8392,13 @@ "dev": true }, "@typescript-eslint/eslint-plugin": { - "version": "4.28.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.28.2.tgz", - "integrity": "sha512-PGqpLLzHSxq956rzNGasO3GsAPf2lY9lDUBXhS++SKonglUmJypaUtcKzRtUte8CV7nruwnDxtLUKpVxs0wQBw==", + "version": "4.29.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.29.1.tgz", + "integrity": "sha512-AHqIU+SqZZgBEiWOrtN94ldR3ZUABV5dUG94j8Nms9rQnHFc8fvDOue/58K4CFz6r8OtDDc35Pw9NQPWo0Ayrw==", "dev": true, "requires": { - "@typescript-eslint/experimental-utils": "4.28.2", - "@typescript-eslint/scope-manager": "4.28.2", + "@typescript-eslint/experimental-utils": "4.29.1", + "@typescript-eslint/scope-manager": "4.29.1", "debug": "^4.3.1", "functional-red-black-tree": "^1.0.1", "regexpp": "^3.1.0", @@ -8296,55 +8407,55 @@ } }, "@typescript-eslint/experimental-utils": { - "version": "4.28.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-4.28.2.tgz", - "integrity": "sha512-MwHPsL6qo98RC55IoWWP8/opTykjTp4JzfPu1VfO2Z0MshNP0UZ1GEV5rYSSnZSUI8VD7iHvtIPVGW5Nfh7klQ==", + "version": "4.29.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-4.29.1.tgz", + "integrity": "sha512-kl6QG6qpzZthfd2bzPNSJB2YcZpNOrP6r9jueXupcZHnL74WiuSjaft7WSu17J9+ae9zTlk0KJMXPUj0daBxMw==", "dev": true, "requires": { "@types/json-schema": "^7.0.7", - "@typescript-eslint/scope-manager": "4.28.2", - "@typescript-eslint/types": "4.28.2", - "@typescript-eslint/typescript-estree": "4.28.2", + "@typescript-eslint/scope-manager": "4.29.1", + "@typescript-eslint/types": "4.29.1", + "@typescript-eslint/typescript-estree": "4.29.1", "eslint-scope": "^5.1.1", "eslint-utils": "^3.0.0" } }, "@typescript-eslint/parser": { - "version": "4.28.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-4.28.2.tgz", - "integrity": "sha512-Q0gSCN51eikAgFGY+gnd5p9bhhCUAl0ERMiDKrTzpSoMYRubdB8MJrTTR/BBii8z+iFwz8oihxd0RAdP4l8w8w==", + "version": "4.29.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-4.29.1.tgz", + "integrity": "sha512-3fL5iN20hzX3Q4OkG7QEPFjZV2qsVGiDhEwwh+EkmE/w7oteiOvUNzmpu5eSwGJX/anCryONltJ3WDmAzAoCMg==", "dev": true, "requires": { - "@typescript-eslint/scope-manager": "4.28.2", - "@typescript-eslint/types": "4.28.2", - "@typescript-eslint/typescript-estree": "4.28.2", + "@typescript-eslint/scope-manager": "4.29.1", + "@typescript-eslint/types": "4.29.1", + "@typescript-eslint/typescript-estree": "4.29.1", "debug": "^4.3.1" } }, "@typescript-eslint/scope-manager": { - "version": "4.28.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-4.28.2.tgz", - "integrity": "sha512-MqbypNjIkJFEFuOwPWNDjq0nqXAKZvDNNs9yNseoGBB1wYfz1G0WHC2AVOy4XD7di3KCcW3+nhZyN6zruqmp2A==", + "version": "4.29.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-4.29.1.tgz", + "integrity": "sha512-Hzv/uZOa9zrD/W5mftZa54Jd5Fed3tL6b4HeaOpwVSabJK8CJ+2MkDasnX/XK4rqP5ZTWngK1ZDeCi6EnxPQ7A==", "dev": true, "requires": { - "@typescript-eslint/types": "4.28.2", - "@typescript-eslint/visitor-keys": "4.28.2" + "@typescript-eslint/types": "4.29.1", + "@typescript-eslint/visitor-keys": "4.29.1" } }, "@typescript-eslint/types": { - "version": "4.28.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-4.28.2.tgz", - "integrity": "sha512-Gr15fuQVd93uD9zzxbApz3wf7ua3yk4ZujABZlZhaxxKY8ojo448u7XTm/+ETpy0V0dlMtj6t4VdDvdc0JmUhA==", + "version": "4.29.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-4.29.1.tgz", + "integrity": "sha512-Jj2yu78IRfw4nlaLtKjVaGaxh/6FhofmQ/j8v3NXmAiKafbIqtAPnKYrf0sbGjKdj0hS316J8WhnGnErbJ4RCA==", "dev": true }, "@typescript-eslint/typescript-estree": { - "version": "4.28.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-4.28.2.tgz", - "integrity": "sha512-86lLstLvK6QjNZjMoYUBMMsULFw0hPHJlk1fzhAVoNjDBuPVxiwvGuPQq3fsBMCxuDJwmX87tM/AXoadhHRljg==", + "version": "4.29.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-4.29.1.tgz", + "integrity": "sha512-lIkkrR9E4lwZkzPiRDNq0xdC3f2iVCUjw/7WPJ4S2Sl6C3nRWkeE1YXCQ0+KsiaQRbpY16jNaokdWnm9aUIsfw==", "dev": true, "requires": { - "@typescript-eslint/types": "4.28.2", - "@typescript-eslint/visitor-keys": "4.28.2", + "@typescript-eslint/types": "4.29.1", + "@typescript-eslint/visitor-keys": "4.29.1", "debug": "^4.3.1", "globby": "^11.0.3", "is-glob": "^4.0.1", @@ -8353,12 +8464,12 @@ } }, "@typescript-eslint/visitor-keys": { - "version": "4.28.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-4.28.2.tgz", - "integrity": "sha512-aT2B4PLyyRDUVUafXzpZFoc0C9t0za4BJAKP5sgWIhG+jHECQZUEjuQSCIwZdiJJ4w4cgu5r3Kh20SOdtEBl0w==", + "version": "4.29.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-4.29.1.tgz", + "integrity": "sha512-zLqtjMoXvgdZY/PG6gqA73V8BjqPs4af1v2kiiETBObp+uC6gRYnJLmJHxC0QyUrrHDLJPIWNYxoBV3wbcRlag==", "dev": true, "requires": { - "@typescript-eslint/types": "4.28.2", + "@typescript-eslint/types": "4.29.1", "eslint-visitor-keys": "^2.0.0" } }, @@ -8374,14 +8485,6 @@ "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", "dev": true }, - "abort-controller": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz", - "integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==", - "requires": { - "event-target-shim": "^5.0.0" - } - }, "acorn": { "version": "7.4.1", "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", @@ -8791,16 +8894,16 @@ "dev": true }, "browserslist": { - "version": "4.16.6", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.16.6.tgz", - "integrity": "sha512-Wspk/PqO+4W9qp5iUTJsa1B/QrYn1keNCcEP5OvP7WBwT4KaDly0uONYmC6Xa3Z5IqnUgS0KcgLYu1l74x0ZXQ==", + "version": "4.16.7", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.16.7.tgz", + "integrity": "sha512-7I4qVwqZltJ7j37wObBe3SoTz+nS8APaNcrBOlgoirb6/HbEU2XxW/LpUDTCngM6iauwFqmRTuOMfyKnFGY5JA==", "dev": true, "requires": { - "caniuse-lite": "^1.0.30001219", + "caniuse-lite": "^1.0.30001248", "colorette": "^1.2.2", - "electron-to-chromium": "^1.3.723", + "electron-to-chromium": "^1.3.793", "escalade": "^3.1.1", - "node-releases": "^1.1.71" + "node-releases": "^1.1.73" } }, "bs-logger": { @@ -8822,9 +8925,9 @@ } }, "buffer-from": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz", - "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==", + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", "dev": true }, "cacheable-lookup": { @@ -8849,8 +8952,7 @@ "callsites": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", - "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", - "dev": true + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==" }, "camelcase": { "version": "5.3.1", @@ -8859,15 +8961,15 @@ "dev": true }, "caniuse-lite": { - "version": "1.0.30001243", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001243.tgz", - "integrity": "sha512-vNxw9mkTBtkmLFnJRv/2rhs1yufpDfCkBZexG3Y0xdOH2Z/eE/85E4Dl5j1YUN34nZVsSp6vVRFQRrez9wJMRA==", + "version": "1.0.30001249", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001249.tgz", + "integrity": "sha512-vcX4U8lwVXPdqzPWi6cAJ3FnQaqXbBqy/GZseKNQzRj37J7qZdGcBtxq/QLFNLLlfsoXLUdHw8Iwenri86Tagw==", "dev": true }, "chalk": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.1.tgz", - "integrity": "sha512-diHzdDKxcU+bAsUboHLPEDQiw0qEe0qd7SYUn3HgcFlWgbDcfLGswOHYeGrHKzG9z6UYf01d9VFMfZxPM1xZSg==", + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, "requires": { "ansi-styles": "^4.1.0", @@ -8903,9 +9005,9 @@ "dev": true }, "cjs-module-lexer": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-1.2.1.tgz", - "integrity": "sha512-jVamGdJPDeuQilKhvVn1h3knuMOZzr8QDnpk+M9aMlCaMkTDd6fBWPhiDqFvFZ07pL0liqabAiuy8SY4jGHeaw==", + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-1.2.2.tgz", + "integrity": "sha512-cOU9usZw8/dXIXKtwa8pM0OTJQuJkxMN6w30csNRUerHfeQ5R6U3kkU/FtJeIf3M202OHfY2U8ccInBG7/xogA==", "dev": true }, "cli-boxes": { @@ -8961,9 +9063,9 @@ "dev": true }, "colorette": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/colorette/-/colorette-1.2.2.tgz", - "integrity": "sha512-MKGMzyfeuutC/ZJ1cba9NqcNpfeqMUcYmyF1ZFY6/Cn7CNSAKx6a+s48sqLqyAiZuaP2TcqMhoo+dlwFnVxT9w==", + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/colorette/-/colorette-1.3.0.tgz", + "integrity": "sha512-ecORCqbSFP7Wm8Y6lyqMJjexBQqXSF7SSeaTyGGphogUjBlFP9m9o08wy86HL2uB7fMTxtOUzLMk7ogKcxMg1w==", "dev": true }, "combined-stream": { @@ -8992,6 +9094,17 @@ "unique-string": "^2.0.0", "write-file-atomic": "^3.0.0", "xdg-basedir": "^4.0.0" + }, + "dependencies": { + "dot-prop": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-5.3.0.tgz", + "integrity": "sha512-QM8q3zDe58hqUqjraQOmzZ1LIH9SWQJTlEKCH4kJ2oQvLZk7RbQXvtDM2XEq3fwkV9CCvvH4LA0AV+ogFsBM2Q==", + "dev": true, + "requires": { + "is-obj": "^2.0.0" + } + } } }, "convert-source-map": { @@ -9165,19 +9278,31 @@ "path-type": "^4.0.0" } }, + "discord-api-types": { + "version": "0.22.0", + "resolved": "https://registry.npmjs.org/discord-api-types/-/discord-api-types-0.22.0.tgz", + "integrity": "sha512-l8yD/2zRbZItUQpy7ZxBJwaLX/Bs2TGaCthRppk8Sw24LOIWg12t9JEreezPoYD0SQcC2htNNo27kYEpYW/Srg==" + }, "discord.js": { - "version": "12.5.3", - "resolved": "https://registry.npmjs.org/discord.js/-/discord.js-12.5.3.tgz", - "integrity": "sha512-D3nkOa/pCkNyn6jLZnAiJApw2N9XrIsXUAdThf01i7yrEuqUmDGc7/CexVWwEcgbQR97XQ+mcnqJpmJ/92B4Aw==", + "version": "13.0.1", + "resolved": "https://registry.npmjs.org/discord.js/-/discord.js-13.0.1.tgz", + "integrity": "sha512-pEODCFfxypBnGEYpSgjkn1jt70raCS1um7Zp0AXEfW1DcR29wISzQ/WeWdnjP5KTXGi0LTtkRiUjOsMgSoukxA==", "requires": { - "@discordjs/collection": "^0.1.6", + "@discordjs/builders": "^0.4.0", + "@discordjs/collection": "^0.2.1", "@discordjs/form-data": "^3.0.1", - "abort-controller": "^3.0.0", + "@sapphire/async-queue": "^1.1.4", + "@types/ws": "^7.4.7", + "discord-api-types": "^0.22.0", "node-fetch": "^2.6.1", - "prism-media": "^1.2.9", - "setimmediate": "^1.0.5", - "tweetnacl": "^1.0.3", - "ws": "^7.4.4" + "ws": "^7.5.1" + }, + "dependencies": { + "@discordjs/collection": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/@discordjs/collection/-/collection-0.2.1.tgz", + "integrity": "sha512-vhxqzzM8gkomw0TYRF3tgx7SwElzUlXT/Aa41O7mOcyN6wIJfj5JmDWaO5XGKsGSsNx7F3i5oIlrucCCWV1Nog==" + } } }, "doctrine": { @@ -9207,10 +9332,9 @@ } }, "dot-prop": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-5.3.0.tgz", - "integrity": "sha512-QM8q3zDe58hqUqjraQOmzZ1LIH9SWQJTlEKCH4kJ2oQvLZk7RbQXvtDM2XEq3fwkV9CCvvH4LA0AV+ogFsBM2Q==", - "dev": true, + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-6.0.1.tgz", + "integrity": "sha512-tE7ztYzXHIeyvc7N+hR3oi7FIbf/NIjVP9hmAt3yMXzrQ072/fpjGLx2GxNxGxUl5V73MEqYzioOMoVhGMJ5cA==", "requires": { "is-obj": "^2.0.0" } @@ -9227,9 +9351,9 @@ "dev": true }, "electron-to-chromium": { - "version": "1.3.772", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.772.tgz", - "integrity": "sha512-X/6VRCXWALzdX+RjCtBU6cyg8WZgoxm9YA02COmDOiNJEZ59WkQggDbWZ4t/giHi/3GS+cvdrP6gbLISANAGYA==", + "version": "1.3.801", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.801.tgz", + "integrity": "sha512-xapG8ekC+IAHtJrGBMQSImNuN+dm+zl7UP1YbhvTkwQn8zf/yYuoxfTSAEiJ9VDD+kjvXaAhNDPSxJ+VImtAJA==", "dev": true }, "emittery": { @@ -9339,13 +9463,13 @@ } }, "eslint": { - "version": "7.30.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-7.30.0.tgz", - "integrity": "sha512-VLqz80i3as3NdloY44BQSJpFw534L9Oh+6zJOUaViV4JPd+DaHwutqP7tcpkW3YiXbK6s05RZl7yl7cQn+lijg==", + "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, "requires": { "@babel/code-frame": "7.12.11", - "@eslint/eslintrc": "^0.4.2", + "@eslint/eslintrc": "^0.4.3", "@humanwhocodes/config-array": "^0.5.0", "ajv": "^6.10.0", "chalk": "^4.0.0", @@ -9501,11 +9625,6 @@ "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", "dev": true }, - "event-target-shim": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz", - "integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==" - }, "execa": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", @@ -9662,35 +9781,17 @@ "integrity": "sha512-4zPxDyhCyiN2wIAtSLI6gc82/EjqZc1onI4Mz/l0pWrAlsSfYH/2ZIcU+e3oA2wDwbzIWNKwa23F8rh6+DRWkw==" }, "flatted": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.1.tgz", - "integrity": "sha512-OMQjaErSFHmHqZe+PSidH5n8j3O0F2DdnVh8JB4j4eUQ2k6KvB0qGfrKIhapvez5JerBbmWkaLYUYWISaESoXg==", + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.2.tgz", + "integrity": "sha512-JaTY/wtrcSyvXJl4IMFHPKyFur1sE9AUqc0QnhOaJ0CxHtAoIV8pYDzeEfAaNEtGkOfq4gr3LBFmdXW5mOQFnA==", "dev": true }, - "form-data": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-3.0.1.tgz", - "integrity": "sha512-RHkBKtLWUVwd7SqRIvCZMEvAMoGUp0XU+seQiZejj0COz3RI3hWP4sCv3gZWWLjJTd7rGwcsF5eKZGii0r/hbg==", - "dev": true, - "requires": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.8", - "mime-types": "^2.1.12" - } - }, "fs.realpath": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", "dev": true }, - "fsevents": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", - "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", - "dev": true, - "optional": true - }, "function-bind": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", @@ -9811,9 +9912,9 @@ } }, "graceful-fs": { - "version": "4.2.6", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.6.tgz", - "integrity": "sha512-nTnJ528pbqxYanhpDYsi4Rd8MAeaBA67+RZ10CM1m3bTAVFEDcd5AuA4a6W5YkGZ1iNXHzZz8T6TBKLeBuNriQ==", + "version": "4.2.8", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.8.tgz", + "integrity": "sha512-qkIilPUYcNhJpd33n0GBXTB1MMPp14TxEsEs0pTrsSVucApsYzW5V+Q8Qxhik6KU3evy+qkAAowTByymK0avdg==", "dev": true }, "has": { @@ -9992,9 +10093,9 @@ } }, "is-core-module": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.4.0.tgz", - "integrity": "sha512-6A2fkfq1rfeQZjxrZJGerpLCTHRNEBiSgnu0+obeJpEPZRUooHgsizvzv0ZjJwOz3iWIHdJtVWJ/tmPr3D21/A==", + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.5.0.tgz", + "integrity": "sha512-TXCMSDsEHMEEZ6eCA8rwRDbLu55MRGmrctljsBX/2v1d9/GzqHOxW5c5oPSgrUt2vBFXebu9rGqckXGPWOlYpg==", "dev": true, "requires": { "has": "^1.0.3" @@ -10052,8 +10153,7 @@ "is-obj": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-2.0.0.tgz", - "integrity": "sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==", - "dev": true + "integrity": "sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==" }, "is-path-inside": { "version": "3.0.3", @@ -10068,9 +10168,9 @@ "dev": true }, "is-stream": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.0.tgz", - "integrity": "sha512-XCoy+WlUr7d1+Z8GgSuXmpuUFC9fOhRXglJMx+dwLKTkL44Cjd4W1Z5P+BQZpr+cR93aGP4S/s7Ftw6Nd/kiEw==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", "dev": true }, "is-typedarray": { @@ -10892,9 +10992,9 @@ } }, "jsdom": { - "version": "16.6.0", - "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-16.6.0.tgz", - "integrity": "sha512-Ty1vmF4NHJkolaEmdjtxTfSfkdb8Ywarwf63f+F8/mDD1uLSSWDxDuMiZxiPhwunLrn9LOSVItWj4bLYsLN3Dg==", + "version": "16.7.0", + "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-16.7.0.tgz", + "integrity": "sha512-u9Smc2G1USStM+s/x1ru5Sxrl6mPYCbByG1U/hUmqaVsm4tbNyS7CicOSRyuGQYZhTu0h84qkZZQ/I+dzizSVw==", "dev": true, "requires": { "abab": "^2.0.5", @@ -10922,7 +11022,7 @@ "whatwg-encoding": "^1.0.5", "whatwg-mimetype": "^2.3.0", "whatwg-url": "^8.5.0", - "ws": "^7.4.5", + "ws": "^7.4.6", "xml-name-validator": "^3.0.0" }, "dependencies": { @@ -10931,6 +11031,17 @@ "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.4.1.tgz", "integrity": "sha512-asabaBSkEKosYKMITunzX177CXxQ4Q8BSSzMTKD+FefUhipQC70gfW5SiUDhYQ3vk8G+81HqQk7Fv9OXwwn9KA==", "dev": true + }, + "form-data": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-3.0.1.tgz", + "integrity": "sha512-RHkBKtLWUVwd7SqRIvCZMEvAMoGUp0XU+seQiZejj0COz3RI3hWP4sCv3gZWWLjJTd7rGwcsF5eKZGii0r/hbg==", + "dev": true, + "requires": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + } } } }, @@ -11026,6 +11137,11 @@ "integrity": "sha1-4j8/nE+Pvd6HJSnBBxhXoIblzO8=", "dev": true }, + "lodash.isequal": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.isequal/-/lodash.isequal-4.5.0.tgz", + "integrity": "sha1-QVxEePK8wwEgwizhDtMib30+GOA=" + }, "lodash.merge": { "version": "4.6.2", "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", @@ -11107,16 +11223,16 @@ } }, "mime-db": { - "version": "1.48.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.48.0.tgz", - "integrity": "sha512-FM3QwxV+TnZYQ2aRqhlKBMHxk10lTbMt3bBkMAp54ddrNeVSfcQYOOKuGuy3Ddrm38I04If834fOUSq1yzslJQ==" + "version": "1.49.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.49.0.tgz", + "integrity": "sha512-CIc8j9URtOVApSFCQIF+VBkX1RwXp/oMMOrqdyXSBXq5RWNEsRfyj1kiRnQgmNXmHxPoFIxOroKA3zcU9P+nAA==" }, "mime-types": { - "version": "2.1.31", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.31.tgz", - "integrity": "sha512-XGZnNzm3QvgKxa8dpzyhFTHmpP3l5YNusmne07VUOXxou9CqUqYa/HBy124RqtVh/O2pECas/MOcsDgpilPOPg==", + "version": "2.1.32", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.32.tgz", + "integrity": "sha512-hJGaVS4G4c9TSMYh2n6SQAGrC4RnfU+daP8G7cSCmaqNjiOoUY0VHCMS42pxnQmVF1GWwFhbHWn3RIxCqTmZ9A==", "requires": { - "mime-db": "1.48.0" + "mime-db": "1.49.0" } }, "mimic-fn": { @@ -11321,6 +11437,26 @@ "word-wrap": "^1.2.3" } }, + "ow": { + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/ow/-/ow-0.27.0.tgz", + "integrity": "sha512-SGnrGUbhn4VaUGdU0EJLMwZWSupPmF46hnTRII7aCLCrqixTAC5eKo8kI4/XXf1eaaI8YEVT+3FeGNJI9himAQ==", + "requires": { + "@sindresorhus/is": "^4.0.1", + "callsites": "^3.1.0", + "dot-prop": "^6.0.1", + "lodash.isequal": "^4.5.0", + "type-fest": "^1.2.1", + "vali-date": "^1.0.0" + }, + "dependencies": { + "type-fest": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-1.4.0.tgz", + "integrity": "sha512-yGSza74xk0UG8k+pLh5oeoYirvIiWo5t0/o3zHHAO2tRDiZcxWP7fywNlXhqb6/r6sWvwi+RsyQMWhVLe4BVuA==" + } + } + }, "p-cancelable": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-2.1.1.tgz", @@ -11553,9 +11689,9 @@ "dev": true }, "pino": { - "version": "6.12.0", - "resolved": "https://registry.npmjs.org/pino/-/pino-6.12.0.tgz", - "integrity": "sha512-5NGopOcUusGuklGHVVv9az0Hv/Dj3urHhD3G+zhl5pBGIRYAeGCi/Ej6YCl16Q2ko28cmYiJz+/qRoJiwy62Rw==", + "version": "6.13.0", + "resolved": "https://registry.npmjs.org/pino/-/pino-6.13.0.tgz", + "integrity": "sha512-mRXSTfa34tbfrWqCIp1sUpZLqBhcoaGapoyxfEwaWwJGMpLijlRdDKIQUyvq4M3DUfFH5vEglwSw8POZYwbThA==", "requires": { "fast-redact": "^3.0.0", "fast-safe-stringify": "^2.0.8", @@ -11563,12 +11699,23 @@ "pino-std-serializers": "^3.1.0", "quick-format-unescaped": "^4.0.3", "sonic-boom": "^1.0.2" + }, + "dependencies": { + "sonic-boom": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/sonic-boom/-/sonic-boom-1.4.1.tgz", + "integrity": "sha512-LRHh/A8tpW7ru89lrlkU4AszXt1dbwSjVWguGrmlxE7tawVmDBlI1PILMkXAxJTwqhgsEeTHzj36D5CmHgQmNg==", + "requires": { + "atomic-sleep": "^1.0.0", + "flatstr": "^1.0.12" + } + } } }, "pino-pretty": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/pino-pretty/-/pino-pretty-5.1.1.tgz", - "integrity": "sha512-bG8a6A2QcZYJXD/ZL7PXn8CDNIUP5TKyQwR9Yjzn5dpGyQ7Wbyl707Dxhx+tPT3BG6YpsXF93Hhe9EUnx0SsPw==", + "version": "5.1.3", + "resolved": "https://registry.npmjs.org/pino-pretty/-/pino-pretty-5.1.3.tgz", + "integrity": "sha512-Zj+0TVdYKkAAIx9EUCL5e4TttwgsaFvJh2ceIMQeFCY8ak9tseEZQGSgpvyjEj1/iIVGIh5tdhkGEQWSMILKHA==", "dev": true, "requires": { "@hapi/bourne": "^2.0.0", @@ -11662,12 +11809,6 @@ } } }, - "prism-media": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/prism-media/-/prism-media-1.3.1.tgz", - "integrity": "sha512-nyYAa3KB4qteJIqdguKmwxTJgy55xxUtkJ3uRnOvO5jO+frci+9zpRXw6QZVcfDeva3S654fU9+26P2OSTzjHw==", - "requires": {} - }, "progress": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", @@ -11829,9 +11970,9 @@ } }, "resolve-alpn": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/resolve-alpn/-/resolve-alpn-1.1.2.tgz", - "integrity": "sha512-8OyfzhAtA32LVUsJSke3auIyINcwdh5l3cvYKdKO0nvsYSKuiLfTM5i78PJswFPT8y6cPW+L1v6/hE95chcpDA==" + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/resolve-alpn/-/resolve-alpn-1.2.0.tgz", + "integrity": "sha512-e4FNQs+9cINYMO5NMFc6kOUCdohjqFPSgMuwuZAOUWqrfWsen+Yjy5qZFkV5K7VO7tFSLKcUL97olkED7sCBHA==" }, "resolve-cwd": { "version": "3.0.0", @@ -11941,11 +12082,6 @@ } } }, - "setimmediate": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", - "integrity": "sha1-KQy7Iy4waULX1+qbg3Mqt4VvgoU=" - }, "shebang-command": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", @@ -11991,12 +12127,12 @@ } }, "sonic-boom": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/sonic-boom/-/sonic-boom-1.4.1.tgz", - "integrity": "sha512-LRHh/A8tpW7ru89lrlkU4AszXt1dbwSjVWguGrmlxE7tawVmDBlI1PILMkXAxJTwqhgsEeTHzj36D5CmHgQmNg==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/sonic-boom/-/sonic-boom-2.1.0.tgz", + "integrity": "sha512-x2j9LXx27EDlyZEC32gBM+scNVMdPutU7FIKV2BOTKCnPrp7bY5BsplCMQ4shYYR3IhDSIrEXoqb6GlS+z7KyQ==", + "dev": true, "requires": { - "atomic-sleep": "^1.0.0", - "flatstr": "^1.0.12" + "atomic-sleep": "^1.0.0" } }, "source-map": { @@ -12160,9 +12296,9 @@ }, "dependencies": { "ajv": { - "version": "8.6.1", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.6.1.tgz", - "integrity": "sha512-42VLtQUOLefAvKFAQIxIZDaThq6om/PrfP0CYk3/vn+y4BMNkKnbli8ON2QCiHov4KkzOSJ/xSoBJdayiiYvVQ==", + "version": "8.6.2", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.6.2.tgz", + "integrity": "sha512-9807RlWAgT564wT+DjeyU5OFMPjmzxVobvDFmNAhY+5zD6A2ly3jDp6sgnfyDtlIQ+7H97oc/DGCzzfu9rjw9w==", "dev": true, "requires": { "fast-deep-equal": "^3.1.1", @@ -12275,9 +12411,9 @@ } }, "ts-jest": { - "version": "27.0.3", - "resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-27.0.3.tgz", - "integrity": "sha512-U5rdMjnYam9Ucw+h0QvtNDbc5+88nxt7tbIvqaZUhFrfG4+SkWhMXjejCLVGcpILTPuV+H3W/GZDZrnZFpPeXw==", + "version": "27.0.4", + "resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-27.0.4.tgz", + "integrity": "sha512-c4E1ECy9Xz2WGfTMyHbSaArlIva7Wi2p43QOMmCqjSSjHP06KXv+aT+eSY+yZMuqsMi3k7pyGsGj2q5oSl5WfQ==", "dev": true, "requires": { "bs-logger": "0.x", @@ -12292,29 +12428,49 @@ "yargs-parser": "20.x" } }, + "ts-mixer": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/ts-mixer/-/ts-mixer-6.0.0.tgz", + "integrity": "sha512-nXIb1fvdY5CBSrDIblLn73NW0qRDk5yJ0Sk1qPBF560OdJfQp9jhl+0tzcY09OZ9U+6GpeoI9RjwoIKFIoB9MQ==" + }, "ts-node": { - "version": "10.1.0", - "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.1.0.tgz", - "integrity": "sha512-6szn3+J9WyG2hE+5W8e0ruZrzyk1uFLYye6IGMBadnOzDh8aP7t8CbFpsfCiEx2+wMixAhjFt7lOZC4+l+WbEA==", + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.2.0.tgz", + "integrity": "sha512-FstYHtQz6isj8rBtYMN4bZdnXN1vq4HCbqn9vdNQcInRqtB86PePJQIxE6es0PhxKWhj2PHuwbG40H+bxkZPmg==", "dev": true, "requires": { + "@cspotcode/source-map-support": "0.6.1", "@tsconfig/node10": "^1.0.7", "@tsconfig/node12": "^1.0.7", "@tsconfig/node14": "^1.0.0", - "@tsconfig/node16": "^1.0.1", + "@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", - "source-map-support": "^0.5.17", "yn": "3.1.1" + }, + "dependencies": { + "acorn": { + "version": "8.4.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.4.1.tgz", + "integrity": "sha512-asabaBSkEKosYKMITunzX177CXxQ4Q8BSSzMTKD+FefUhipQC70gfW5SiUDhYQ3vk8G+81HqQk7Fv9OXwwn9KA==", + "dev": true + }, + "acorn-walk": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.1.1.tgz", + "integrity": "sha512-FbJdceMlPHEAWJOILDk1fXD8lnTlEIWFkqtfk+MvmL5q/qlHfN7GEHcsFZWt/Tea9jRNPWUZG4G976nqAAmU9w==", + "dev": true + } } }, "tslib": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", - "dev": true + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.0.tgz", + "integrity": "sha512-N82ooyxVNm6h1riLCoyS9e3fuJ3AMG2zIZs2Gd1ATcSFjSA23Q0fzjjZeh0jbJvWVDZ0cJT8yaNNaaXHzueNjg==" }, "tsutils": { "version": "3.21.0", @@ -12323,13 +12479,16 @@ "dev": true, "requires": { "tslib": "^1.8.1" + }, + "dependencies": { + "tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + } } }, - "tweetnacl": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-1.0.3.tgz", - "integrity": "sha512-6rt+RN7aOi1nGMyC4Xa5DdYiukl2UWCbcJft7YhxReBGQD7OAM8Pbxw6YMo4r2diNEA8FEmu32YOn9rhaiE5yw==" - }, "type-check": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", @@ -12504,6 +12663,11 @@ } } }, + "vali-date": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/vali-date/-/vali-date-1.0.0.tgz", + "integrity": "sha1-G5BKWWCfsyjvB4E4Qgk09rhnCaY=" + }, "w3c-hr-time": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/w3c-hr-time/-/w3c-hr-time-1.0.2.tgz", diff --git a/package.json b/package.json index d38a3fa..479755d 100644 --- a/package.json +++ b/package.json @@ -25,7 +25,7 @@ "homepage": "https://github.com/ES-Community/bot#readme", "dependencies": { "cron": "^1.8.2", - "discord.js": "^12.5.3", + "discord.js": "^13.0.0", "dotenv": "^10.0.0", "emoji-regex": "^9.2.2", "got": "^11.8.2", @@ -38,7 +38,6 @@ "@types/jest": "^26.0.24", "@types/node": "^16.4.13", "@types/pino": "^6.3.9", - "@types/ws": "^7.4.6", "@typescript-eslint/eslint-plugin": "^4.28.2", "@typescript-eslint/parser": "^4.28.2", "eslint": "^7.30.0", @@ -51,7 +50,7 @@ "typescript": "^4.3.5" }, "engines": { - "node": "16.x" + "node": ">=16.6.0" }, "volta": { "node": "16.6.1" diff --git a/src/crons/CommitStrip.ts b/src/crons/CommitStrip.ts index 2590ea9..aca2264 100644 --- a/src/crons/CommitStrip.ts +++ b/src/crons/CommitStrip.ts @@ -19,12 +19,14 @@ export default new Cron({ const channel = findTextChannelByName(context.client.channels, 'gif'); - await channel.send( - new MessageEmbed() - .setTitle(latestCommitStrip.title) - .setURL(latestCommitStrip.link) - .setImage(latestCommitStrip.imageUrl), - ); + await channel.send({ + embeds: [ + new MessageEmbed() + .setTitle(latestCommitStrip.title) + .setURL(latestCommitStrip.link) + .setImage(latestCommitStrip.imageUrl), + ], + }); }, }); diff --git a/src/crons/EpicGames.ts b/src/crons/EpicGames.ts index e8f24de..779faa3 100644 --- a/src/crons/EpicGames.ts +++ b/src/crons/EpicGames.ts @@ -30,22 +30,27 @@ export default new Cron({ for (const game of games) { context.logger.info(`Found a new offered game (${game.title})`); - await channel.send( - new MessageEmbed({ title: game.title, url: game.link }) - .setThumbnail(game.thumbnail) - .addField( - 'DĂ©but', - game.discountStartDate.toLocaleDateString('fr-FR', dateFmtOptions), - true, - ) - .addField( - 'Fin', - game.discountEndDate.toLocaleDateString('fr-FR', dateFmtOptions), - true, - ) - .addField('Prix', `${game.originalPrice} → **Gratuit**`) - .setTimestamp(), - ); + await channel.send({ + embeds: [ + new MessageEmbed({ title: game.title, url: game.link }) + .setThumbnail(game.thumbnail) + .addField( + 'DĂ©but', + game.discountStartDate.toLocaleDateString( + 'fr-FR', + dateFmtOptions, + ), + true, + ) + .addField( + 'Fin', + game.discountEndDate.toLocaleDateString('fr-FR', dateFmtOptions), + true, + ) + .addField('Prix', `${game.originalPrice} → **Gratuit**`) + .setTimestamp(), + ], + }); } }, }); diff --git a/src/framework/Bot.ts b/src/framework/Bot.ts index 3357d9d..b2dc3fd 100644 --- a/src/framework/Bot.ts +++ b/src/framework/Bot.ts @@ -2,7 +2,7 @@ import { once } from 'events'; import fs from 'fs'; import path from 'path'; -import { Client } from 'discord.js'; +import { Client, Intents } from 'discord.js'; import pino from 'pino'; import { Cron } from './Cron'; @@ -142,7 +142,10 @@ export class Bot { if (this._client) { throw new Error('Bot can only be started once'); } - this._client = new Client(); + this._client = new Client({ + intents: new Intents(['GUILDS', 'GUILD_MESSAGES']), + }); + try { await Promise.all([ this.client.login(this.token), diff --git a/src/framework/Cron.ts b/src/framework/Cron.ts index 8a3940e..d11a8ac 100644 --- a/src/framework/Cron.ts +++ b/src/framework/Cron.ts @@ -1,6 +1,6 @@ import { randomUUID } from 'crypto'; import { CronJob, CronTime } from 'cron'; -import { Client, MessageEmbed } from 'discord.js'; +import { Client, Formatters, MessageEmbed } from 'discord.js'; import { Logger } from 'pino'; import { Base, BaseConfig } from './Base'; import { Bot } from './Bot'; @@ -65,14 +65,16 @@ export class Cron extends Base { } catch (error) { logger.error(error, 'cron handler error'); try { - await findTextChannelByName(bot.client.channels, 'logs').send( - new MessageEmbed() - .setTitle('Cron run failed') - .addField('Name', this.name, true) - .addField('Run id', id, true) - .setDescription(`\`\`\`\n${error.stack}\n\`\`\``) - .setColor('RED'), - ); + await findTextChannelByName(bot.client.channels, 'logs').send({ + embeds: [ + new MessageEmbed() + .setTitle('Cron run failed') + .addField('Name', this.name, true) + .addField('Run id', id, true) + .setDescription(Formatters.codeBlock(error.stack)) + .setColor('RED'), + ], + }); } catch (error2) { logger.error(error2, 'failed to send error to #logs'); } diff --git a/src/framework/FormatChecker.ts b/src/framework/FormatChecker.ts index 74a3911..18fefd7 100644 --- a/src/framework/FormatChecker.ts +++ b/src/framework/FormatChecker.ts @@ -107,11 +107,11 @@ export class FormatChecker extends Base { public start(bot: Bot): void { this.bot = bot; - this.bot.client.on('message', this._messageHandler); + this.bot.client.on('messageCreate', this._messageHandler); this.bot.client.on('messageUpdate', this._messageUpdateHandler); } public stop(bot: Bot): void { - bot.client.off('message', this._messageHandler); + bot.client.off('messageCreate', this._messageHandler); } } diff --git a/src/framework/helpers.ts b/src/framework/helpers.ts index b9521bf..66b019c 100644 --- a/src/framework/helpers.ts +++ b/src/framework/helpers.ts @@ -2,6 +2,7 @@ import { Channel, ChannelManager, GuildChannelManager, + PartialDMChannel, TextChannel, } from 'discord.js'; @@ -21,6 +22,8 @@ export function findTextChannelByName( return channel; } -export function isTextChannel(channel: Channel): channel is TextChannel { +export function isTextChannel( + channel: Channel | PartialDMChannel, +): channel is TextChannel { return channel instanceof TextChannel; } From a3696fd99cd64c5353cdca727fe54df2e4c3536c Mon Sep 17 00:00:00 2001 From: Mestery Date: Sun, 11 Jul 2021 23:15:17 +0200 Subject: [PATCH 2/5] feat(framework): slash commands --- README.md | 93 ++++++++++---- package-lock.json | 1 + package.json | 1 + src/bot.ts | 1 + src/commands/Hello.ts | 32 +++++ src/framework/Bot.ts | 25 +++- src/framework/command/Command.ts | 155 ++++++++++++++++++++++++ src/framework/command/CommandManager.ts | 108 +++++++++++++++++ src/framework/command/index.ts | 2 + src/framework/index.ts | 1 + tests/framework/Bot.spec.ts | 4 +- 11 files changed, 397 insertions(+), 26 deletions(-) create mode 100644 src/commands/Hello.ts create mode 100644 src/framework/command/Command.ts create mode 100644 src/framework/command/CommandManager.ts create mode 100644 src/framework/command/index.ts diff --git a/README.md b/README.md index e382fb4..8db9cb0 100644 --- a/README.md +++ b/README.md @@ -1,29 +1,27 @@ # Bot Discord de la communautĂ© -## DĂ©veloppement - -### PrĂ©requis +## PrĂ©requis - Node.js v16 - npm v7 - Un bot Discord installĂ© sur une copie du serveur ES Community. - - Template: https://discord.new/T3mtuFqjR8Tm + - Template : https://discord.new/T3mtuFqjR8Tm -### PrĂ©paration de l'environnement +## PrĂ©paration de l'environnement -Installez les dĂ©pendances avec npm: +Installez les dĂ©pendances avec npm : ```console npm ci ``` -CrĂ©ez un fichier `.env` avec votre token de bot: +CrĂ©ez un fichier `.env` avec votre token de bot : ```env DISCORD_TOKEN=votretoken ``` -### ExĂ©cution du bot +## ExĂ©cution du bot ```console npm start @@ -31,15 +29,15 @@ npm start Cette commande exĂ©cute le fichier `src/bot.ts`, qui dĂ©marre le bot. Les changements dans le dossier `src` sont observĂ©s par `nodemon` et le bot est redĂ©marrĂ© automatiquement. -### Tests +## Tests -Le projet contient 3 scripts de test qui doivent passer pour tout commit poussĂ© sur la branche `main`. Vous pouvez exĂ©cuter tous les tests avec la commande suivante: +Le projet contient 3 scripts de test qui doivent passer pour tout commit poussĂ© sur la branche `main`. Vous pouvez exĂ©cuter tous les tests avec la commande suivante : ```console npm test ``` -#### Tests TS +### Tests TS ```console # ExĂ©cution des tests. @@ -51,7 +49,7 @@ npm run test-coverage Le framework de test [Jest](https://jestjs.io/) est utilisĂ© pour exĂ©cuter les tests. Ceux-ci doivent ĂȘtre Ă©crits en TypeScript dans le dossier `tests`. Essayez de conserver la mĂȘme structure de dossiers que dans `src` pour organiser les tests. -#### Lint +### Lint ```console # ExĂ©cution d'ESLint @@ -61,9 +59,9 @@ npm run lint npm run lint-fix ``` -Nous utilisons [ESLint](https://eslint.org/) ainsi que [typescript-eslint](https://github.com/typescript-eslint/typescript-eslint) pour l'analyse statique du code. +Nous utilisons [ESLint](https://eslint.org/) ainsi que [TypeScript ESLint](https://github.com/typescript-eslint/typescript-eslint) pour l'analyse statique du code. -#### VĂ©rification des types TypeScript +### VĂ©rification des types TypeScript ```console npm run check-types @@ -71,24 +69,75 @@ npm run check-types Cette commande exĂ©cute le compilateur TypeScript avec l'option `--noEmit`. Elle permet de valider les types de l'entier du projet, y compris sur les fichiers qui ne sont pas testĂ©s avec Jest. -### Écriture de fonctionnalitĂ©s +## Écriture de fonctionnalitĂ©s + +### Commandes + +Chaque commande doit ĂȘtre Ă©crite dans un fichier du dossier `src/commands`. Ce +fichier doit instancier et exporter par dĂ©faut une instance de la classe `Command`, +en lui passant les paramĂštres de configuration suivants : + +- `enabled`: boolean. Peut ĂȘtre mis Ă  `false` pour dĂ©sactiver la commande. +- `name`: string. Nom de la commande.. +- `description`: string. Description de ce que fait la commande (en français). +- `options`?: object. Options (arguments) de la commande. +- `guildId`?: Snowflake. L'identifiant d'une guilde, si cette commande est spĂ©cifique Ă  une guilde. +- `defaultPermission`?: boolean. Si la commande doit ĂȘtre activĂ© par dĂ©faut quand le bot est ajoutĂ© Ă  un serveur (`true` par dĂ©faut). +- `handle`: function. Fonction exĂ©cutĂ©e lorsque cette commande est appellĂ©e. Elle recevra un argument `context`, avec les propriĂ©tĂ©s : + - `args`: Objet correctement typĂ©, contenant les options fournis par l'Ă©xecuteur de la commande (abstraction d'`interaction.options`). + - `interaction`: Instance de CommandInteraction (discord.js). + - `client`: Instance du Client (discord.js). + - `logger`: Instance du Logger (pino). -#### TĂąches cron +#### Exemple + +**Fichier exemplaire :** [src/commands/Hello.ts](src/commands/Hello.ts). + +```ts +import { Command, CommandOptionTypes } from '../framework'; + +// crĂ©ation d'une commande slash (https://discord.com/developers/docs/interactions/slash-commands) +export default new Command({ + enabled: true, + name: 'say', // nom de la commande + description: 'Dit ce que vous lui dites.', // description de la commande + options: { + message: { + // ceci est une option ("argument") de la commande slash + type: CommandOptionTypes.String, // type d'option (en l'occurence, chaine de caractĂšre) + description: 'Ce que le bot doit dire.', // description de cette option + required: true, // option obligatoire (par dĂ©faut, false) + }, + }, + handle({ args, interaction }) { + // args aura comme type : `{ message: string }` + return interaction.reply( + `**${interaction.user.username}** m'a dit de dire : « ${args.message} ».`, + ); + // si toutefois, vous voulez accĂ©der aux arguments fourni comme telle par discord.js : + // interaction.options.get('message').value; + }, +}); +``` + +### TĂąches cron Chaque tĂąche cron doit ĂȘtre Ă©crite dans un fichier du dossier `src/crons`. Ce -fichier doit instancier et exporter par dĂ©faut une instance de la classe Cron, -en lui passant les paramĂštres de configuration suivants: +fichier doit instancier et exporter par dĂ©faut une instance de la classe `Cron`, +en lui passant les paramĂštres de configuration suivants : - `enabled`: boolean. Peut ĂȘtre mis Ă  `false` pour dĂ©sactiver la tĂąche. - `name`: string. Nom de la tĂąche. UtilisĂ© dans les logs. - `description`: string. Description de ce que fait la tĂąche (en français). - `schedule`: string. Programme d'exĂ©cution. Vous pouvez utiliser [crontab guru](https://crontab.guru/) pour le prĂ©parer. -- `handle`: function. Fonction exĂ©cutĂ©e selon le programme. Elle recevra un argument `context`, avec les propriĂ©tĂ©s: +- `handle`: function. Fonction exĂ©cutĂ©e selon le programme. Elle recevra un argument `context`, avec les propriĂ©tĂ©s : - `date`: Date thĂ©orique d'exĂ©cution de la tĂąche. - - `client`: Instance du client discord.js. - - `logger`: Instance du logger pino. + - `client`: Instance du Client (discord.js). + - `logger`: Instance du Logger (pino). + +#### Exemple -Exemple: +**Fichier exemplaire :** [src/crons/CommitStrip.ts](src/crons/CommitStrip.ts). ```ts import { Cron } from '../framework'; diff --git a/package-lock.json b/package-lock.json index ac651b8..fa77c94 100644 --- a/package-lock.json +++ b/package-lock.json @@ -25,6 +25,7 @@ "@types/pino": "^6.3.9", "@typescript-eslint/eslint-plugin": "^4.28.2", "@typescript-eslint/parser": "^4.28.2", + "discord-api-types": "^0.22.0", "eslint": "^7.30.0", "jest": "^27.0.6", "nodemon": "^2.0.12", diff --git a/package.json b/package.json index 479755d..98754ea 100644 --- a/package.json +++ b/package.json @@ -40,6 +40,7 @@ "@types/pino": "^6.3.9", "@typescript-eslint/eslint-plugin": "^4.28.2", "@typescript-eslint/parser": "^4.28.2", + "discord-api-types": "^0.22.0", "eslint": "^7.30.0", "jest": "^27.0.6", "nodemon": "^2.0.12", diff --git a/src/bot.ts b/src/bot.ts index 97f58ce..dea7924 100644 --- a/src/bot.ts +++ b/src/bot.ts @@ -7,6 +7,7 @@ import { Bot } from './framework'; const bot = new Bot({ token: process.env.DISCORD_TOKEN, + commands: path.join(__dirname, 'commands'), crons: path.join(__dirname, 'crons'), formatCheckers: path.join(__dirname, 'format-checkers'), }); diff --git a/src/commands/Hello.ts b/src/commands/Hello.ts new file mode 100644 index 0000000..43d50da --- /dev/null +++ b/src/commands/Hello.ts @@ -0,0 +1,32 @@ +import { Command, CommandOptionTypes } from '../framework'; + +export default new Command({ + name: 'hello', + description: 'Vous salue.', + enabled: true, + options: { + stars: { + description: "Nombre d'Ă©toiles accompagnant le salut.", + required: true, + type: CommandOptionTypes.Integer, + choices: [ + { name: '1 Ă©toile', value: 1 }, + { name: '2 Ă©toiles', value: 2 }, + { name: '3 Ă©toiles', value: 3 }, + { name: '4 Ă©toiles', value: 4 }, + { name: '5 Ă©toiles', value: 5 }, + ] as const, + }, + user: { + description: 'Mentionne un utilisateur spĂ©cifique (vous par dĂ©faut).', + type: CommandOptionTypes.User, + }, + }, + handle({ args, interaction }) { + return interaction.reply( + `Salut ${(args.user ?? interaction.user).toString()} ${'⭐'.repeat( + args.stars, + )}`, + ); + }, +}); diff --git a/src/framework/Bot.ts b/src/framework/Bot.ts index b2dc3fd..b62a02f 100644 --- a/src/framework/Bot.ts +++ b/src/framework/Bot.ts @@ -5,8 +5,9 @@ import path from 'path'; import { Client, Intents } from 'discord.js'; import pino from 'pino'; -import { Cron } from './Cron'; import { Base, BaseConfig } from './Base'; +import { Command, CommandManager } from './command'; +import { Cron } from './Cron'; import { FormatChecker } from './FormatChecker'; export interface BotOptions { @@ -15,6 +16,10 @@ export interface BotOptions { * Defaults to `process.env.DISCORD_TOKEN`. */ token?: string; + /** + * Directory that contains the `Command` definitions. + */ + commands?: string; /** * Directory that contains the `Cron` definitions. */ @@ -27,11 +32,14 @@ export interface BotOptions { type Constructor = { new (config: U): T; + // eslint-disable-next-line @typescript-eslint/no-unused-vars + new (config: U): T; }; export class Bot { private readonly token?: string; private _client: Client | null; + private commandManager?: CommandManager; private crons: Cron[] = []; private formatCheckers: FormatChecker[] = []; @@ -42,9 +50,16 @@ export class Bot { this._client = null; this.logger = pino(); + if (options.commands) { + this.commandManager = new CommandManager( + this.loadDirectory(options.commands, 'commands', Command), + ); + } + if (options.crons) { this.crons = this.loadDirectory(options.crons, 'crons', Cron); } + if (options.formatCheckers) { this.formatCheckers = this.loadDirectory( options.formatCheckers, @@ -151,6 +166,9 @@ export class Bot { this.client.login(this.token), once(this.client, 'ready'), ]); + if (this.commandManager) { + await this.commandManager.start(this); + } this.startCrons(); this.startFormatCheckers(); } catch (error) { @@ -162,10 +180,13 @@ export class Bot { /** * Stop the bot. */ - public stop(): void { + public async stop(): Promise { if (!this._client) { throw new Error('Bot was not started'); } + if (this.commandManager) { + await this.commandManager.stop(this); + } this.stopCrons(); this.stopFormatCheckers(); this._client.destroy(); diff --git a/src/framework/command/Command.ts b/src/framework/command/Command.ts new file mode 100644 index 0000000..56482b1 --- /dev/null +++ b/src/framework/command/Command.ts @@ -0,0 +1,155 @@ +import type { + Client, + CommandInteraction, + GuildChannel, + GuildMember, + Role, + Snowflake, + User, +} from 'discord.js'; +import type { + APIRole, + APIInteractionDataResolvedGuildMember, + APIInteractionDataResolvedChannel, +} from 'discord-api-types/v9'; +import type { Logger } from 'pino'; +import { Base, BaseConfig } from '../Base'; + +export const enum CommandOptionTypes { + String = 3, + Integer, + Boolean, + User, + Channel, + Role, + Mentionable, +} + +interface CommandOptionsData< + T extends CommandOptionTypes = + | CommandOptionTypes.Boolean + | CommandOptionTypes.Channel + | CommandOptionTypes.Mentionable + | CommandOptionTypes.Role + | CommandOptionTypes.User, + C = never, +> { + readonly type: T; + readonly description: string; + readonly required?: boolean; + readonly choices?: C extends never + ? never + : readonly { readonly name: string; readonly value: C }[]; +} + +export type CommandOptions = Record< + string, + | CommandOptionsData + | CommandOptionsData + | CommandOptionsData +>; + +interface OptionTypes { + [CommandOptionTypes.Boolean]: boolean; + [CommandOptionTypes.Integer]: number; + [CommandOptionTypes.String]: string; + [CommandOptionTypes.Role]: Role | APIRole; + [CommandOptionTypes.Channel]: + | GuildChannel + | APIInteractionDataResolvedChannel; + [CommandOptionTypes.User]: + | User + | GuildMember + | APIInteractionDataResolvedGuildMember; + [CommandOptionTypes.Mentionable]: + | OptionTypes[CommandOptionTypes.Role] + | OptionTypes[CommandOptionTypes.User]; +} + +type BuildArgs = { + [K in Keys]: T[K]['choices'] extends readonly [unknown, ...unknown[]] + ? T[K]['choices'][number]['value'] + : OptionTypes[T[K]['type']]; +}; + +type FinalCommandOptions< + T extends CommandOptions, + RequiredArgs = keyof { + [K in keyof T as T[K]['required'] extends true + ? K + : never]: never /* unimportant */; + }, +> = BuildArgs> & + Partial>>; + +export type CommandHandler = ( + context: CommandContext, +) => Promise; + +export interface CommandContext { + /** + * discord.js Client instance. + */ + client: Client; + /** + * Pino logger. + */ + logger: Logger; + /** + * The arguments (options) provided by the user, with correct typings + */ + args: FinalCommandOptions; + /** + * CommandInteraction instance. + */ + interaction: CommandInteraction; +} + +export interface CommandConfig + extends BaseConfig { + /** + * The guild ID (if this command is specific to a guild) + */ + guildId?: Snowflake; + /** + * Whether the command is enabled by default when the app is added to a guild + * @default true + */ + defaultPermission?: boolean; + /** + * Command options + */ + options?: T; + /** + * Command handler + */ + handle: CommandHandler; +} + +export class Command extends Base { + /** + * The guild ID (if this command is specific to a guild) + */ + public readonly guildId: Snowflake | undefined; + /** + * Whether the command is enabled by default when the app is added to a guild + * @default true + */ + public readonly defaultPermission: boolean | undefined; + /** + * Command options + */ + public readonly options: T | undefined; + /** + * Command handler + */ + public readonly handler: CommandHandler; + + public constructor(config: CommandConfig) { + super(config); + this.guildId = config.guildId; + this.options = config.options; + this.defaultPermission = config.defaultPermission; + this.handler = config.handle; + } +} diff --git a/src/framework/command/CommandManager.ts b/src/framework/command/CommandManager.ts new file mode 100644 index 0000000..4c3df40 --- /dev/null +++ b/src/framework/command/CommandManager.ts @@ -0,0 +1,108 @@ +/* eslint-disable @typescript-eslint/no-explicit-any, @typescript-eslint/no-non-null-assertion */ +import { randomUUID } from 'crypto'; +import { Snowflake, Interaction } from 'discord.js'; +import type { Bot } from '../Bot'; +import { Command } from './Command'; + +export class CommandManager { + /** + * Registered slash commands. + */ + public readonly commands = new Map(); + + private bot!: Bot; + + public constructor(private holds: Command[]) { + this._interactionHandler = this._interactionHandler.bind(this); + } + + public async _interactionHandler(interaction: Interaction): Promise { + if (!interaction.isCommand()) { + return; + } + + const command = this.commands.get(interaction.commandId); + + if (!command) { + return this.bot.logger + .child({ + id: randomUUID(), + type: 'CommandManager', + }) + .error( + 'unregistred slash command %s (id: %s)', + interaction.commandName, + interaction.commandId, + ); + } + + const logger = this.bot.logger.child({ + id: randomUUID(), + type: 'Command', + commandName: command.name, + }); + + try { + logger.debug('execute command handler'); + await command.handler({ + client: this.bot.client, + logger, + interaction, + args: Object.fromEntries( + interaction.options.data.map((option, name) => [ + name, + (option.member ?? + option.user ?? + option.channel ?? + option.role ?? + option.value) as any, + ]), + ), + }); + } catch (error) { + logger.error(error, 'command handler error'); + } + } + + public async start(bot: Bot): Promise { + this.bot = bot; + + await Promise.all( + this.holds.map(async (hold) => { + // The application cannot be null if the Client is ready. + const command = await this.bot.client.application!.commands.create( + { + name: hold.name, + description: hold.description, + defaultPermission: hold.defaultPermission, + options: + hold.options && + (Object.entries(hold.options).map(([key, value]) => ({ + name: key, + ...value, + })) as any), + }, + hold.guildId as any, + ); + this.commands.set(command.id, hold); + }), + ); + + // We don't need this.holds anymore. + this.holds = []; + + this.bot.client.on('interactionCreate', this._interactionHandler); + } + + public async stop(bot: Bot): Promise { + bot.client.off('interactionCreate', this._interactionHandler); + + // Unregister *all* registered slash commands. + await Promise.all( + // The application cannot be null if the Client is ready. + ( + await bot.client.application!.commands.fetch() + ).map((command) => command.delete()), + ); + } +} diff --git a/src/framework/command/index.ts b/src/framework/command/index.ts new file mode 100644 index 0000000..f7d8e84 --- /dev/null +++ b/src/framework/command/index.ts @@ -0,0 +1,2 @@ +export * from './Command'; +export * from './CommandManager'; diff --git a/src/framework/index.ts b/src/framework/index.ts index 7a4be7c..e7d8e8c 100644 --- a/src/framework/index.ts +++ b/src/framework/index.ts @@ -1,4 +1,5 @@ export * from './Bot'; export * from './Cron'; export * from './FormatChecker'; +export * from './command'; export * from './helpers'; diff --git a/tests/framework/Bot.spec.ts b/tests/framework/Bot.spec.ts index 1ec5b2f..f6538c3 100644 --- a/tests/framework/Bot.spec.ts +++ b/tests/framework/Bot.spec.ts @@ -15,9 +15,9 @@ test('bot.start() throws if called twice', async () => { await expect(bot.start()).rejects.toThrow(/can only be started once/); }); -test('bot.stop() throws if it was not started', () => { +test('bot.stop() throws if it was not started', async () => { const bot = new Bot(dummyOptions); - expect(() => bot.stop()).toThrow(/was not started/); + await expect(bot.stop()).rejects.toThrow(/was not started/); }); test('bot.client throws if it was not started', () => { From 0abd0998da76b40377842caae5853feaaa200408 Mon Sep 17 00:00:00 2001 From: Mestery Date: Tue, 10 Aug 2021 15:48:14 +0200 Subject: [PATCH 3/5] feat: use native esm --- jest.config.js | 14 ++- package-lock.json | 6 +- package.json | 10 +- src/bot.ts | 19 ++-- src/commands/Hello.ts | 2 +- src/crons/CommitStrip.ts | 2 +- src/crons/EpicGames.ts | 2 +- src/emoji-regex.ts | 7 ++ src/format-checkers/Job.ts | 2 +- src/format-checkers/Link.ts | 13 ++- src/format-checkers/Project.ts | 15 ++- src/framework/Bot.ts | 120 +++++++++++------------- src/framework/Cron.ts | 15 ++- src/framework/FormatChecker.ts | 9 +- src/framework/command/Command.ts | 2 +- src/framework/command/CommandManager.ts | 6 +- src/framework/command/index.ts | 4 +- src/framework/index.ts | 10 +- src/global.d.ts | 11 +++ tests/framework/Bot.spec.ts | 10 +- tsconfig.json | 6 +- 21 files changed, 147 insertions(+), 138 deletions(-) create mode 100644 src/emoji-regex.ts create mode 100644 src/global.d.ts diff --git a/jest.config.js b/jest.config.js index d9e4e7f..0f3fa4e 100644 --- a/jest.config.js +++ b/jest.config.js @@ -1,7 +1,17 @@ -module.exports = { - preset: 'ts-jest', +export default { + preset: 'ts-jest/presets/default-esm', + globals: { + 'ts-jest': { + useESM: true, + }, + }, testEnvironment: 'node', moduleNameMapper: { + // Since Jest doesn't supports `exports`, it will resolve the CJS exports of discord.js + // a way to fix this, is to force the use of the ESM wrapper of discord.js + '^discord.js$': 'discord.js/src/index.mjs', + '^node:(.+)$': '$1', + '^(\\.\\.?/.+)\\.js$': '$1', '^#src/(.*)$': '/src/$1', }, }; diff --git a/package-lock.json b/package-lock.json index fa77c94..d25f56d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -19,7 +19,6 @@ }, "devDependencies": { "@types/cron": "^1.7.3", - "@types/emoji-regex": "^8.0.0", "@types/jest": "^26.0.24", "@types/node": "^16.4.13", "@types/pino": "^6.3.9", @@ -36,7 +35,7 @@ "typescript": "^4.3.5" }, "engines": { - "node": ">=16.6.0" + "node": ">=16.6.1" } }, "node_modules/@babel/code-frame": { @@ -8247,8 +8246,7 @@ } }, "@types/emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/@types/emoji-regex/-/emoji-regex-8.0.0.tgz", + "version": "https://registry.npmjs.org/@types/emoji-regex/-/emoji-regex-8.0.0.tgz", "integrity": "sha512-iacbaYN9IWWrGWTwlYLVOeUtN/e4cjN9Uh6v7Yo1Qa/vJzeSQeh10L/erBBSl53BTmbnQ07vsWp8mmNHGI4WbQ==", "dev": true }, diff --git a/package.json b/package.json index 98754ea..31b266f 100644 --- a/package.json +++ b/package.json @@ -2,6 +2,7 @@ "name": "esc-bot", "version": "0.0.0", "private": true, + "type": "module", "scripts": { "build": "tsc -p tsconfig.prod.json", "check-types": "tsc --noEmit", @@ -9,10 +10,10 @@ "format": "prettier --write src tests", "lint": "eslint src --ext ts", "lint-fix": "npm run lint -- --fix", - "start": "nodemon --watch \"src/**/*.ts\" -e ts --exec \"ts-node -r dotenv/config src/bot.ts | pino-pretty\"", + "start": "nodemon --watch \"src/**/*.ts\" -e ts --exec \"node --loader ts-node/esm -r dotenv/config src/bot.ts | pino-pretty\"", "test": "npm run test-only && npm run lint && npm run check-types", - "test-only": "jest", - "test-coverage": "jest --coverage" + "test-only": "node --experimental-vm-modules node_modules/jest/bin/jest.js", + "test-coverage": "npm run test-only -- --coverage" }, "repository": { "type": "git", @@ -34,7 +35,6 @@ }, "devDependencies": { "@types/cron": "^1.7.3", - "@types/emoji-regex": "^8.0.0", "@types/jest": "^26.0.24", "@types/node": "^16.4.13", "@types/pino": "^6.3.9", @@ -51,7 +51,7 @@ "typescript": "^4.3.5" }, "engines": { - "node": ">=16.6.0" + "node": ">=16.6.1" }, "volta": { "node": "16.6.1" diff --git a/src/bot.ts b/src/bot.ts index dea7924..e67fbbf 100644 --- a/src/bot.ts +++ b/src/bot.ts @@ -1,17 +1,14 @@ // Must be imported first so it runs before other files. -import './setup-env'; +import './setup-env.js'; -import path from 'path'; +import { Bot } from './framework/index.js'; -import { Bot } from './framework'; +const bot = new Bot(process.env.DISCORD_TOKEN); -const bot = new Bot({ - token: process.env.DISCORD_TOKEN, - commands: path.join(__dirname, 'commands'), - crons: path.join(__dirname, 'crons'), - formatCheckers: path.join(__dirname, 'format-checkers'), +await bot.start({ + commands: new URL('commands/', import.meta.url), + crons: new URL('crons/', import.meta.url), + formatCheckers: new URL('format-checkers/', import.meta.url), }); -bot.start().then(() => { - bot.logger.info('Bot started'); -}); +bot.logger.info('Bot started'); diff --git a/src/commands/Hello.ts b/src/commands/Hello.ts index 43d50da..c143731 100644 --- a/src/commands/Hello.ts +++ b/src/commands/Hello.ts @@ -1,4 +1,4 @@ -import { Command, CommandOptionTypes } from '../framework'; +import { Command, CommandOptionTypes } from '../framework/index.js'; export default new Command({ name: 'hello', diff --git a/src/crons/CommitStrip.ts b/src/crons/CommitStrip.ts index aca2264..38d272d 100644 --- a/src/crons/CommitStrip.ts +++ b/src/crons/CommitStrip.ts @@ -2,7 +2,7 @@ import { MessageEmbed } from 'discord.js'; import got from 'got'; import { decode } from 'html-entities'; -import { Cron, findTextChannelByName } from '../framework'; +import { Cron, findTextChannelByName } from '../framework/index.js'; export default new Cron({ enabled: true, diff --git a/src/crons/EpicGames.ts b/src/crons/EpicGames.ts index 779faa3..0037440 100644 --- a/src/crons/EpicGames.ts +++ b/src/crons/EpicGames.ts @@ -2,7 +2,7 @@ import { MessageEmbed } from 'discord.js'; import got from 'got'; import { Logger } from 'pino'; -import { Cron, findTextChannelByName } from '../framework'; +import { Cron, findTextChannelByName } from '../framework/index.js'; const dateFmtOptions: Intl.DateTimeFormatOptions = { timeZone: 'Europe/Paris', diff --git a/src/emoji-regex.ts b/src/emoji-regex.ts new file mode 100644 index 0000000..a523f5a --- /dev/null +++ b/src/emoji-regex.ts @@ -0,0 +1,7 @@ +/* eslint-disable @typescript-eslint/no-var-requires */ + +import { createRequire } from 'node:module'; +const require = createRequire(import.meta.url); + +// emoji-regex, TypeScript and ESM do not like each other. +export default require('emoji-regex/text')() as RegExp; diff --git a/src/format-checkers/Job.ts b/src/format-checkers/Job.ts index 4335e6b..4df702a 100644 --- a/src/format-checkers/Job.ts +++ b/src/format-checkers/Job.ts @@ -1,4 +1,4 @@ -import { FormatChecker } from '../framework'; +import { FormatChecker } from '../framework/index.js'; export default new FormatChecker({ enabled: true, diff --git a/src/format-checkers/Link.ts b/src/format-checkers/Link.ts index 809a459..c84f484 100644 --- a/src/format-checkers/Link.ts +++ b/src/format-checkers/Link.ts @@ -1,18 +1,17 @@ -import { FormatChecker } from '../framework'; -import createRegExp from 'emoji-regex/text'; +import { FormatChecker } from '../framework/index.js'; +import emojiRegExp from '../emoji-regex.js'; -const unicodeEmojiRegexp = createRegExp().source; -const urlRegexp = +const urlRegExp = '?'; -const titleRegexp = `(?:[\\w- ]|(?:)|${unicodeEmojiRegexp})+`; -const linkRegexp = `^\\[( )?(\\*\\*)?${titleRegexp}\\2\\1\\](?:[^\\n])+ - ${urlRegexp}$`; +const titleRegExp = `(?:[\\w- ]|(?:)|${emojiRegExp})+`; +const linkRegExp = `^\\[( )?(\\*\\*)?${titleRegExp}\\2\\1\\](?:[^\\n])+ - ${urlRegExp}$`; export default new FormatChecker({ enabled: true, name: 'Link', description: 'Force le formatage du canal #liens.', channelName: 'liens', - checker: new RegExp(linkRegexp), + checker: new RegExp(linkRegExp), examples: [ '[**SUJET**] Votre description ici - https://github.com/es-community', '[👍] Votre description ici - https://github.com/es-community', diff --git a/src/format-checkers/Project.ts b/src/format-checkers/Project.ts index 348b447..0dcd289 100644 --- a/src/format-checkers/Project.ts +++ b/src/format-checkers/Project.ts @@ -1,12 +1,11 @@ -import createRegExp from 'emoji-regex/text'; -import { FormatChecker } from '../framework'; +import { FormatChecker } from '../framework/index.js'; +import emojiRegExp from '../emoji-regex.js'; -const unicodeEmojiRegexp = createRegExp().source; -const urlRegexp = +const urlRegExp = '?'; -const headerRegexp = `(?:[\\w- ]|(?:)|${unicodeEmojiRegexp})`; -const projectRegexp = new RegExp( - `^\\*\\*${headerRegexp}+\\*\\*\\n\\n(?:.*\\n)+\n(?:(?:${headerRegexp}* )?${urlRegexp}\n)+$`, +const headerRegExp = `(?:[\\w- ]|(?:)|${emojiRegExp})`; +const projectRegExp = new RegExp( + `^\\*\\*${headerRegExp}+\\*\\*\\n\\n(?:.*\\n)+\n(?:(?:${headerRegExp}* )?${urlRegExp}\n)+$`, ); export default new FormatChecker({ @@ -14,7 +13,7 @@ export default new FormatChecker({ name: 'Project', description: 'Force le formatage du canal #projets.', channelName: 'projets', - checker: ({ cleanContent }) => projectRegexp.test(cleanContent + '\n'), + checker: ({ cleanContent }) => projectRegExp.test(cleanContent + '\n'), examples: [ `**Nom du projet**\n\nDescription du projet\n\nhttps://github.com`, ], diff --git a/src/framework/Bot.ts b/src/framework/Bot.ts index b62a02f..78eef50 100644 --- a/src/framework/Bot.ts +++ b/src/framework/Bot.ts @@ -1,33 +1,27 @@ -import { once } from 'events'; -import fs from 'fs'; -import path from 'path'; +import { once } from 'node:events'; +import fs from 'node:fs/promises'; import { Client, Intents } from 'discord.js'; import pino from 'pino'; -import { Base, BaseConfig } from './Base'; -import { Command, CommandManager } from './command'; -import { Cron } from './Cron'; -import { FormatChecker } from './FormatChecker'; +import { Command, CommandManager } from './command/index.js'; +import { Base, BaseConfig } from './Base.js'; +import { Cron } from './Cron.js'; +import { FormatChecker } from './FormatChecker.js'; -export interface BotOptions { - /** - * Discord token. - * Defaults to `process.env.DISCORD_TOKEN`. - */ - token?: string; +export interface BotStartOptions { /** * Directory that contains the `Command` definitions. */ - commands?: string; + commands?: URL; /** * Directory that contains the `Cron` definitions. */ - crons?: string; + crons?: URL; /** * Directory that contains the `FormatChecker` definitions. */ - formatCheckers?: string; + formatCheckers?: URL; } type Constructor = { @@ -37,46 +31,29 @@ type Constructor = { }; export class Bot { - private readonly token?: string; - private _client: Client | null; + private _client: Client | null; private commandManager?: CommandManager; private crons: Cron[] = []; private formatCheckers: FormatChecker[] = []; public readonly logger: pino.Logger; - public constructor(options: BotOptions = {}) { - this.token = options.token; + /** + * @param token Discord token. Defaults to `process.env.DISCORD_TOKEN`. + */ + public constructor(private readonly token?: string) { this._client = null; this.logger = pino(); - - if (options.commands) { - this.commandManager = new CommandManager( - this.loadDirectory(options.commands, 'commands', Command), - ); - } - - if (options.crons) { - this.crons = this.loadDirectory(options.crons, 'crons', Cron); - } - - if (options.formatCheckers) { - this.formatCheckers = this.loadDirectory( - options.formatCheckers, - 'format-checkers', - FormatChecker, - ); - } } - private loadDirectory( - directory: string, + private async loadDirectory( + directory: URL, name: string, constructor: Constructor, - ): T[] { + ): Promise { let list: string[]; try { - list = fs.readdirSync(directory); + list = await fs.readdir(directory); } catch (err) { if (err.code === 'ENOENT') { throw new Error( @@ -86,27 +63,22 @@ export class Bot { throw err; } - const allExports = list - .filter((file) => { - const ext = path.extname(file); - // Ignore non-source files (such as ".map") - return ['.js', '.ts'].includes(ext); - }) - .map((file) => { - const filePath = path.join(directory, file); - // eslint-disable-next-line @typescript-eslint/no-var-requires - const value = require(filePath); - if ( - !value || - !value.default || - !(value.default instanceof constructor) - ) { - throw new Error( - `${filePath} must export an instance of ${constructor.name}`, - ); - } - return value.default as T; - }); + const allExports = await Promise.all( + list + .filter((file) => !file.endsWith('.map')) + .map(async (file) => { + const filePath = new URL(file, directory); + // @ts-expect-error Types are not up to date + // eslint-disable-next-line @typescript-eslint/no-var-requires + const mod = await import(filePath); + if (!(mod.default instanceof constructor)) { + throw new Error( + `${filePath} must export an instance of ${constructor.name}`, + ); + } + return mod.default as T; + }), + ); const enabledExports = allExports.filter((element) => element.enabled); @@ -143,7 +115,7 @@ export class Bot { * Returns the discord.js Client instance. * The bot must be started first. */ - public get client(): Client { + public get client(): Client { if (!this._client) { throw new Error('Bot was not started'); } @@ -153,7 +125,7 @@ export class Bot { /** * Start the bot by connecting it to Discord. */ - public async start(): Promise { + public async start(options: BotStartOptions = {}): Promise { if (this._client) { throw new Error('Bot can only be started once'); } @@ -161,6 +133,24 @@ export class Bot { intents: new Intents(['GUILDS', 'GUILD_MESSAGES']), }); + if (options.commands) { + this.commandManager = new CommandManager( + await this.loadDirectory(options.commands, 'commands', Command), + ); + } + + if (options.crons) { + this.crons = await this.loadDirectory(options.crons, 'crons', Cron); + } + + if (options.formatCheckers) { + this.formatCheckers = await this.loadDirectory( + options.formatCheckers, + 'format-checkers', + FormatChecker, + ); + } + try { await Promise.all([ this.client.login(this.token), diff --git a/src/framework/Cron.ts b/src/framework/Cron.ts index d11a8ac..8a2a68c 100644 --- a/src/framework/Cron.ts +++ b/src/framework/Cron.ts @@ -1,10 +1,11 @@ -import { randomUUID } from 'crypto'; +import { randomUUID } from 'node:crypto'; + import { CronJob, CronTime } from 'cron'; import { Client, Formatters, MessageEmbed } from 'discord.js'; import { Logger } from 'pino'; -import { Base, BaseConfig } from './Base'; -import { Bot } from './Bot'; -import { findTextChannelByName } from './helpers'; +import { Base, BaseConfig } from './Base.js'; +import { Bot } from './Bot.js'; +import { findTextChannelByName } from './helpers.js'; export type CronHandler = (context: CronContext) => Promise; @@ -54,11 +55,7 @@ export class Cron extends Base { private async executeJob(date: Date, bot: Bot) { const id = randomUUID(); - const logger = bot.logger.child({ - id, - type: 'Cron', - cronName: this.name, - }); + const logger = bot.logger.child({ id, type: 'Cron', cronName: this.name }); try { logger.debug('execute cron handler'); await this.handler({ date, client: bot.client, logger }); diff --git a/src/framework/FormatChecker.ts b/src/framework/FormatChecker.ts index 18fefd7..cbd894b 100644 --- a/src/framework/FormatChecker.ts +++ b/src/framework/FormatChecker.ts @@ -1,9 +1,10 @@ +import { randomUUID } from 'node:crypto'; + import { Message, PartialMessage } from 'discord.js'; -import { randomUUID } from 'crypto'; import { Logger } from 'pino'; -import { Base, BaseConfig } from './Base'; -import { Bot } from './Bot'; -import { findTextChannelByName, isTextChannel } from './helpers'; +import { Base, BaseConfig } from './Base.js'; +import { Bot } from './Bot.js'; +import { findTextChannelByName, isTextChannel } from './helpers.js'; type FunctionChecker = (message: Message, logger: Logger) => boolean; diff --git a/src/framework/command/Command.ts b/src/framework/command/Command.ts index 56482b1..8a0e2d8 100644 --- a/src/framework/command/Command.ts +++ b/src/framework/command/Command.ts @@ -13,7 +13,7 @@ import type { APIInteractionDataResolvedChannel, } from 'discord-api-types/v9'; import type { Logger } from 'pino'; -import { Base, BaseConfig } from '../Base'; +import { Base, BaseConfig } from '../Base.js'; export const enum CommandOptionTypes { String = 3, diff --git a/src/framework/command/CommandManager.ts b/src/framework/command/CommandManager.ts index 4c3df40..2b28b1d 100644 --- a/src/framework/command/CommandManager.ts +++ b/src/framework/command/CommandManager.ts @@ -1,8 +1,8 @@ /* eslint-disable @typescript-eslint/no-explicit-any, @typescript-eslint/no-non-null-assertion */ -import { randomUUID } from 'crypto'; +import { randomUUID } from 'node:crypto'; import { Snowflake, Interaction } from 'discord.js'; -import type { Bot } from '../Bot'; -import { Command } from './Command'; +import type { Bot } from '../Bot.js'; +import type { Command } from './Command.js'; export class CommandManager { /** diff --git a/src/framework/command/index.ts b/src/framework/command/index.ts index f7d8e84..f2bd8f1 100644 --- a/src/framework/command/index.ts +++ b/src/framework/command/index.ts @@ -1,2 +1,2 @@ -export * from './Command'; -export * from './CommandManager'; +export * from './Command.js'; +export * from './CommandManager.js'; diff --git a/src/framework/index.ts b/src/framework/index.ts index e7d8e8c..b0c9b15 100644 --- a/src/framework/index.ts +++ b/src/framework/index.ts @@ -1,5 +1,5 @@ -export * from './Bot'; -export * from './Cron'; -export * from './FormatChecker'; -export * from './command'; -export * from './helpers'; +export * from './command/index.js'; +export * from './Bot.js'; +export * from './Cron.js'; +export * from './FormatChecker.js'; +export * from './helpers.js'; diff --git a/src/global.d.ts b/src/global.d.ts new file mode 100644 index 0000000..f9821eb --- /dev/null +++ b/src/global.d.ts @@ -0,0 +1,11 @@ +import { URL as _URL, URLSearchParams as _URLSearchParams } from 'node:url'; + +declare global { + // https://github.com/DefinitelyTyped/DefinitelyTyped/issues/34960 + + const URLSearchParams: typeof _URLSearchParams; + type URLSearchParams = _URLSearchParams; + + const URL: typeof _URL; + type URL = _URL; +} diff --git a/tests/framework/Bot.spec.ts b/tests/framework/Bot.spec.ts index f6538c3..20aac9f 100644 --- a/tests/framework/Bot.spec.ts +++ b/tests/framework/Bot.spec.ts @@ -1,14 +1,14 @@ import { Bot } from '#src/framework'; -const dummyOptions = { token: 'dummy' }; +const dummyToken = 'dummy'; test('bot.start() throws if called with bad token', async () => { - const bot = new Bot(dummyOptions); + const bot = new Bot(dummyToken); await expect(bot.start()).rejects.toThrow(/invalid token/); }); test('bot.start() throws if called twice', async () => { - const bot = new Bot(dummyOptions); + const bot = new Bot(dummyToken); bot.start().catch(() => { // ignore }); @@ -16,11 +16,11 @@ test('bot.start() throws if called twice', async () => { }); test('bot.stop() throws if it was not started', async () => { - const bot = new Bot(dummyOptions); + const bot = new Bot(dummyToken); await expect(bot.stop()).rejects.toThrow(/was not started/); }); test('bot.client throws if it was not started', () => { - const bot = new Bot(dummyOptions); + const bot = new Bot(dummyToken); expect(() => bot.client).toThrow(/was not started/); }); diff --git a/tsconfig.json b/tsconfig.json index 63b16f0..413527e 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,12 +1,12 @@ { "include": ["src/**/*.ts", "tests/**/*.ts"], "compilerOptions": { - "target": "ES2020", - "lib": ["ES2020"], + "target": "ESNext", + "lib": ["ESNext"], "strict": true, "outDir": "build", "moduleResolution": "node", - "module": "CommonJS", + "module": "ESNext", "esModuleInterop": true, "sourceMap": true, "rootDir": "./", From 57338fc555a82b83964a396d47d3a4337e931c03 Mon Sep 17 00:00:00 2001 From: Mestery Date: Tue, 10 Aug 2021 18:56:48 +0200 Subject: [PATCH 4/5] feat: add slash commands manager tool --- README.md | 18 ++- package-lock.json | 202 +++++++++++++++++++++-- package.json | 3 + src/framework/command/Command.ts | 33 ++-- src/framework/command/CommandManager.ts | 86 ++++++---- src/framework/command/helpers.ts | 19 +++ tools/masco.ts | 206 ++++++++++++++++++++++++ tsconfig.json | 5 +- 8 files changed, 505 insertions(+), 67 deletions(-) create mode 100644 src/framework/command/helpers.ts create mode 100644 tools/masco.ts diff --git a/README.md b/README.md index 8db9cb0..0b14677 100644 --- a/README.md +++ b/README.md @@ -73,16 +73,28 @@ Cette commande exĂ©cute le compilateur TypeScript avec l'option `--noEmit`. Elle ### Commandes +#### Migrations + +Si vous avez apportĂ© des modifications Ă  des commandes, ajoutĂ© des nouvelles commandes ou supprimĂ© des commands, vous devez lancer une migration avant de lancer le bot. +Les migrations permettent d'enregistrer ou de mettre Ă  jour les commande auprĂšs de Discord. Si la migration n'est pas effectuĂ© (lorsque c'est nĂ©cessaire), les nouvelles commandes, commandes modifiĂ©es ou supprimĂ©es disfonctionneront. Le bot vous avertira au dĂ©marrage si une migration est nĂ©cessaire. + +Pour migrer le commande vous pouvez faire : + +```sh +$ npm run masco migrate # pour toutes les commandes +$ npm run masco migrate # pour une commande spĂ©cifique +``` + +Veuillez vous rĂ©fĂ©r Ă  la commande d'aide de `masco` pour plus d'informations et d'exempels : `npm run help`. + Chaque commande doit ĂȘtre Ă©crite dans un fichier du dossier `src/commands`. Ce fichier doit instancier et exporter par dĂ©faut une instance de la classe `Command`, en lui passant les paramĂštres de configuration suivants : -- `enabled`: boolean. Peut ĂȘtre mis Ă  `false` pour dĂ©sactiver la commande. +- `enabled`: boolean. Si la commande doit ĂȘtre activĂ© par dĂ©faut quand le bot est ajoutĂ© Ă  un serveur (`true` par dĂ©faut) (correspond Ă  `default_permission`). - `name`: string. Nom de la commande.. - `description`: string. Description de ce que fait la commande (en français). - `options`?: object. Options (arguments) de la commande. -- `guildId`?: Snowflake. L'identifiant d'une guilde, si cette commande est spĂ©cifique Ă  une guilde. -- `defaultPermission`?: boolean. Si la commande doit ĂȘtre activĂ© par dĂ©faut quand le bot est ajoutĂ© Ă  un serveur (`true` par dĂ©faut). - `handle`: function. Fonction exĂ©cutĂ©e lorsque cette commande est appellĂ©e. Elle recevra un argument `context`, avec les propriĂ©tĂ©s : - `args`: Objet correctement typĂ©, contenant les options fournis par l'Ă©xecuteur de la commande (abstraction d'`interaction.options`). - `interaction`: Instance de CommandInteraction (discord.js). diff --git a/package-lock.json b/package-lock.json index d25f56d..9b79da9 100644 --- a/package-lock.json +++ b/package-lock.json @@ -18,9 +18,11 @@ "pino": "^6.12.0" }, "devDependencies": { + "@discordjs/rest": "^0.1.0-canary.0", "@types/cron": "^1.7.3", "@types/jest": "^26.0.24", "@types/node": "^16.4.13", + "@types/node-fetch": "^2.5.12", "@types/pino": "^6.3.9", "@typescript-eslint/eslint-plugin": "^4.28.2", "@typescript-eslint/parser": "^4.28.2", @@ -721,6 +723,12 @@ "npm": ">=7.0.0" } }, + "node_modules/@discordjs/collection": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/@discordjs/collection/-/collection-0.1.6.tgz", + "integrity": "sha512-utRNxnd9kSS2qhyivo9lMlt5qgAUasH2gb7BEOn6p0efFh24gjGomHzWKMAPn2hEReOPQZCJaRKoURwRotKucQ==", + "dev": true + }, "node_modules/@discordjs/form-data": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/@discordjs/form-data/-/form-data-3.0.1.tgz", @@ -734,6 +742,35 @@ "node": ">= 6" } }, + "node_modules/@discordjs/rest": { + "version": "0.1.0-canary.0", + "resolved": "https://registry.npmjs.org/@discordjs/rest/-/rest-0.1.0-canary.0.tgz", + "integrity": "sha512-d+s//ISYVV+e0w/926wMEeO7vju+Pn11x1JM4tcmVMCHSDgpi6pnFCNAXF1TEdnDcy7xf9tq5cf2pQkb/7ySTQ==", + "dev": true, + "dependencies": { + "@discordjs/collection": "^0.1.6", + "@sapphire/async-queue": "^1.1.4", + "@sapphire/snowflake": "^1.3.5", + "abort-controller": "^3.0.0", + "discord-api-types": "^0.18.1", + "form-data": "^4.0.0", + "node-fetch": "^2.6.1", + "tslib": "^2.3.0" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@discordjs/rest/node_modules/discord-api-types": { + "version": "0.18.1", + "resolved": "https://registry.npmjs.org/discord-api-types/-/discord-api-types-0.18.1.tgz", + "integrity": "sha512-hNC38R9ZF4uaujaZQtQfm5CdQO58uhdkoHQAVvMfIL0LgOSZeW575W8H6upngQOuoxWd8tiRII3LLJm9zuQKYg==", + "deprecated": "No longer supported. Install the latest release (0.20.2)", + "dev": true, + "engines": { + "node": ">=12" + } + }, "node_modules/@eslint/eslintrc": { "version": "0.4.3", "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-0.4.3.tgz", @@ -1098,6 +1135,16 @@ "npm": ">=6" } }, + "node_modules/@sapphire/snowflake": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/@sapphire/snowflake/-/snowflake-1.3.6.tgz", + "integrity": "sha512-QnzuLp+p9D7agynVub/zqlDVriDza9y3STArBhNiNBUgIX8+GL5FpQxstRfw1jDr5jkZUjcuKYAHxjIuXKdJAg==", + "dev": true, + "engines": { + "node": ">=12", + "npm": ">=6" + } + }, "node_modules/@sindresorhus/is": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-4.0.1.tgz", @@ -1233,12 +1280,6 @@ "moment": ">=2.14.0" } }, - "node_modules/@types/emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/@types/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-iacbaYN9IWWrGWTwlYLVOeUtN/e4cjN9Uh6v7Yo1Qa/vJzeSQeh10L/erBBSl53BTmbnQ07vsWp8mmNHGI4WbQ==", - "dev": true - }, "node_modules/@types/graceful-fs": { "version": "4.1.5", "resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.5.tgz", @@ -1306,6 +1347,30 @@ "resolved": "https://registry.npmjs.org/@types/node/-/node-16.4.13.tgz", "integrity": "sha512-bLL69sKtd25w7p1nvg9pigE4gtKVpGTPojBFLMkGHXuUgap2sLqQt2qUnqmVCDfzGUL0DRNZP+1prIZJbMeAXg==" }, + "node_modules/@types/node-fetch": { + "version": "2.5.12", + "resolved": "https://registry.npmjs.org/@types/node-fetch/-/node-fetch-2.5.12.tgz", + "integrity": "sha512-MKgC4dlq4kKNa/mYrwpKfzQMB5X3ee5U6fSprkKpToBqBmX4nFZL9cW5jl6sWn+xpRJ7ypWh2yyqqr8UUCstSw==", + "dev": true, + "dependencies": { + "@types/node": "*", + "form-data": "^3.0.0" + } + }, + "node_modules/@types/node-fetch/node_modules/form-data": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-3.0.1.tgz", + "integrity": "sha512-RHkBKtLWUVwd7SqRIvCZMEvAMoGUp0XU+seQiZejj0COz3RI3hWP4sCv3gZWWLjJTd7rGwcsF5eKZGii0r/hbg==", + "dev": true, + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/@types/pino": { "version": "6.3.11", "resolved": "https://registry.npmjs.org/@types/pino/-/pino-6.3.11.tgz", @@ -1547,6 +1612,18 @@ "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", "dev": true }, + "node_modules/abort-controller": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz", + "integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==", + "dev": true, + "dependencies": { + "event-target-shim": "^5.0.0" + }, + "engines": { + "node": ">=6.5" + } + }, "node_modules/acorn": { "version": "7.4.1", "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", @@ -3047,6 +3124,15 @@ "node": ">=0.10.0" } }, + "node_modules/event-target-shim": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz", + "integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, "node_modules/execa": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", @@ -3246,6 +3332,20 @@ "integrity": "sha512-JaTY/wtrcSyvXJl4IMFHPKyFur1sE9AUqc0QnhOaJ0CxHtAoIV8pYDzeEfAaNEtGkOfq4gr3LBFmdXW5mOQFnA==", "dev": true }, + "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==", + "dev": true, + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/fs.realpath": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", @@ -7823,6 +7923,12 @@ "tslib": "^2.3.0" } }, + "@discordjs/collection": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/@discordjs/collection/-/collection-0.1.6.tgz", + "integrity": "sha512-utRNxnd9kSS2qhyivo9lMlt5qgAUasH2gb7BEOn6p0efFh24gjGomHzWKMAPn2hEReOPQZCJaRKoURwRotKucQ==", + "dev": true + }, "@discordjs/form-data": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/@discordjs/form-data/-/form-data-3.0.1.tgz", @@ -7833,6 +7939,30 @@ "mime-types": "^2.1.12" } }, + "@discordjs/rest": { + "version": "0.1.0-canary.0", + "resolved": "https://registry.npmjs.org/@discordjs/rest/-/rest-0.1.0-canary.0.tgz", + "integrity": "sha512-d+s//ISYVV+e0w/926wMEeO7vju+Pn11x1JM4tcmVMCHSDgpi6pnFCNAXF1TEdnDcy7xf9tq5cf2pQkb/7ySTQ==", + "dev": true, + "requires": { + "@discordjs/collection": "^0.1.6", + "@sapphire/async-queue": "^1.1.4", + "@sapphire/snowflake": "^1.3.5", + "abort-controller": "^3.0.0", + "discord-api-types": "^0.18.1", + "form-data": "^4.0.0", + "node-fetch": "^2.6.1", + "tslib": "^2.3.0" + }, + "dependencies": { + "discord-api-types": { + "version": "0.18.1", + "resolved": "https://registry.npmjs.org/discord-api-types/-/discord-api-types-0.18.1.tgz", + "integrity": "sha512-hNC38R9ZF4uaujaZQtQfm5CdQO58uhdkoHQAVvMfIL0LgOSZeW575W8H6upngQOuoxWd8tiRII3LLJm9zuQKYg==", + "dev": true + } + } + }, "@eslint/eslintrc": { "version": "0.4.3", "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-0.4.3.tgz", @@ -8122,6 +8252,12 @@ "resolved": "https://registry.npmjs.org/@sapphire/async-queue/-/async-queue-1.1.4.tgz", "integrity": "sha512-fFrlF/uWpGOX5djw5Mu2Hnnrunao75WGey0sP0J3jnhmrJ5TAPzHYOmytD5iN/+pMxS+f+u/gezqHa9tPhRHEA==" }, + "@sapphire/snowflake": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/@sapphire/snowflake/-/snowflake-1.3.6.tgz", + "integrity": "sha512-QnzuLp+p9D7agynVub/zqlDVriDza9y3STArBhNiNBUgIX8+GL5FpQxstRfw1jDr5jkZUjcuKYAHxjIuXKdJAg==", + "dev": true + }, "@sindresorhus/is": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-4.0.1.tgz", @@ -8245,11 +8381,6 @@ "moment": ">=2.14.0" } }, - "@types/emoji-regex": { - "version": "https://registry.npmjs.org/@types/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-iacbaYN9IWWrGWTwlYLVOeUtN/e4cjN9Uh6v7Yo1Qa/vJzeSQeh10L/erBBSl53BTmbnQ07vsWp8mmNHGI4WbQ==", - "dev": true - }, "@types/graceful-fs": { "version": "4.1.5", "resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.5.tgz", @@ -8317,6 +8448,29 @@ "resolved": "https://registry.npmjs.org/@types/node/-/node-16.4.13.tgz", "integrity": "sha512-bLL69sKtd25w7p1nvg9pigE4gtKVpGTPojBFLMkGHXuUgap2sLqQt2qUnqmVCDfzGUL0DRNZP+1prIZJbMeAXg==" }, + "@types/node-fetch": { + "version": "2.5.12", + "resolved": "https://registry.npmjs.org/@types/node-fetch/-/node-fetch-2.5.12.tgz", + "integrity": "sha512-MKgC4dlq4kKNa/mYrwpKfzQMB5X3ee5U6fSprkKpToBqBmX4nFZL9cW5jl6sWn+xpRJ7ypWh2yyqqr8UUCstSw==", + "dev": true, + "requires": { + "@types/node": "*", + "form-data": "^3.0.0" + }, + "dependencies": { + "form-data": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-3.0.1.tgz", + "integrity": "sha512-RHkBKtLWUVwd7SqRIvCZMEvAMoGUp0XU+seQiZejj0COz3RI3hWP4sCv3gZWWLjJTd7rGwcsF5eKZGii0r/hbg==", + "dev": true, + "requires": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + } + } + } + }, "@types/pino": { "version": "6.3.11", "resolved": "https://registry.npmjs.org/@types/pino/-/pino-6.3.11.tgz", @@ -8484,6 +8638,15 @@ "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", "dev": true }, + "abort-controller": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz", + "integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==", + "dev": true, + "requires": { + "event-target-shim": "^5.0.0" + } + }, "acorn": { "version": "7.4.1", "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", @@ -9624,6 +9787,12 @@ "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", "dev": true }, + "event-target-shim": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz", + "integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==", + "dev": true + }, "execa": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", @@ -9785,6 +9954,17 @@ "integrity": "sha512-JaTY/wtrcSyvXJl4IMFHPKyFur1sE9AUqc0QnhOaJ0CxHtAoIV8pYDzeEfAaNEtGkOfq4gr3LBFmdXW5mOQFnA==", "dev": true }, + "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==", + "dev": true, + "requires": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + } + }, "fs.realpath": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", diff --git a/package.json b/package.json index 31b266f..fc58325 100644 --- a/package.json +++ b/package.json @@ -4,6 +4,7 @@ "private": true, "type": "module", "scripts": { + "masco": "node --loader ts-node/esm tools/masco.ts", "build": "tsc -p tsconfig.prod.json", "check-types": "tsc --noEmit", "heroku-postbuild": "npm run build", @@ -34,9 +35,11 @@ "pino": "^6.12.0" }, "devDependencies": { + "@discordjs/rest": "^0.1.0-canary.0", "@types/cron": "^1.7.3", "@types/jest": "^26.0.24", "@types/node": "^16.4.13", + "@types/node-fetch": "^2.5.12", "@types/pino": "^6.3.9", "@typescript-eslint/eslint-plugin": "^4.28.2", "@typescript-eslint/parser": "^4.28.2", diff --git a/src/framework/command/Command.ts b/src/framework/command/Command.ts index 8a0e2d8..dcc4f9a 100644 --- a/src/framework/command/Command.ts +++ b/src/framework/command/Command.ts @@ -4,7 +4,6 @@ import type { GuildChannel, GuildMember, Role, - Snowflake, User, } from 'discord.js'; import type { @@ -25,7 +24,7 @@ export const enum CommandOptionTypes { Mentionable, } -interface CommandOptionsData< +type CommandOptionsData< T extends CommandOptionTypes = | CommandOptionTypes.Boolean | CommandOptionTypes.Channel @@ -33,14 +32,18 @@ interface CommandOptionsData< | CommandOptionTypes.Role | CommandOptionTypes.User, C = never, -> { +> = { readonly type: T; readonly description: string; + /** + * If the options is required + * @default false + */ readonly required?: boolean; readonly choices?: C extends never ? never - : readonly { readonly name: string; readonly value: C }[]; -} + : readonly { readonly name: string; readonly value: T }[]; +}; export type CommandOptions = Record< string, @@ -107,15 +110,11 @@ export interface CommandContext { export interface CommandConfig extends BaseConfig { - /** - * The guild ID (if this command is specific to a guild) - */ - guildId?: Snowflake; /** * Whether the command is enabled by default when the app is added to a guild * @default true */ - defaultPermission?: boolean; + enabled: boolean; /** * Command options */ @@ -127,15 +126,15 @@ export interface CommandConfig } export class Command extends Base { - /** - * The guild ID (if this command is specific to a guild) - */ - public readonly guildId: Snowflake | undefined; /** * Whether the command is enabled by default when the app is added to a guild * @default true */ - public readonly defaultPermission: boolean | undefined; + public readonly enabled: boolean; + /** + * Command name + */ + public readonly name: string; /** * Command options */ @@ -147,9 +146,9 @@ export class Command extends Base { public constructor(config: CommandConfig) { super(config); - this.guildId = config.guildId; + this.name = config.name.toLowerCase(); this.options = config.options; - this.defaultPermission = config.defaultPermission; + this.enabled = config.enabled; this.handler = config.handle; } } diff --git a/src/framework/command/CommandManager.ts b/src/framework/command/CommandManager.ts index 2b28b1d..e0cd1ca 100644 --- a/src/framework/command/CommandManager.ts +++ b/src/framework/command/CommandManager.ts @@ -1,8 +1,11 @@ /* eslint-disable @typescript-eslint/no-explicit-any, @typescript-eslint/no-non-null-assertion */ import { randomUUID } from 'node:crypto'; -import { Snowflake, Interaction } from 'discord.js'; +import { isDeepStrictEqual } from 'node:util'; + +import { Snowflake, Interaction, Constants } from 'discord.js'; import type { Bot } from '../Bot.js'; import type { Command } from './Command.js'; +import { createCommandData } from './helpers.js'; export class CommandManager { /** @@ -11,8 +14,10 @@ export class CommandManager { public readonly commands = new Map(); private bot!: Bot; + private holds?: Command[]; - public constructor(private holds: Command[]) { + public constructor(holds: Command[]) { + this.holds = holds; this._interactionHandler = this._interactionHandler.bind(this); } @@ -25,12 +30,9 @@ export class CommandManager { if (!command) { return this.bot.logger - .child({ - id: randomUUID(), - type: 'CommandManager', - }) + .child({ id: randomUUID(), type: 'CommandManager' }) .error( - 'unregistred slash command %s (id: %s)', + 'unknown command %s (id: %s)', interaction.commandName, interaction.commandId, ); @@ -49,8 +51,8 @@ export class CommandManager { logger, interaction, args: Object.fromEntries( - interaction.options.data.map((option, name) => [ - name, + interaction.options.data.map((option) => [ + option.name, (option.member ?? option.user ?? option.channel ?? @@ -67,42 +69,56 @@ export class CommandManager { public async start(bot: Bot): Promise { this.bot = bot; - await Promise.all( - this.holds.map(async (hold) => { - // The application cannot be null if the Client is ready. - const command = await this.bot.client.application!.commands.create( + const registeredCommands = ( + await bot.client.application.commands.fetch() + ).clone(); + + for (const command of this.holds!) { + const commandData = createCommandData(command); + const registeredCommand = registeredCommands.find((command) => + isDeepStrictEqual( { - name: hold.name, - description: hold.description, - defaultPermission: hold.defaultPermission, - options: - hold.options && - (Object.entries(hold.options).map(([key, value]) => ({ - name: key, - ...value, - })) as any), + name: command.name, + description: command.description, + options: command.options.map(({ type, ...option }) => ({ + type: Constants.ApplicationCommandOptionTypes[type], + ...option, + })), + defaultPermission: command.defaultPermission, }, - hold.guildId as any, + commandData, + ), + ); + + if (registeredCommand) { + this.commands.set(registeredCommand.id, command); + registeredCommands.delete(registeredCommand.id); + } else { + bot.logger + .child({ id: randomUUID(), type: 'CommandManager' }) + .warn( + "The command '%s' is not registered or not up to date with the local command. Please run the migrations before starting the bot", + command.name, + ); + } + } + + for (const command of registeredCommands.values()) { + bot.logger + .child({ id: randomUUID(), type: 'CommandManager' }) + .warn( + "The registered command '%s' doesn't exist locally. Please run the migrations before starting the bot", + command.name, ); - this.commands.set(command.id, hold); - }), - ); + } // We don't need this.holds anymore. - this.holds = []; + delete this.holds; this.bot.client.on('interactionCreate', this._interactionHandler); } public async stop(bot: Bot): Promise { bot.client.off('interactionCreate', this._interactionHandler); - - // Unregister *all* registered slash commands. - await Promise.all( - // The application cannot be null if the Client is ready. - ( - await bot.client.application!.commands.fetch() - ).map((command) => command.delete()), - ); } } diff --git a/src/framework/command/helpers.ts b/src/framework/command/helpers.ts new file mode 100644 index 0000000..6ee1b41 --- /dev/null +++ b/src/framework/command/helpers.ts @@ -0,0 +1,19 @@ +import { ApplicationCommandData } from 'discord.js'; +import { Command } from './Command.js'; + +export const createCommandData = ( + command: Command, +): ApplicationCommandData => ({ + name: command.name, + description: command.description, + defaultPermission: command.enabled, + options: + command.options && + (Object.entries(command.options).map(([key, value]) => ({ + name: key, + required: false, + choices: undefined, + ...value, + options: undefined, + })) as any), +}); diff --git a/tools/masco.ts b/tools/masco.ts new file mode 100644 index 0000000..a4248a3 --- /dev/null +++ b/tools/masco.ts @@ -0,0 +1,206 @@ +'use strict'; + +const TOKEN = + process.env.DISCORD_TOKEN ?? + (await import('dotenv')).config().parsed?.DISCORD_TOKEN; +if (!TOKEN) { + throw new Error('DISCORD_TOKEN is missing.'); +} +const APPLICATION_ID = atob(TOKEN.split('.')[0]); + +import { fileURLToPath } from 'node:url'; +import { isDeepStrictEqual } from 'node:util'; +import { readdirSync } from 'node:fs'; + +import { ApplicationCommandData, SnowflakeUtil } from 'discord.js'; +import { REST as HttpClient } from '@discordjs/rest'; +import { + Routes, + RESTGetAPIApplicationCommandsResult, + RESTPostAPIApplicationCommandsJSONBody, + APIApplicationCommand, + RESTPutAPIApplicationCommandsJSONBody, + RESTPutAPIApplicationCommandsResult, + Snowflake, +} from 'discord-api-types/v9'; + +import { Command } from '../src/framework/index.js'; +import { createCommandData } from '../src/framework/command/helpers.js'; + +type APIApplicationCommandData = RESTPostAPIApplicationCommandsJSONBody; + +const httpClient = new HttpClient({ version: '9' }).setToken(TOKEN); + +const commandsPath = new URL('../src/commands/', import.meta.url); +const registeredCommands = (await httpClient.get( + Routes.applicationCommands(APPLICATION_ID), +)) as RESTGetAPIApplicationCommandsResult; + +async function importCommand( + fileName: string, +): Promise { + const filePath = new URL(fileName, commandsPath); + + // @ts-expect-error Types are not up to date + const mod = await import(filePath); + if (!(mod.default instanceof Command)) { + throw new Error( + `${fileURLToPath(filePath)} must export an instance of Command`, + ); + } + + const data = createCommandData(mod.default) as ApplicationCommandData & + APIApplicationCommandData; + data.default_permission = data.defaultPermission; + delete data.defaultPermission; + if (data.options?.length) { + for (const option of data.options as any) { + if (option.required === false) delete option.required; + if (!option.choices?.length) delete option.choices; + delete option.options; + } + } else delete data.options; + return data; +} + +// Limitations: +// A command name can be safely edit, if its description *and* its options have not been changed during the same migration run. +// A command description and/or options can be safely edited, if the name has not been changed during the same migration run. +function findTargetRegisteredCommand({ + name, + description, + default_permission, + options, +}: APIApplicationCommandData): + | [target: APIApplicationCommand, changed: boolean] + | undefined { + for (const command of registeredCommands.values()) { + const arePartiallyEqual = + description === command.description && + isDeepStrictEqual(options, command.options); + + if (name === command.name) + return [ + command, + !arePartiallyEqual || default_permission !== command.default_permission, + ]; + if (arePartiallyEqual) return [command, true]; // true because the name has changed + } +} + +async function purgeCommands(commandsIgnore?: Snowflake[]) { + await Promise.all( + registeredCommands.map(async ({ id, name }) => { + if (commandsIgnore?.includes(id)) return; + await httpClient.delete(Routes.applicationCommand(APPLICATION_ID, id)); + console.log(`Command ${name} has been successfully unregistered.`); + }), + ); +} + +const args = process.argv.slice(2); + +if (!args[0] || args[0] === 'help') { + console.log(` + This tool MAnages Slash COmmands between local and Discord. + + Usage: + $ masco [command] [command options] + + Commands: + help Displays this help message. + purge Deletes all registered commands. + list Lists all registered commands. + show Shows a registered *raw* command specific property (object path). + migrate Registers or updates local commands or specific command to Discord. + + Examples: + $ masco show hello options + $ masco show hello options.0.description + $ masco migrate + $ masco migrate Hello + `); + // delete all registered commands +} else if (args[0] === 'purge') { + purgeCommands(); +} else if (args[0] === 'show' && args[1]) { + let data: any = registeredCommands.find(({ name }) => name === args[1]); + if (!data) { + throw new Error('Command not found'); + } + if (args[2]) { + const keys = args[2].split('.'); + for (let i = 0; i < keys.length; i++) { + const key = keys[i]; + if (key in data) data = data[keys[i]]; + else + throw new Error( + `The path ${keys.slice(0, i + 1).join('.')} is invalid.`, + ); + } + } + console.dir(data, { depth: Infinity }); + // list all registered commands +} else if (args[0] === 'list') { + console.table( + Object.fromEntries( + registeredCommands.map((command) => [ + command.id, + { + name: command.name, + description: command.description, + enabled: command.default_permission, + }, + ]), + ), + ); + // migrate only a specific command +} else if (args[0] === 'migrate' && args[1]) { + const command = await importCommand(args[0]); + const targetData = await findTargetRegisteredCommand(command); + if (targetData?.[1]) { + await httpClient.patch( + Routes.applicationCommand(APPLICATION_ID, targetData[0].id), + { body: command }, + ); + console.log(`Command ${command.name} has been successfully updated.`); + } else { + await httpClient.post(Routes.applicationCommands(APPLICATION_ID), { + body: command, + }); + console.log(`Command ${command.name} has been successfully created.`); + } +} else if (args[0] === 'migrate') { + const body: RESTPutAPIApplicationCommandsJSONBody = []; + const knownCommands = Array(); + + for (const fileName of readdirSync(commandsPath)) { + if (fileName.endsWith('.map')) continue; + + const command = await importCommand(fileName); + const targetData = findTargetRegisteredCommand(command); + + if (!targetData || targetData[1]) body.push(command); + if (targetData) knownCommands.push(targetData[0].id); + } + + if (body.length > 0) { + const now = Date.now(); + const result = (await httpClient.put( + Routes.applicationCommands(APPLICATION_ID), + { body }, + )) as RESTPutAPIApplicationCommandsResult; + + for (const command of result) { + console.log( + `Command ${command.name} has been successfully %s.`, + SnowflakeUtil.deconstruct(command.id).timestamp > now + ? 'created' + : 'updated', + ); + } + } + + // unregister remaining commands (= deleted commands) + purgeCommands(knownCommands); +} diff --git a/tsconfig.json b/tsconfig.json index 413527e..5e506f7 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,5 +1,8 @@ { - "include": ["src/**/*.ts", "tests/**/*.ts"], + "include": ["src/**/*.ts", "tools/**/*.ts", "tests/**/*.ts"], + "ts-node": { + "files": true + }, "compilerOptions": { "target": "ESNext", "lib": ["ESNext"], From 9a8087695ad10167c797accf0a374e066ebccd59 Mon Sep 17 00:00:00 2001 From: Mestery Date: Tue, 10 Aug 2021 19:03:16 +0200 Subject: [PATCH 5/5] fixup! feat: add slash commands manager tool --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 0b14677..9698cd8 100644 --- a/README.md +++ b/README.md @@ -85,7 +85,7 @@ $ npm run masco migrate # pour toutes les commandes $ npm run masco migrate # pour une commande spĂ©cifique ``` -Veuillez vous rĂ©fĂ©r Ă  la commande d'aide de `masco` pour plus d'informations et d'exempels : `npm run help`. +Veuillez vous rĂ©fĂ©rer Ă  la commande d'aide de `masco` pour plus d'informations et d'exempels : `npm run help`. Chaque commande doit ĂȘtre Ă©crite dans un fichier du dossier `src/commands`. Ce fichier doit instancier et exporter par dĂ©faut une instance de la classe `Command`,