loads of new commands, updates and bug fixes
diff --git a/package-lock.json b/package-lock.json
new file mode 100644
index 0000000..3e187f2
--- /dev/null
+++ b/package-lock.json
@@ -0,0 +1,2920 @@
+{
+ "name": "nucleus",
+ "version": "0.0.1",
+ "lockfileVersion": 2,
+ "requires": true,
+ "packages": {
+ "": {
+ "name": "nucleus",
+ "version": "0.0.1",
+ "license": "SEE LICENSE IN LICENSE",
+ "dependencies": {
+ "@discordjs/builders": "^0.12.0",
+ "@ungap/structured-clone": "^1.0.1",
+ "body-parser": "^1.20.0",
+ "discord.js": "^13.8.0",
+ "express": "^4.18.1",
+ "humanize": "^0.0.9",
+ "humanize-duration": "^3.27.1",
+ "jshaiku": "file:../haiku",
+ "json-diff": "^0.7.1",
+ "mongodb": "^4.7.0",
+ "node-tesseract": "^0.2.7",
+ "structured-clone": "^0.2.2",
+ "tesseract.js": "^2.1.5",
+ "typescript": "^4.5.5",
+ "unscan": "^1.1.2"
+ }
+ },
+ "../haiku": {
+ "name": "jshaiku",
+ "version": "1.0.0",
+ "license": "AGPL-3.0",
+ "dependencies": {
+ "@discordjs/builders": "^0.11.0",
+ "@discordjs/rest": "^0.2.0-canary.0",
+ "@types/node-cron": "^3.0.1",
+ "ansi-styles": "^6.1.0",
+ "chalk": "^5.0.0",
+ "discord-api-types": "^0.26.1",
+ "discord.js": "^13.8.0",
+ "node-cron": "^3.0.0"
+ },
+ "devDependencies": {
+ "@babel/core": "^7.16.7",
+ "@babel/preset-env": "^7.16.8",
+ "@babel/preset-typescript": "^7.16.7",
+ "@types/jest": "^27.4.0",
+ "babel-jest": "^27.4.6",
+ "jest": "^27.4.7",
+ "ts-node": "^10.4.0",
+ "typescript": "4.5.4"
+ }
+ },
+ "node_modules/@discordjs/builders": {
+ "version": "0.12.0",
+ "resolved": "https://registry.npmjs.org/@discordjs/builders/-/builders-0.12.0.tgz",
+ "integrity": "sha512-Vx2MjUZd6QVo1uS2uWt708Fd6cHWGFblAvbpL5EBO+kLl0BADmPwwvts+YJ/VfSywed6Vsk6K2cEooR/Ytjhjw==",
+ "license": "Apache-2.0",
+ "dependencies": {
+ "@sindresorhus/is": "^4.3.0",
+ "discord-api-types": "^0.26.1",
+ "ts-mixer": "^6.0.0",
+ "tslib": "^2.3.1",
+ "zod": "^3.11.6"
+ },
+ "engines": {
+ "node": ">=16.9.0"
+ }
+ },
+ "node_modules/@discordjs/collection": {
+ "version": "0.7.0",
+ "resolved": "https://registry.npmjs.org/@discordjs/collection/-/collection-0.7.0.tgz",
+ "integrity": "sha512-R5i8Wb8kIcBAFEPLLf7LVBQKBDYUL+ekb23sOgpkpyGT+V4P7V83wTxcsqmX+PbqHt4cEHn053uMWfRqh/Z/nA==",
+ "engines": {
+ "node": ">=16.9.0"
+ }
+ },
+ "node_modules/@sapphire/async-queue": {
+ "version": "1.3.1",
+ "resolved": "https://registry.npmjs.org/@sapphire/async-queue/-/async-queue-1.3.1.tgz",
+ "integrity": "sha512-FFTlPOWZX1kDj9xCAsRzH5xEJfawg1lNoYAA+ecOWJMHOfiZYb1uXOI3ne9U4UILSEPwfE68p3T9wUHwIQfR0g==",
+ "engines": {
+ "node": ">=v14.0.0",
+ "npm": ">=7.0.0"
+ }
+ },
+ "node_modules/@sapphire/shapeshift": {
+ "version": "3.2.0",
+ "resolved": "https://registry.npmjs.org/@sapphire/shapeshift/-/shapeshift-3.2.0.tgz",
+ "integrity": "sha512-asNgE5Ooil2/oGIAj6vZMoUc2ZFED0TGYD7jwvZsjHPQZBEh9ITj94ca4bCgiCR1s2ER/UjzykH+5wE3ebVZnQ==",
+ "engines": {
+ "node": ">=v15.0.0",
+ "npm": ">=7.0.0"
+ }
+ },
+ "node_modules/@sindresorhus/is": {
+ "version": "4.6.0",
+ "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-4.6.0.tgz",
+ "integrity": "sha512-t09vSN3MdfsyCHoFcTRCH/iUtG7OJ0CsjzB8cjAmKc/va/kIgeDI/TxsigdncE/4be734m0cvIYwNaV4i2XqAw==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sindresorhus/is?sponsor=1"
+ }
+ },
+ "node_modules/@types/node": {
+ "version": "17.0.21",
+ "resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.21.tgz",
+ "integrity": "sha512-DBZCJbhII3r90XbQxI8Y9IjjiiOGlZ0Hr32omXIZvwwZ7p4DMMXGrKXVyPfuoBOri9XNtL0UK69jYIBIsRX3QQ==",
+ "license": "MIT"
+ },
+ "node_modules/@types/node-fetch": {
+ "version": "2.6.1",
+ "resolved": "https://registry.npmjs.org/@types/node-fetch/-/node-fetch-2.6.1.tgz",
+ "integrity": "sha512-oMqjURCaxoSIsHSr1E47QHzbmzNR5rK8McHuNb11BOM9cHcIK3Avy0s/b2JlXHoQGTYS3NsvWzV1M0iK7l0wbA==",
+ "license": "MIT",
+ "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==",
+ "license": "MIT",
+ "dependencies": {
+ "asynckit": "^0.4.0",
+ "combined-stream": "^1.0.8",
+ "mime-types": "^2.1.12"
+ },
+ "engines": {
+ "node": ">= 6"
+ }
+ },
+ "node_modules/@types/webidl-conversions": {
+ "version": "6.1.1",
+ "resolved": "https://registry.npmjs.org/@types/webidl-conversions/-/webidl-conversions-6.1.1.tgz",
+ "integrity": "sha512-XAahCdThVuCFDQLT7R7Pk/vqeObFNL3YqRyFZg+AqAP/W1/w3xHaIxuW7WszQqTbIBOPRcItYJIou3i/mppu3Q==",
+ "license": "MIT"
+ },
+ "node_modules/@types/whatwg-url": {
+ "version": "8.2.1",
+ "resolved": "https://registry.npmjs.org/@types/whatwg-url/-/whatwg-url-8.2.1.tgz",
+ "integrity": "sha512-2YubE1sjj5ifxievI5Ge1sckb9k/Er66HyR2c+3+I6VDUUg1TLPdYYTEbQ+DjRkS4nTxMJhgWfSfMRD2sl2EYQ==",
+ "license": "MIT",
+ "dependencies": {
+ "@types/node": "*",
+ "@types/webidl-conversions": "*"
+ }
+ },
+ "node_modules/@types/ws": {
+ "version": "8.5.3",
+ "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.3.tgz",
+ "integrity": "sha512-6YOoWjruKj1uLf3INHH7D3qTXwFfEsg1kf3c0uDdSBJwfa/llkwIjrAGV7j7mVgGNbzTQ3HiHKKDXl6bJPD97w==",
+ "dependencies": {
+ "@types/node": "*"
+ }
+ },
+ "node_modules/@ungap/structured-clone": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.0.1.tgz",
+ "integrity": "sha512-zKVyTt6rELvPXYwcVPTJcPFtY0AckN5A7xWuc7owBqR0FdtuDYhE9MZZUi6IY1kZUQFSXV1B3UOOIyLkVHYd2w==",
+ "license": "ISC"
+ },
+ "node_modules/accepts": {
+ "version": "1.3.8",
+ "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz",
+ "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==",
+ "license": "MIT",
+ "dependencies": {
+ "mime-types": "~2.1.34",
+ "negotiator": "0.6.3"
+ },
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/array-flatten": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz",
+ "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=",
+ "license": "MIT"
+ },
+ "node_modules/asynckit": {
+ "version": "0.4.0",
+ "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
+ "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=",
+ "license": "MIT"
+ },
+ "node_modules/balanced-match": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
+ "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==",
+ "license": "MIT"
+ },
+ "node_modules/base64-js": {
+ "version": "1.5.1",
+ "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz",
+ "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==",
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/feross"
+ },
+ {
+ "type": "patreon",
+ "url": "https://www.patreon.com/feross"
+ },
+ {
+ "type": "consulting",
+ "url": "https://feross.org/support"
+ }
+ ],
+ "license": "MIT"
+ },
+ "node_modules/blueimp-load-image": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/blueimp-load-image/-/blueimp-load-image-3.0.0.tgz",
+ "integrity": "sha512-Q9rFbd4ZUNvzSFmRXx9MoG0RwWwJeMjjEUbG7WIOJgUg22Jgkow0wL5b35B6qwiBscxACW9OHdrP5s2vQ3x8DQ==",
+ "license": "MIT"
+ },
+ "node_modules/bmp-js": {
+ "version": "0.1.0",
+ "resolved": "https://registry.npmjs.org/bmp-js/-/bmp-js-0.1.0.tgz",
+ "integrity": "sha1-4Fpj95amwf8l9Hcex62twUjAcjM=",
+ "license": "MIT"
+ },
+ "node_modules/body-parser": {
+ "version": "1.20.0",
+ "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.0.tgz",
+ "integrity": "sha512-DfJ+q6EPcGKZD1QWUjSpqp+Q7bDQTsQIF4zfUAtZ6qk+H/3/QRhg9CEp39ss+/T2vw0+HaidC0ecJj/DRLIaKg==",
+ "license": "MIT",
+ "dependencies": {
+ "bytes": "3.1.2",
+ "content-type": "~1.0.4",
+ "debug": "2.6.9",
+ "depd": "2.0.0",
+ "destroy": "1.2.0",
+ "http-errors": "2.0.0",
+ "iconv-lite": "0.4.24",
+ "on-finished": "2.4.1",
+ "qs": "6.10.3",
+ "raw-body": "2.5.1",
+ "type-is": "~1.6.18",
+ "unpipe": "1.0.0"
+ },
+ "engines": {
+ "node": ">= 0.8",
+ "npm": "1.2.8000 || >= 1.4.16"
+ }
+ },
+ "node_modules/brace-expansion": {
+ "version": "1.1.11",
+ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
+ "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
+ "license": "MIT",
+ "dependencies": {
+ "balanced-match": "^1.0.0",
+ "concat-map": "0.0.1"
+ }
+ },
+ "node_modules/bson": {
+ "version": "4.6.4",
+ "resolved": "https://registry.npmjs.org/bson/-/bson-4.6.4.tgz",
+ "integrity": "sha512-TdQ3FzguAu5HKPPlr0kYQCyrYUYh8tFM+CMTpxjNzVzxeiJY00Rtuj3LXLHSgiGvmaWlZ8PE+4KyM2thqE38pQ==",
+ "license": "Apache-2.0",
+ "dependencies": {
+ "buffer": "^5.6.0"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/buffer": {
+ "version": "5.7.1",
+ "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz",
+ "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==",
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/feross"
+ },
+ {
+ "type": "patreon",
+ "url": "https://www.patreon.com/feross"
+ },
+ {
+ "type": "consulting",
+ "url": "https://feross.org/support"
+ }
+ ],
+ "license": "MIT",
+ "dependencies": {
+ "base64-js": "^1.3.1",
+ "ieee754": "^1.1.13"
+ }
+ },
+ "node_modules/bytes": {
+ "version": "3.1.2",
+ "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz",
+ "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/call-bind": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz",
+ "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==",
+ "license": "MIT",
+ "dependencies": {
+ "function-bind": "^1.1.1",
+ "get-intrinsic": "^1.0.2"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/cli-color": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/cli-color/-/cli-color-2.0.1.tgz",
+ "integrity": "sha512-eBbxZF6fqPUNnf7CLAFOersUnyYzv83tHFLSlts+OAHsNendaqv2tHCq+/MO+b3Y+9JeoUlIvobyxG/Z8GNeOg==",
+ "license": "ISC",
+ "dependencies": {
+ "d": "^1.0.1",
+ "es5-ext": "^0.10.53",
+ "es6-iterator": "^2.0.3",
+ "memoizee": "^0.4.15",
+ "timers-ext": "^0.1.7"
+ },
+ "engines": {
+ "node": ">=0.10"
+ }
+ },
+ "node_modules/colors": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/colors/-/colors-1.4.0.tgz",
+ "integrity": "sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.1.90"
+ }
+ },
+ "node_modules/combined-stream": {
+ "version": "1.0.8",
+ "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
+ "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
+ "license": "MIT",
+ "dependencies": {
+ "delayed-stream": "~1.0.0"
+ },
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/commander": {
+ "version": "8.3.0",
+ "resolved": "https://registry.npmjs.org/commander/-/commander-8.3.0.tgz",
+ "integrity": "sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 12"
+ }
+ },
+ "node_modules/concat-map": {
+ "version": "0.0.1",
+ "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
+ "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=",
+ "license": "MIT"
+ },
+ "node_modules/content-disposition": {
+ "version": "0.5.4",
+ "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz",
+ "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==",
+ "license": "MIT",
+ "dependencies": {
+ "safe-buffer": "5.2.1"
+ },
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/content-type": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz",
+ "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/cookie": {
+ "version": "0.5.0",
+ "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz",
+ "integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/cookie-signature": {
+ "version": "1.0.6",
+ "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz",
+ "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=",
+ "license": "MIT"
+ },
+ "node_modules/d": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/d/-/d-1.0.1.tgz",
+ "integrity": "sha512-m62ShEObQ39CfralilEQRjH6oAMtNCV1xJyEx5LpRYUVN+EviphDgUc/F3hnYbADmkiNs67Y+3ylmlG7Lnu+FA==",
+ "license": "ISC",
+ "dependencies": {
+ "es5-ext": "^0.10.50",
+ "type": "^1.0.1"
+ }
+ },
+ "node_modules/debug": {
+ "version": "2.6.9",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
+ "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
+ "license": "MIT",
+ "dependencies": {
+ "ms": "2.0.0"
+ }
+ },
+ "node_modules/delayed-stream": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
+ "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=",
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.4.0"
+ }
+ },
+ "node_modules/denque": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/denque/-/denque-2.0.1.tgz",
+ "integrity": "sha512-tfiWc6BQLXNLpNiR5iGd0Ocu3P3VpxfzFiqubLgMfhfOw9WyvgJBd46CClNn9k3qfbjvT//0cf7AlYRX/OslMQ==",
+ "license": "Apache-2.0",
+ "engines": {
+ "node": ">=0.10"
+ }
+ },
+ "node_modules/depd": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz",
+ "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/destroy": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz",
+ "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.8",
+ "npm": "1.2.8000 || >= 1.4.16"
+ }
+ },
+ "node_modules/difflib": {
+ "version": "0.2.4",
+ "resolved": "https://registry.npmjs.org/difflib/-/difflib-0.2.4.tgz",
+ "integrity": "sha1-teMDYabbAjF21WKJLbhZQKcY9H4=",
+ "dependencies": {
+ "heap": ">= 0.2.0"
+ }
+ },
+ "node_modules/discord-api-types": {
+ "version": "0.26.1",
+ "resolved": "https://registry.npmjs.org/discord-api-types/-/discord-api-types-0.26.1.tgz",
+ "integrity": "sha512-T5PdMQ+Y1MEECYMV5wmyi9VEYPagEDEi4S0amgsszpWY0VB9JJ/hEvM6BgLhbdnKky4gfmZEXtEEtojN8ZKJQQ==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/discord.js": {
+ "version": "13.8.0",
+ "resolved": "https://registry.npmjs.org/discord.js/-/discord.js-13.8.0.tgz",
+ "integrity": "sha512-EPAA/2VLycYN5wSzavqa4iJ6qj3UtQFtHw5TH/60Fj29ymfEsCQVn//o1mTpwDxzwb+rPIrWhkxKIGGnjfv0Iw==",
+ "dependencies": {
+ "@discordjs/builders": "^0.14.0",
+ "@discordjs/collection": "^0.7.0",
+ "@sapphire/async-queue": "^1.3.1",
+ "@types/node-fetch": "^2.6.1",
+ "@types/ws": "^8.5.3",
+ "discord-api-types": "^0.33.3",
+ "form-data": "^4.0.0",
+ "node-fetch": "^2.6.1",
+ "ws": "^8.7.0"
+ },
+ "engines": {
+ "node": ">=16.6.0",
+ "npm": ">=7.0.0"
+ }
+ },
+ "node_modules/discord.js/node_modules/@discordjs/builders": {
+ "version": "0.14.0",
+ "resolved": "https://registry.npmjs.org/@discordjs/builders/-/builders-0.14.0.tgz",
+ "integrity": "sha512-+fqLIqa9wN3R+kvlld8sgG0nt04BAZxdCDP4t2qZ9TJsquLWA+xMtT8Waibb3d4li4AQS+IOfjiHAznv/dhHgQ==",
+ "dependencies": {
+ "@sapphire/shapeshift": "^3.1.0",
+ "@sindresorhus/is": "^4.6.0",
+ "discord-api-types": "^0.33.3",
+ "fast-deep-equal": "^3.1.3",
+ "ts-mixer": "^6.0.1",
+ "tslib": "^2.4.0"
+ },
+ "engines": {
+ "node": ">=16.9.0"
+ }
+ },
+ "node_modules/discord.js/node_modules/discord-api-types": {
+ "version": "0.33.5",
+ "resolved": "https://registry.npmjs.org/discord-api-types/-/discord-api-types-0.33.5.tgz",
+ "integrity": "sha512-dvO5M52v7m7Dy96+XUnzXNsQ/0npsYpU6dL205kAtEDueswoz3aU3bh1UMoK4cQmcGtB1YRyLKqp+DXi05lzFg=="
+ },
+ "node_modules/dreamopt": {
+ "version": "0.8.0",
+ "resolved": "https://registry.npmjs.org/dreamopt/-/dreamopt-0.8.0.tgz",
+ "integrity": "sha1-W8yAvnCX5F/EicNCQFq2gUCowdk=",
+ "dependencies": {
+ "wordwrap": ">=0.0.2"
+ },
+ "engines": {
+ "node": ">=0.4.0"
+ }
+ },
+ "node_modules/ee-first": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
+ "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=",
+ "license": "MIT"
+ },
+ "node_modules/encodeurl": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz",
+ "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/es5-ext": {
+ "version": "0.10.57",
+ "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.57.tgz",
+ "integrity": "sha512-L7cCNoPwTkAp7IBHxrKLsh7NKiVFkcdxlP9vbVw9QUvb7gF0Mz9bEBN0WY9xqdTjGF907EMT/iG013vnbqwu1Q==",
+ "hasInstallScript": true,
+ "license": "ISC",
+ "dependencies": {
+ "es6-iterator": "^2.0.3",
+ "es6-symbol": "^3.1.3",
+ "next-tick": "^1.1.0"
+ },
+ "engines": {
+ "node": ">=0.10"
+ }
+ },
+ "node_modules/es6-iterator": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/es6-iterator/-/es6-iterator-2.0.3.tgz",
+ "integrity": "sha1-p96IkUGgWpSwhUQDstCg+/qY87c=",
+ "license": "MIT",
+ "dependencies": {
+ "d": "1",
+ "es5-ext": "^0.10.35",
+ "es6-symbol": "^3.1.1"
+ }
+ },
+ "node_modules/es6-symbol": {
+ "version": "3.1.3",
+ "resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.3.tgz",
+ "integrity": "sha512-NJ6Yn3FuDinBaBRWl/q5X/s4koRHBrgKAu+yGI6JCBeiu3qrcbJhwT2GeR/EXVfylRk8dpQVJoLEFhK+Mu31NA==",
+ "license": "ISC",
+ "dependencies": {
+ "d": "^1.0.1",
+ "ext": "^1.1.2"
+ }
+ },
+ "node_modules/es6-weak-map": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/es6-weak-map/-/es6-weak-map-2.0.3.tgz",
+ "integrity": "sha512-p5um32HOTO1kP+w7PRnB+5lQ43Z6muuMuIMffvDN8ZB4GcnjLBV6zGStpbASIMk4DCAvEaamhe2zhyCb/QXXsA==",
+ "license": "ISC",
+ "dependencies": {
+ "d": "1",
+ "es5-ext": "^0.10.46",
+ "es6-iterator": "^2.0.3",
+ "es6-symbol": "^3.1.1"
+ }
+ },
+ "node_modules/escape-html": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz",
+ "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=",
+ "license": "MIT"
+ },
+ "node_modules/etag": {
+ "version": "1.8.1",
+ "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz",
+ "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/event-emitter": {
+ "version": "0.3.5",
+ "resolved": "https://registry.npmjs.org/event-emitter/-/event-emitter-0.3.5.tgz",
+ "integrity": "sha1-34xp7vFkeSPHFXuc6DhAYQsCzDk=",
+ "license": "MIT",
+ "dependencies": {
+ "d": "1",
+ "es5-ext": "~0.10.14"
+ }
+ },
+ "node_modules/express": {
+ "version": "4.18.1",
+ "resolved": "https://registry.npmjs.org/express/-/express-4.18.1.tgz",
+ "integrity": "sha512-zZBcOX9TfehHQhtupq57OF8lFZ3UZi08Y97dwFCkD8p9d/d2Y3M+ykKcwaMDEL+4qyUolgBDX6AblpR3fL212Q==",
+ "license": "MIT",
+ "dependencies": {
+ "accepts": "~1.3.8",
+ "array-flatten": "1.1.1",
+ "body-parser": "1.20.0",
+ "content-disposition": "0.5.4",
+ "content-type": "~1.0.4",
+ "cookie": "0.5.0",
+ "cookie-signature": "1.0.6",
+ "debug": "2.6.9",
+ "depd": "2.0.0",
+ "encodeurl": "~1.0.2",
+ "escape-html": "~1.0.3",
+ "etag": "~1.8.1",
+ "finalhandler": "1.2.0",
+ "fresh": "0.5.2",
+ "http-errors": "2.0.0",
+ "merge-descriptors": "1.0.1",
+ "methods": "~1.1.2",
+ "on-finished": "2.4.1",
+ "parseurl": "~1.3.3",
+ "path-to-regexp": "0.1.7",
+ "proxy-addr": "~2.0.7",
+ "qs": "6.10.3",
+ "range-parser": "~1.2.1",
+ "safe-buffer": "5.2.1",
+ "send": "0.18.0",
+ "serve-static": "1.15.0",
+ "setprototypeof": "1.2.0",
+ "statuses": "2.0.1",
+ "type-is": "~1.6.18",
+ "utils-merge": "1.0.1",
+ "vary": "~1.1.2"
+ },
+ "engines": {
+ "node": ">= 0.10.0"
+ }
+ },
+ "node_modules/ext": {
+ "version": "1.6.0",
+ "resolved": "https://registry.npmjs.org/ext/-/ext-1.6.0.tgz",
+ "integrity": "sha512-sdBImtzkq2HpkdRLtlLWDa6w4DX22ijZLKx8BMPUuKe1c5lbN6xwQDQCxSfxBQnHZ13ls/FH0MQZx/q/gr6FQg==",
+ "license": "ISC",
+ "dependencies": {
+ "type": "^2.5.0"
+ }
+ },
+ "node_modules/ext/node_modules/type": {
+ "version": "2.6.0",
+ "resolved": "https://registry.npmjs.org/type/-/type-2.6.0.tgz",
+ "integrity": "sha512-eiDBDOmkih5pMbo9OqsqPRGMljLodLcwd5XD5JbtNB0o89xZAwynY9EdCDsJU7LtcVCClu9DvM7/0Ep1hYX3EQ==",
+ "license": "ISC"
+ },
+ "node_modules/fast-deep-equal": {
+ "version": "3.1.3",
+ "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
+ "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q=="
+ },
+ "node_modules/file-type": {
+ "version": "12.4.2",
+ "resolved": "https://registry.npmjs.org/file-type/-/file-type-12.4.2.tgz",
+ "integrity": "sha512-UssQP5ZgIOKelfsaB5CuGAL+Y+q7EmONuiwF3N5HAH0t27rvrttgi6Ra9k/+DVaY9UF6+ybxu5pOXLUdA8N7Vg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/finalhandler": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz",
+ "integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==",
+ "license": "MIT",
+ "dependencies": {
+ "debug": "2.6.9",
+ "encodeurl": "~1.0.2",
+ "escape-html": "~1.0.3",
+ "on-finished": "2.4.1",
+ "parseurl": "~1.3.3",
+ "statuses": "2.0.1",
+ "unpipe": "~1.0.0"
+ },
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "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==",
+ "license": "MIT",
+ "dependencies": {
+ "asynckit": "^0.4.0",
+ "combined-stream": "^1.0.8",
+ "mime-types": "^2.1.12"
+ },
+ "engines": {
+ "node": ">= 6"
+ }
+ },
+ "node_modules/forwarded": {
+ "version": "0.2.0",
+ "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz",
+ "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/fresh": {
+ "version": "0.5.2",
+ "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz",
+ "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.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=",
+ "license": "ISC"
+ },
+ "node_modules/function-bind": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz",
+ "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==",
+ "license": "MIT"
+ },
+ "node_modules/get-intrinsic": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.1.tgz",
+ "integrity": "sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q==",
+ "license": "MIT",
+ "dependencies": {
+ "function-bind": "^1.1.1",
+ "has": "^1.0.3",
+ "has-symbols": "^1.0.1"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/glob": {
+ "version": "5.0.15",
+ "resolved": "https://registry.npmjs.org/glob/-/glob-5.0.15.tgz",
+ "integrity": "sha1-G8k2ueAvSmA/zCIuz3Yz0wuLk7E=",
+ "license": "ISC",
+ "dependencies": {
+ "inflight": "^1.0.4",
+ "inherits": "2",
+ "minimatch": "2 || 3",
+ "once": "^1.3.0",
+ "path-is-absolute": "^1.0.0"
+ },
+ "engines": {
+ "node": "*"
+ }
+ },
+ "node_modules/has": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz",
+ "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==",
+ "license": "MIT",
+ "dependencies": {
+ "function-bind": "^1.1.1"
+ },
+ "engines": {
+ "node": ">= 0.4.0"
+ }
+ },
+ "node_modules/has-symbols": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz",
+ "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/heap": {
+ "version": "0.2.7",
+ "resolved": "https://registry.npmjs.org/heap/-/heap-0.2.7.tgz",
+ "integrity": "sha512-2bsegYkkHO+h/9MGbn6KWcE45cHZgPANo5LXF7EvWdT0yT2EguSVO1nDgU5c8+ZOPwp2vMNa7YFsJhVcDR9Sdg==",
+ "license": "MIT"
+ },
+ "node_modules/http-errors": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz",
+ "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==",
+ "license": "MIT",
+ "dependencies": {
+ "depd": "2.0.0",
+ "inherits": "2.0.4",
+ "setprototypeof": "1.2.0",
+ "statuses": "2.0.1",
+ "toidentifier": "1.0.1"
+ },
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/humanize": {
+ "version": "0.0.9",
+ "resolved": "https://registry.npmjs.org/humanize/-/humanize-0.0.9.tgz",
+ "integrity": "sha1-GZT/rs3+nEQe0r2sdFK3u0yeQaQ=",
+ "engines": {
+ "node": "*"
+ }
+ },
+ "node_modules/humanize-duration": {
+ "version": "3.27.1",
+ "resolved": "https://registry.npmjs.org/humanize-duration/-/humanize-duration-3.27.1.tgz",
+ "integrity": "sha512-jCVkMl+EaM80rrMrAPl96SGG4NRac53UyI1o/yAzebDntEY6K6/Fj2HOjdPg8omTqIe5Y0wPBai2q5xXrIbarA==",
+ "license": "Unlicense"
+ },
+ "node_modules/iconv-lite": {
+ "version": "0.4.24",
+ "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
+ "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==",
+ "license": "MIT",
+ "dependencies": {
+ "safer-buffer": ">= 2.1.2 < 3"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/idb-keyval": {
+ "version": "3.2.0",
+ "resolved": "https://registry.npmjs.org/idb-keyval/-/idb-keyval-3.2.0.tgz",
+ "integrity": "sha512-slx8Q6oywCCSfKgPgL0sEsXtPVnSbTLWpyiDcu6msHOyKOLari1TD1qocXVCft80umnkk3/Qqh3lwoFt8T/BPQ==",
+ "license": "Apache-2.0"
+ },
+ "node_modules/ieee754": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz",
+ "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==",
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/feross"
+ },
+ {
+ "type": "patreon",
+ "url": "https://www.patreon.com/feross"
+ },
+ {
+ "type": "consulting",
+ "url": "https://feross.org/support"
+ }
+ ],
+ "license": "BSD-3-Clause"
+ },
+ "node_modules/inflight": {
+ "version": "1.0.6",
+ "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
+ "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=",
+ "license": "ISC",
+ "dependencies": {
+ "once": "^1.3.0",
+ "wrappy": "1"
+ }
+ },
+ "node_modules/inherits": {
+ "version": "2.0.4",
+ "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
+ "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
+ "license": "ISC"
+ },
+ "node_modules/ip": {
+ "version": "1.1.8",
+ "resolved": "https://registry.npmjs.org/ip/-/ip-1.1.8.tgz",
+ "integrity": "sha512-PuExPYUiu6qMBQb4l06ecm6T6ujzhmh+MeJcW9wa89PoAz5pvd4zPgN5WJV104mb6S2T1AwNIAaB70JNrLQWhg==",
+ "license": "MIT"
+ },
+ "node_modules/ipaddr.js": {
+ "version": "1.9.1",
+ "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz",
+ "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.10"
+ }
+ },
+ "node_modules/is-electron": {
+ "version": "2.2.1",
+ "resolved": "https://registry.npmjs.org/is-electron/-/is-electron-2.2.1.tgz",
+ "integrity": "sha512-r8EEQQsqT+Gn0aXFx7lTFygYQhILLCB+wn0WCDL5LZRINeLH/Rvw1j2oKodELLXYNImQ3CRlVsY8wW4cGOsyuw==",
+ "license": "MIT"
+ },
+ "node_modules/is-promise": {
+ "version": "2.2.2",
+ "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.2.2.tgz",
+ "integrity": "sha512-+lP4/6lKUBfQjZ2pdxThZvLUAafmZb8OAxFb8XXtiQmS35INgr85hdOGoEs124ez1FCnZJt6jau/T+alh58QFQ==",
+ "license": "MIT"
+ },
+ "node_modules/is-url": {
+ "version": "1.2.4",
+ "resolved": "https://registry.npmjs.org/is-url/-/is-url-1.2.4.tgz",
+ "integrity": "sha512-ITvGim8FhRiYe4IQ5uHSkj7pVaPDrCTkNd3yq3cV7iZAcJdHTUMPMEHcqSOy9xZ9qFenQCvi+2wjH9a1nXqHww==",
+ "license": "MIT"
+ },
+ "node_modules/jpeg-autorotate": {
+ "version": "7.1.1",
+ "resolved": "https://registry.npmjs.org/jpeg-autorotate/-/jpeg-autorotate-7.1.1.tgz",
+ "integrity": "sha512-ewTZTG/QWOM0D5h/yKcQ3QgyrnQYsr3qmcS+bqoAwgQAY1KBa31aJ+q+FlElaxo/rSYqfF1ixf+8EIgluBkgTg==",
+ "license": "MIT",
+ "dependencies": {
+ "colors": "^1.4.0",
+ "glob": "^7.1.6",
+ "jpeg-js": "^0.4.2",
+ "piexifjs": "^1.0.6",
+ "yargs-parser": "^20.2.1"
+ },
+ "bin": {
+ "jpeg-autorotate": "src/cli.js"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/jpeg-autorotate/node_modules/glob": {
+ "version": "7.2.0",
+ "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz",
+ "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==",
+ "license": "ISC",
+ "dependencies": {
+ "fs.realpath": "^1.0.0",
+ "inflight": "^1.0.4",
+ "inherits": "2",
+ "minimatch": "^3.0.4",
+ "once": "^1.3.0",
+ "path-is-absolute": "^1.0.0"
+ },
+ "engines": {
+ "node": "*"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/isaacs"
+ }
+ },
+ "node_modules/jpeg-js": {
+ "version": "0.4.3",
+ "resolved": "https://registry.npmjs.org/jpeg-js/-/jpeg-js-0.4.3.tgz",
+ "integrity": "sha512-ru1HWKek8octvUHFHvE5ZzQ1yAsJmIvRdGWvSoKV52XKyuyYA437QWDttXT8eZXDSbuMpHlLzPDZUPd6idIz+Q==",
+ "license": "BSD-3-Clause"
+ },
+ "node_modules/jshaiku": {
+ "resolved": "../haiku",
+ "link": true
+ },
+ "node_modules/json-diff": {
+ "version": "0.7.3",
+ "resolved": "https://registry.npmjs.org/json-diff/-/json-diff-0.7.3.tgz",
+ "integrity": "sha512-VBvNBt3cIrCBHa3gYbVsCFUEReqWZPf+Biq1ZtFdIiQ6rytRLDp3qvtrGv7z/iZDd1D4vXWpW7Nx1nP8muLzkg==",
+ "license": "MIT",
+ "dependencies": {
+ "cli-color": "^2.0.0",
+ "difflib": "~0.2.1",
+ "dreamopt": "~0.8.0"
+ },
+ "bin": {
+ "json-diff": "bin/json-diff.js"
+ },
+ "engines": {
+ "node": "*"
+ }
+ },
+ "node_modules/lru-queue": {
+ "version": "0.1.0",
+ "resolved": "https://registry.npmjs.org/lru-queue/-/lru-queue-0.1.0.tgz",
+ "integrity": "sha1-Jzi9nw089PhEkMVzbEhpmsYyzaM=",
+ "license": "MIT",
+ "dependencies": {
+ "es5-ext": "~0.10.2"
+ }
+ },
+ "node_modules/media-typer": {
+ "version": "0.3.0",
+ "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz",
+ "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/memoizee": {
+ "version": "0.4.15",
+ "resolved": "https://registry.npmjs.org/memoizee/-/memoizee-0.4.15.tgz",
+ "integrity": "sha512-UBWmJpLZd5STPm7PMUlOw/TSy972M+z8gcyQ5veOnSDRREz/0bmpyTfKt3/51DhEBqCZQn1udM/5flcSPYhkdQ==",
+ "license": "ISC",
+ "dependencies": {
+ "d": "^1.0.1",
+ "es5-ext": "^0.10.53",
+ "es6-weak-map": "^2.0.3",
+ "event-emitter": "^0.3.5",
+ "is-promise": "^2.2.2",
+ "lru-queue": "^0.1.0",
+ "next-tick": "^1.1.0",
+ "timers-ext": "^0.1.7"
+ }
+ },
+ "node_modules/memory-pager": {
+ "version": "1.5.0",
+ "resolved": "https://registry.npmjs.org/memory-pager/-/memory-pager-1.5.0.tgz",
+ "integrity": "sha512-ZS4Bp4r/Zoeq6+NLJpP+0Zzm0pR8whtGPf1XExKLJBAczGMnSi3It14OiNCStjQjM6NU1okjQGSxgEZN8eBYKg==",
+ "license": "MIT",
+ "optional": true
+ },
+ "node_modules/merge-descriptors": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz",
+ "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=",
+ "license": "MIT"
+ },
+ "node_modules/methods": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz",
+ "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/mime": {
+ "version": "1.6.0",
+ "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz",
+ "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==",
+ "license": "MIT",
+ "bin": {
+ "mime": "cli.js"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/mime-db": {
+ "version": "1.51.0",
+ "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.51.0.tgz",
+ "integrity": "sha512-5y8A56jg7XVQx2mbv1lu49NR4dokRnhZYTtL+KGfaa27uq4pSTXkwQkFJl4pkRMyNFz/EtYDSkiiEHx3F7UN6g==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/mime-types": {
+ "version": "2.1.34",
+ "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.34.tgz",
+ "integrity": "sha512-6cP692WwGIs9XXdOO4++N+7qjqv0rqxxVvJ3VHPh/Sc9mVZcQP+ZGhkKiTvWMQRr2tbHkJP/Yn7Y0npb3ZBs4A==",
+ "license": "MIT",
+ "dependencies": {
+ "mime-db": "1.51.0"
+ },
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/minimatch": {
+ "version": "3.1.2",
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
+ "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
+ "license": "ISC",
+ "dependencies": {
+ "brace-expansion": "^1.1.7"
+ },
+ "engines": {
+ "node": "*"
+ }
+ },
+ "node_modules/mongodb": {
+ "version": "4.7.0",
+ "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-4.7.0.tgz",
+ "integrity": "sha512-HhVar6hsUeMAVlIbwQwWtV36iyjKd9qdhY+s4wcU8K6TOj4Q331iiMy+FoPuxEntDIijTYWivwFJkLv8q/ZgvA==",
+ "license": "Apache-2.0",
+ "dependencies": {
+ "bson": "^4.6.3",
+ "denque": "^2.0.1",
+ "mongodb-connection-string-url": "^2.5.2",
+ "socks": "^2.6.2"
+ },
+ "engines": {
+ "node": ">=12.9.0"
+ },
+ "optionalDependencies": {
+ "saslprep": "^1.0.3"
+ }
+ },
+ "node_modules/mongodb-connection-string-url": {
+ "version": "2.5.2",
+ "resolved": "https://registry.npmjs.org/mongodb-connection-string-url/-/mongodb-connection-string-url-2.5.2.tgz",
+ "integrity": "sha512-tWDyIG8cQlI5k3skB6ywaEA5F9f5OntrKKsT/Lteub2zgwSUlhqEN2inGgBTm8bpYJf8QYBdA/5naz65XDpczA==",
+ "license": "Apache-2.0",
+ "dependencies": {
+ "@types/whatwg-url": "^8.2.1",
+ "whatwg-url": "^11.0.0"
+ }
+ },
+ "node_modules/ms": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+ "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=",
+ "license": "MIT"
+ },
+ "node_modules/negotiator": {
+ "version": "0.6.3",
+ "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz",
+ "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/next-tick": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/next-tick/-/next-tick-1.1.0.tgz",
+ "integrity": "sha512-CXdUiJembsNjuToQvxayPZF9Vqht7hewsvy2sOWafLvi2awflj9mOC6bHIg50orX8IJvWKY9wYQ/zB2kogPslQ==",
+ "license": "ISC"
+ },
+ "node_modules/node-fetch": {
+ "version": "2.6.7",
+ "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz",
+ "integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==",
+ "license": "MIT",
+ "dependencies": {
+ "whatwg-url": "^5.0.0"
+ },
+ "engines": {
+ "node": "4.x || >=6.0.0"
+ },
+ "peerDependencies": {
+ "encoding": "^0.1.0"
+ },
+ "peerDependenciesMeta": {
+ "encoding": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/node-fetch/node_modules/tr46": {
+ "version": "0.0.3",
+ "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz",
+ "integrity": "sha1-gYT9NH2snNwYWZLzpmIuFLnZq2o=",
+ "license": "MIT"
+ },
+ "node_modules/node-fetch/node_modules/whatwg-url": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz",
+ "integrity": "sha1-lmRU6HZUYuN2RNNib2dCzotwll0=",
+ "license": "MIT",
+ "dependencies": {
+ "tr46": "~0.0.3",
+ "webidl-conversions": "^3.0.0"
+ }
+ },
+ "node_modules/node-tesseract": {
+ "version": "0.2.7",
+ "resolved": "https://registry.npmjs.org/node-tesseract/-/node-tesseract-0.2.7.tgz",
+ "integrity": "sha1-yPAvuDUaQnByc1d4wFGYI/JgG4Q=",
+ "license": "MIT",
+ "dependencies": {
+ "glob": "^5.0.10",
+ "node-uuid": "^1.4.1"
+ }
+ },
+ "node_modules/node-uuid": {
+ "version": "1.4.8",
+ "resolved": "https://registry.npmjs.org/node-uuid/-/node-uuid-1.4.8.tgz",
+ "integrity": "sha1-sEDrCSOWivq/jTL7HxfxFn/auQc=",
+ "bin": {
+ "uuid": "bin/uuid"
+ }
+ },
+ "node_modules/object-inspect": {
+ "version": "1.12.0",
+ "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.0.tgz",
+ "integrity": "sha512-Ho2z80bVIvJloH+YzRmpZVQe87+qASmBUKZDWgx9cu+KDrX2ZDH/3tMy+gXbZETVGs2M8YdxObOh7XAtim9Y0g==",
+ "license": "MIT",
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/on-finished": {
+ "version": "2.4.1",
+ "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz",
+ "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==",
+ "license": "MIT",
+ "dependencies": {
+ "ee-first": "1.1.1"
+ },
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/once": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
+ "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=",
+ "license": "ISC",
+ "dependencies": {
+ "wrappy": "1"
+ }
+ },
+ "node_modules/opencollective-postinstall": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/opencollective-postinstall/-/opencollective-postinstall-2.0.3.tgz",
+ "integrity": "sha512-8AV/sCtuzUeTo8gQK5qDZzARrulB3egtLzFgteqB2tcT4Mw7B8Kt7JcDHmltjz6FOAHsvTevk70gZEbhM4ZS9Q==",
+ "license": "MIT",
+ "bin": {
+ "opencollective-postinstall": "index.js"
+ }
+ },
+ "node_modules/parseurl": {
+ "version": "1.3.3",
+ "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz",
+ "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/path-is-absolute": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
+ "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=",
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/path-to-regexp": {
+ "version": "0.1.7",
+ "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz",
+ "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=",
+ "license": "MIT"
+ },
+ "node_modules/piexifjs": {
+ "version": "1.0.6",
+ "resolved": "https://registry.npmjs.org/piexifjs/-/piexifjs-1.0.6.tgz",
+ "integrity": "sha512-0wVyH0cKohzBQ5Gi2V1BuxYpxWfxF3cSqfFXfPIpl5tl9XLS5z4ogqhUCD20AbHi0h9aJkqXNJnkVev6gwh2ag==",
+ "license": "MIT"
+ },
+ "node_modules/proxy-addr": {
+ "version": "2.0.7",
+ "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz",
+ "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==",
+ "license": "MIT",
+ "dependencies": {
+ "forwarded": "0.2.0",
+ "ipaddr.js": "1.9.1"
+ },
+ "engines": {
+ "node": ">= 0.10"
+ }
+ },
+ "node_modules/punycode": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz",
+ "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/qs": {
+ "version": "6.10.3",
+ "resolved": "https://registry.npmjs.org/qs/-/qs-6.10.3.tgz",
+ "integrity": "sha512-wr7M2E0OFRfIfJZjKGieI8lBKb7fRCH4Fv5KNPEs7gJ8jadvotdsS08PzOKR7opXhZ/Xkjtt3WF9g38drmyRqQ==",
+ "license": "BSD-3-Clause",
+ "dependencies": {
+ "side-channel": "^1.0.4"
+ },
+ "engines": {
+ "node": ">=0.6"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/range-parser": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz",
+ "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/raw-body": {
+ "version": "2.5.1",
+ "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.1.tgz",
+ "integrity": "sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==",
+ "license": "MIT",
+ "dependencies": {
+ "bytes": "3.1.2",
+ "http-errors": "2.0.0",
+ "iconv-lite": "0.4.24",
+ "unpipe": "1.0.0"
+ },
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/regenerator-runtime": {
+ "version": "0.13.9",
+ "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz",
+ "integrity": "sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA==",
+ "license": "MIT"
+ },
+ "node_modules/resolve-url": {
+ "version": "0.2.1",
+ "resolved": "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz",
+ "integrity": "sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo=",
+ "license": "MIT"
+ },
+ "node_modules/safe-buffer": {
+ "version": "5.2.1",
+ "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
+ "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==",
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/feross"
+ },
+ {
+ "type": "patreon",
+ "url": "https://www.patreon.com/feross"
+ },
+ {
+ "type": "consulting",
+ "url": "https://feross.org/support"
+ }
+ ],
+ "license": "MIT"
+ },
+ "node_modules/safer-buffer": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
+ "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==",
+ "license": "MIT"
+ },
+ "node_modules/saslprep": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/saslprep/-/saslprep-1.0.3.tgz",
+ "integrity": "sha512-/MY/PEMbk2SuY5sScONwhUDsV2p77Znkb/q3nSVstq/yQzYJOH/Azh29p9oJLsl3LnQwSvZDKagDGBsBwSooag==",
+ "license": "MIT",
+ "optional": true,
+ "dependencies": {
+ "sparse-bitfield": "^3.0.3"
+ },
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/send": {
+ "version": "0.18.0",
+ "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz",
+ "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==",
+ "license": "MIT",
+ "dependencies": {
+ "debug": "2.6.9",
+ "depd": "2.0.0",
+ "destroy": "1.2.0",
+ "encodeurl": "~1.0.2",
+ "escape-html": "~1.0.3",
+ "etag": "~1.8.1",
+ "fresh": "0.5.2",
+ "http-errors": "2.0.0",
+ "mime": "1.6.0",
+ "ms": "2.1.3",
+ "on-finished": "2.4.1",
+ "range-parser": "~1.2.1",
+ "statuses": "2.0.1"
+ },
+ "engines": {
+ "node": ">= 0.8.0"
+ }
+ },
+ "node_modules/send/node_modules/ms": {
+ "version": "2.1.3",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
+ "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
+ "license": "MIT"
+ },
+ "node_modules/serve-static": {
+ "version": "1.15.0",
+ "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz",
+ "integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==",
+ "license": "MIT",
+ "dependencies": {
+ "encodeurl": "~1.0.2",
+ "escape-html": "~1.0.3",
+ "parseurl": "~1.3.3",
+ "send": "0.18.0"
+ },
+ "engines": {
+ "node": ">= 0.8.0"
+ }
+ },
+ "node_modules/setprototypeof": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz",
+ "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==",
+ "license": "ISC"
+ },
+ "node_modules/side-channel": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz",
+ "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==",
+ "license": "MIT",
+ "dependencies": {
+ "call-bind": "^1.0.0",
+ "get-intrinsic": "^1.0.2",
+ "object-inspect": "^1.9.0"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/smart-buffer": {
+ "version": "4.2.0",
+ "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz",
+ "integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 6.0.0",
+ "npm": ">= 3.0.0"
+ }
+ },
+ "node_modules/socks": {
+ "version": "2.6.2",
+ "resolved": "https://registry.npmjs.org/socks/-/socks-2.6.2.tgz",
+ "integrity": "sha512-zDZhHhZRY9PxRruRMR7kMhnf3I8hDs4S3f9RecfnGxvcBHQcKcIH/oUcEWffsfl1XxdYlA7nnlGbbTvPz9D8gA==",
+ "license": "MIT",
+ "dependencies": {
+ "ip": "^1.1.5",
+ "smart-buffer": "^4.2.0"
+ },
+ "engines": {
+ "node": ">= 10.13.0",
+ "npm": ">= 3.0.0"
+ }
+ },
+ "node_modules/sparse-bitfield": {
+ "version": "3.0.3",
+ "resolved": "https://registry.npmjs.org/sparse-bitfield/-/sparse-bitfield-3.0.3.tgz",
+ "integrity": "sha512-kvzhi7vqKTfkh0PZU+2D2PIllw2ymqJKujUcyPMd9Y75Nv4nPbGJZXNhxsgdQab2BmlDct1YnfQCguEvHr7VsQ==",
+ "license": "MIT",
+ "optional": true,
+ "dependencies": {
+ "memory-pager": "^1.0.2"
+ }
+ },
+ "node_modules/statuses": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz",
+ "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/structured-clone": {
+ "version": "0.2.2",
+ "resolved": "https://registry.npmjs.org/structured-clone/-/structured-clone-0.2.2.tgz",
+ "integrity": "sha1-rJK2vjGVimQ9sw8TNavGobAt/cI=",
+ "license": "MIT"
+ },
+ "node_modules/tesseract.js": {
+ "version": "2.1.5",
+ "resolved": "https://registry.npmjs.org/tesseract.js/-/tesseract.js-2.1.5.tgz",
+ "integrity": "sha512-7CIS3SWr7TXpeaH9+HS7iUtVbCfPFYOO3p6rkRAkdtsOtrbz6496x59na6SCbFAIaZulQxy8BjwSu3qL3AoDRg==",
+ "hasInstallScript": true,
+ "license": "Apache-2.0",
+ "dependencies": {
+ "blueimp-load-image": "^3.0.0",
+ "bmp-js": "^0.1.0",
+ "file-type": "^12.4.1",
+ "idb-keyval": "^3.2.0",
+ "is-electron": "^2.2.0",
+ "is-url": "^1.2.4",
+ "jpeg-autorotate": "^7.1.1",
+ "node-fetch": "^2.6.0",
+ "opencollective-postinstall": "^2.0.2",
+ "regenerator-runtime": "^0.13.3",
+ "resolve-url": "^0.2.1",
+ "tesseract.js-core": "^2.2.0",
+ "zlibjs": "^0.3.1"
+ }
+ },
+ "node_modules/tesseract.js-core": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/tesseract.js-core/-/tesseract.js-core-2.2.0.tgz",
+ "integrity": "sha512-a8L+OJTbUipBsEDsJhDPlnLB0TY1MkTZqw5dqUwmiDSjUzwvU7HWLg/2+WDRulKUi4LE+7PnHlaBlW0k+V0U0w==",
+ "license": "Apache License 2.0"
+ },
+ "node_modules/timers-ext": {
+ "version": "0.1.7",
+ "resolved": "https://registry.npmjs.org/timers-ext/-/timers-ext-0.1.7.tgz",
+ "integrity": "sha512-b85NUNzTSdodShTIbky6ZF02e8STtVVfD+fu4aXXShEELpozH+bCpJLYMPZbsABN2wDH7fJpqIoXxJpzbf0NqQ==",
+ "license": "ISC",
+ "dependencies": {
+ "es5-ext": "~0.10.46",
+ "next-tick": "1"
+ }
+ },
+ "node_modules/toidentifier": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz",
+ "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.6"
+ }
+ },
+ "node_modules/tr46": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/tr46/-/tr46-3.0.0.tgz",
+ "integrity": "sha512-l7FvfAHlcmulp8kr+flpQZmVwtu7nfRV7NZujtN0OqES8EL4O4e0qqzL0DC5gAvx/ZC/9lk6rhcUwYvkBnBnYA==",
+ "license": "MIT",
+ "dependencies": {
+ "punycode": "^2.1.1"
+ },
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/ts-mixer": {
+ "version": "6.0.1",
+ "resolved": "https://registry.npmjs.org/ts-mixer/-/ts-mixer-6.0.1.tgz",
+ "integrity": "sha512-hvE+ZYXuINrx6Ei6D6hz+PTim0Uf++dYbK9FFifLNwQj+RwKquhQpn868yZsCtJYiclZF1u8l6WZxxKi+vv7Rg=="
+ },
+ "node_modules/tslib": {
+ "version": "2.4.0",
+ "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz",
+ "integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ=="
+ },
+ "node_modules/type": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/type/-/type-1.2.0.tgz",
+ "integrity": "sha512-+5nt5AAniqsCnu2cEQQdpzCAh33kVx8n0VoFidKpB1dVVLAN/F+bgVOqOJqOnEnrhp222clB5p3vUlD+1QAnfg==",
+ "license": "ISC"
+ },
+ "node_modules/type-is": {
+ "version": "1.6.18",
+ "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz",
+ "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==",
+ "license": "MIT",
+ "dependencies": {
+ "media-typer": "0.3.0",
+ "mime-types": "~2.1.24"
+ },
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/typescript": {
+ "version": "4.6.2",
+ "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.6.2.tgz",
+ "integrity": "sha512-HM/hFigTBHZhLXshn9sN37H085+hQGeJHJ/X7LpBWLID/fbc2acUMfU+lGD98X81sKP+pFa9f0DZmCwB9GnbAg==",
+ "license": "Apache-2.0",
+ "bin": {
+ "tsc": "bin/tsc",
+ "tsserver": "bin/tsserver"
+ },
+ "engines": {
+ "node": ">=4.2.0"
+ }
+ },
+ "node_modules/unpipe": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz",
+ "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/unscan": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/unscan/-/unscan-1.1.2.tgz",
+ "integrity": "sha512-a5RcGaBFMO9l78QWKffeWUo2cvfqUv05JCXuphE8MFOA92qyqp1Da7isnR+zjJspi45+yS8tTSuhd0vV3asWdA==",
+ "license": "MIT",
+ "dependencies": {
+ "commander": "^8.3.0",
+ "form-data": "^4.0.0",
+ "node-fetch": "^2.6.5"
+ },
+ "bin": {
+ "unscan": "bin/unscan.js"
+ }
+ },
+ "node_modules/utils-merge": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz",
+ "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.4.0"
+ }
+ },
+ "node_modules/vary": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz",
+ "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/webidl-conversions": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz",
+ "integrity": "sha1-JFNCdeKnvGvnvIZhHMFq4KVlSHE=",
+ "license": "BSD-2-Clause"
+ },
+ "node_modules/whatwg-url": {
+ "version": "11.0.0",
+ "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-11.0.0.tgz",
+ "integrity": "sha512-RKT8HExMpoYx4igMiVMY83lN6UeITKJlBQ+vR/8ZJ8OCdSiN3RwCq+9gH0+Xzj0+5IrM6i4j/6LuvzbZIQgEcQ==",
+ "license": "MIT",
+ "dependencies": {
+ "tr46": "^3.0.0",
+ "webidl-conversions": "^7.0.0"
+ },
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/whatwg-url/node_modules/webidl-conversions": {
+ "version": "7.0.0",
+ "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz",
+ "integrity": "sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==",
+ "license": "BSD-2-Clause",
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/wordwrap": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz",
+ "integrity": "sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus=",
+ "license": "MIT"
+ },
+ "node_modules/wrappy": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
+ "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=",
+ "license": "ISC"
+ },
+ "node_modules/ws": {
+ "version": "8.8.0",
+ "resolved": "https://registry.npmjs.org/ws/-/ws-8.8.0.tgz",
+ "integrity": "sha512-JDAgSYQ1ksuwqfChJusw1LSJ8BizJ2e/vVu5Lxjq3YvNJNlROv1ui4i+c/kUUrPheBvQl4c5UbERhTwKa6QBJQ==",
+ "engines": {
+ "node": ">=10.0.0"
+ },
+ "peerDependencies": {
+ "bufferutil": "^4.0.1",
+ "utf-8-validate": "^5.0.2"
+ },
+ "peerDependenciesMeta": {
+ "bufferutil": {
+ "optional": true
+ },
+ "utf-8-validate": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/yargs-parser": {
+ "version": "20.2.9",
+ "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz",
+ "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==",
+ "license": "ISC",
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/zlibjs": {
+ "version": "0.3.1",
+ "resolved": "https://registry.npmjs.org/zlibjs/-/zlibjs-0.3.1.tgz",
+ "integrity": "sha1-UBl+2yihxCymWcyLTmqd3W1ERVQ=",
+ "license": "MIT",
+ "engines": {
+ "node": "*"
+ }
+ },
+ "node_modules/zod": {
+ "version": "3.13.4",
+ "resolved": "https://registry.npmjs.org/zod/-/zod-3.13.4.tgz",
+ "integrity": "sha512-LZRucWt4j/ru5azOkJxCfpR87IyFDn8h2UODdqvXzZLb3K7bb9chUrUIGTy3BPsr8XnbQYfQ5Md5Hu2OYIo1mg==",
+ "license": "MIT",
+ "funding": {
+ "url": "https://github.com/sponsors/colinhacks"
+ }
+ }
+ },
+ "dependencies": {
+ "@discordjs/builders": {
+ "version": "0.12.0",
+ "resolved": "https://registry.npmjs.org/@discordjs/builders/-/builders-0.12.0.tgz",
+ "integrity": "sha512-Vx2MjUZd6QVo1uS2uWt708Fd6cHWGFblAvbpL5EBO+kLl0BADmPwwvts+YJ/VfSywed6Vsk6K2cEooR/Ytjhjw==",
+ "requires": {
+ "@sindresorhus/is": "^4.3.0",
+ "discord-api-types": "^0.26.1",
+ "ts-mixer": "^6.0.0",
+ "tslib": "^2.3.1",
+ "zod": "^3.11.6"
+ }
+ },
+ "@discordjs/collection": {
+ "version": "0.7.0",
+ "resolved": "https://registry.npmjs.org/@discordjs/collection/-/collection-0.7.0.tgz",
+ "integrity": "sha512-R5i8Wb8kIcBAFEPLLf7LVBQKBDYUL+ekb23sOgpkpyGT+V4P7V83wTxcsqmX+PbqHt4cEHn053uMWfRqh/Z/nA=="
+ },
+ "@sapphire/async-queue": {
+ "version": "1.3.1",
+ "resolved": "https://registry.npmjs.org/@sapphire/async-queue/-/async-queue-1.3.1.tgz",
+ "integrity": "sha512-FFTlPOWZX1kDj9xCAsRzH5xEJfawg1lNoYAA+ecOWJMHOfiZYb1uXOI3ne9U4UILSEPwfE68p3T9wUHwIQfR0g=="
+ },
+ "@sapphire/shapeshift": {
+ "version": "3.2.0",
+ "resolved": "https://registry.npmjs.org/@sapphire/shapeshift/-/shapeshift-3.2.0.tgz",
+ "integrity": "sha512-asNgE5Ooil2/oGIAj6vZMoUc2ZFED0TGYD7jwvZsjHPQZBEh9ITj94ca4bCgiCR1s2ER/UjzykH+5wE3ebVZnQ=="
+ },
+ "@sindresorhus/is": {
+ "version": "4.6.0",
+ "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-4.6.0.tgz",
+ "integrity": "sha512-t09vSN3MdfsyCHoFcTRCH/iUtG7OJ0CsjzB8cjAmKc/va/kIgeDI/TxsigdncE/4be734m0cvIYwNaV4i2XqAw=="
+ },
+ "@types/node": {
+ "version": "17.0.21",
+ "resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.21.tgz",
+ "integrity": "sha512-DBZCJbhII3r90XbQxI8Y9IjjiiOGlZ0Hr32omXIZvwwZ7p4DMMXGrKXVyPfuoBOri9XNtL0UK69jYIBIsRX3QQ=="
+ },
+ "@types/node-fetch": {
+ "version": "2.6.1",
+ "resolved": "https://registry.npmjs.org/@types/node-fetch/-/node-fetch-2.6.1.tgz",
+ "integrity": "sha512-oMqjURCaxoSIsHSr1E47QHzbmzNR5rK8McHuNb11BOM9cHcIK3Avy0s/b2JlXHoQGTYS3NsvWzV1M0iK7l0wbA==",
+ "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==",
+ "requires": {
+ "asynckit": "^0.4.0",
+ "combined-stream": "^1.0.8",
+ "mime-types": "^2.1.12"
+ }
+ }
+ }
+ },
+ "@types/webidl-conversions": {
+ "version": "6.1.1",
+ "resolved": "https://registry.npmjs.org/@types/webidl-conversions/-/webidl-conversions-6.1.1.tgz",
+ "integrity": "sha512-XAahCdThVuCFDQLT7R7Pk/vqeObFNL3YqRyFZg+AqAP/W1/w3xHaIxuW7WszQqTbIBOPRcItYJIou3i/mppu3Q=="
+ },
+ "@types/whatwg-url": {
+ "version": "8.2.1",
+ "resolved": "https://registry.npmjs.org/@types/whatwg-url/-/whatwg-url-8.2.1.tgz",
+ "integrity": "sha512-2YubE1sjj5ifxievI5Ge1sckb9k/Er66HyR2c+3+I6VDUUg1TLPdYYTEbQ+DjRkS4nTxMJhgWfSfMRD2sl2EYQ==",
+ "requires": {
+ "@types/node": "*",
+ "@types/webidl-conversions": "*"
+ }
+ },
+ "@types/ws": {
+ "version": "8.5.3",
+ "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.3.tgz",
+ "integrity": "sha512-6YOoWjruKj1uLf3INHH7D3qTXwFfEsg1kf3c0uDdSBJwfa/llkwIjrAGV7j7mVgGNbzTQ3HiHKKDXl6bJPD97w==",
+ "requires": {
+ "@types/node": "*"
+ }
+ },
+ "@ungap/structured-clone": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.0.1.tgz",
+ "integrity": "sha512-zKVyTt6rELvPXYwcVPTJcPFtY0AckN5A7xWuc7owBqR0FdtuDYhE9MZZUi6IY1kZUQFSXV1B3UOOIyLkVHYd2w=="
+ },
+ "accepts": {
+ "version": "1.3.8",
+ "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz",
+ "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==",
+ "requires": {
+ "mime-types": "~2.1.34",
+ "negotiator": "0.6.3"
+ }
+ },
+ "array-flatten": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz",
+ "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI="
+ },
+ "asynckit": {
+ "version": "0.4.0",
+ "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
+ "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k="
+ },
+ "balanced-match": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
+ "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="
+ },
+ "base64-js": {
+ "version": "1.5.1",
+ "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz",
+ "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA=="
+ },
+ "blueimp-load-image": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/blueimp-load-image/-/blueimp-load-image-3.0.0.tgz",
+ "integrity": "sha512-Q9rFbd4ZUNvzSFmRXx9MoG0RwWwJeMjjEUbG7WIOJgUg22Jgkow0wL5b35B6qwiBscxACW9OHdrP5s2vQ3x8DQ=="
+ },
+ "bmp-js": {
+ "version": "0.1.0",
+ "resolved": "https://registry.npmjs.org/bmp-js/-/bmp-js-0.1.0.tgz",
+ "integrity": "sha1-4Fpj95amwf8l9Hcex62twUjAcjM="
+ },
+ "body-parser": {
+ "version": "1.20.0",
+ "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.0.tgz",
+ "integrity": "sha512-DfJ+q6EPcGKZD1QWUjSpqp+Q7bDQTsQIF4zfUAtZ6qk+H/3/QRhg9CEp39ss+/T2vw0+HaidC0ecJj/DRLIaKg==",
+ "requires": {
+ "bytes": "3.1.2",
+ "content-type": "~1.0.4",
+ "debug": "2.6.9",
+ "depd": "2.0.0",
+ "destroy": "1.2.0",
+ "http-errors": "2.0.0",
+ "iconv-lite": "0.4.24",
+ "on-finished": "2.4.1",
+ "qs": "6.10.3",
+ "raw-body": "2.5.1",
+ "type-is": "~1.6.18",
+ "unpipe": "1.0.0"
+ }
+ },
+ "brace-expansion": {
+ "version": "1.1.11",
+ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
+ "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
+ "requires": {
+ "balanced-match": "^1.0.0",
+ "concat-map": "0.0.1"
+ }
+ },
+ "bson": {
+ "version": "4.6.4",
+ "resolved": "https://registry.npmjs.org/bson/-/bson-4.6.4.tgz",
+ "integrity": "sha512-TdQ3FzguAu5HKPPlr0kYQCyrYUYh8tFM+CMTpxjNzVzxeiJY00Rtuj3LXLHSgiGvmaWlZ8PE+4KyM2thqE38pQ==",
+ "requires": {
+ "buffer": "^5.6.0"
+ }
+ },
+ "buffer": {
+ "version": "5.7.1",
+ "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz",
+ "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==",
+ "requires": {
+ "base64-js": "^1.3.1",
+ "ieee754": "^1.1.13"
+ }
+ },
+ "bytes": {
+ "version": "3.1.2",
+ "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz",
+ "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg=="
+ },
+ "call-bind": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz",
+ "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==",
+ "requires": {
+ "function-bind": "^1.1.1",
+ "get-intrinsic": "^1.0.2"
+ }
+ },
+ "cli-color": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/cli-color/-/cli-color-2.0.1.tgz",
+ "integrity": "sha512-eBbxZF6fqPUNnf7CLAFOersUnyYzv83tHFLSlts+OAHsNendaqv2tHCq+/MO+b3Y+9JeoUlIvobyxG/Z8GNeOg==",
+ "requires": {
+ "d": "^1.0.1",
+ "es5-ext": "^0.10.53",
+ "es6-iterator": "^2.0.3",
+ "memoizee": "^0.4.15",
+ "timers-ext": "^0.1.7"
+ }
+ },
+ "colors": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/colors/-/colors-1.4.0.tgz",
+ "integrity": "sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA=="
+ },
+ "combined-stream": {
+ "version": "1.0.8",
+ "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
+ "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
+ "requires": {
+ "delayed-stream": "~1.0.0"
+ }
+ },
+ "commander": {
+ "version": "8.3.0",
+ "resolved": "https://registry.npmjs.org/commander/-/commander-8.3.0.tgz",
+ "integrity": "sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww=="
+ },
+ "concat-map": {
+ "version": "0.0.1",
+ "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
+ "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s="
+ },
+ "content-disposition": {
+ "version": "0.5.4",
+ "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz",
+ "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==",
+ "requires": {
+ "safe-buffer": "5.2.1"
+ }
+ },
+ "content-type": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz",
+ "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA=="
+ },
+ "cookie": {
+ "version": "0.5.0",
+ "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz",
+ "integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw=="
+ },
+ "cookie-signature": {
+ "version": "1.0.6",
+ "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz",
+ "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw="
+ },
+ "d": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/d/-/d-1.0.1.tgz",
+ "integrity": "sha512-m62ShEObQ39CfralilEQRjH6oAMtNCV1xJyEx5LpRYUVN+EviphDgUc/F3hnYbADmkiNs67Y+3ylmlG7Lnu+FA==",
+ "requires": {
+ "es5-ext": "^0.10.50",
+ "type": "^1.0.1"
+ }
+ },
+ "debug": {
+ "version": "2.6.9",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
+ "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
+ "requires": {
+ "ms": "2.0.0"
+ }
+ },
+ "delayed-stream": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
+ "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk="
+ },
+ "denque": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/denque/-/denque-2.0.1.tgz",
+ "integrity": "sha512-tfiWc6BQLXNLpNiR5iGd0Ocu3P3VpxfzFiqubLgMfhfOw9WyvgJBd46CClNn9k3qfbjvT//0cf7AlYRX/OslMQ=="
+ },
+ "depd": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz",
+ "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw=="
+ },
+ "destroy": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz",
+ "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg=="
+ },
+ "difflib": {
+ "version": "0.2.4",
+ "resolved": "https://registry.npmjs.org/difflib/-/difflib-0.2.4.tgz",
+ "integrity": "sha1-teMDYabbAjF21WKJLbhZQKcY9H4=",
+ "requires": {
+ "heap": ">= 0.2.0"
+ }
+ },
+ "discord-api-types": {
+ "version": "0.26.1",
+ "resolved": "https://registry.npmjs.org/discord-api-types/-/discord-api-types-0.26.1.tgz",
+ "integrity": "sha512-T5PdMQ+Y1MEECYMV5wmyi9VEYPagEDEi4S0amgsszpWY0VB9JJ/hEvM6BgLhbdnKky4gfmZEXtEEtojN8ZKJQQ=="
+ },
+ "discord.js": {
+ "version": "13.8.0",
+ "resolved": "https://registry.npmjs.org/discord.js/-/discord.js-13.8.0.tgz",
+ "integrity": "sha512-EPAA/2VLycYN5wSzavqa4iJ6qj3UtQFtHw5TH/60Fj29ymfEsCQVn//o1mTpwDxzwb+rPIrWhkxKIGGnjfv0Iw==",
+ "requires": {
+ "@discordjs/builders": "^0.14.0",
+ "@discordjs/collection": "^0.7.0",
+ "@sapphire/async-queue": "^1.3.1",
+ "@types/node-fetch": "^2.6.1",
+ "@types/ws": "^8.5.3",
+ "discord-api-types": "^0.33.3",
+ "form-data": "^4.0.0",
+ "node-fetch": "^2.6.1",
+ "ws": "^8.7.0"
+ },
+ "dependencies": {
+ "@discordjs/builders": {
+ "version": "0.14.0",
+ "resolved": "https://registry.npmjs.org/@discordjs/builders/-/builders-0.14.0.tgz",
+ "integrity": "sha512-+fqLIqa9wN3R+kvlld8sgG0nt04BAZxdCDP4t2qZ9TJsquLWA+xMtT8Waibb3d4li4AQS+IOfjiHAznv/dhHgQ==",
+ "requires": {
+ "@sapphire/shapeshift": "^3.1.0",
+ "@sindresorhus/is": "^4.6.0",
+ "discord-api-types": "^0.33.3",
+ "fast-deep-equal": "^3.1.3",
+ "ts-mixer": "^6.0.1",
+ "tslib": "^2.4.0"
+ }
+ },
+ "discord-api-types": {
+ "version": "0.33.5",
+ "resolved": "https://registry.npmjs.org/discord-api-types/-/discord-api-types-0.33.5.tgz",
+ "integrity": "sha512-dvO5M52v7m7Dy96+XUnzXNsQ/0npsYpU6dL205kAtEDueswoz3aU3bh1UMoK4cQmcGtB1YRyLKqp+DXi05lzFg=="
+ }
+ }
+ },
+ "dreamopt": {
+ "version": "0.8.0",
+ "resolved": "https://registry.npmjs.org/dreamopt/-/dreamopt-0.8.0.tgz",
+ "integrity": "sha1-W8yAvnCX5F/EicNCQFq2gUCowdk=",
+ "requires": {
+ "wordwrap": ">=0.0.2"
+ }
+ },
+ "ee-first": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
+ "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0="
+ },
+ "encodeurl": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz",
+ "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k="
+ },
+ "es5-ext": {
+ "version": "0.10.57",
+ "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.57.tgz",
+ "integrity": "sha512-L7cCNoPwTkAp7IBHxrKLsh7NKiVFkcdxlP9vbVw9QUvb7gF0Mz9bEBN0WY9xqdTjGF907EMT/iG013vnbqwu1Q==",
+ "requires": {
+ "es6-iterator": "^2.0.3",
+ "es6-symbol": "^3.1.3",
+ "next-tick": "^1.1.0"
+ }
+ },
+ "es6-iterator": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/es6-iterator/-/es6-iterator-2.0.3.tgz",
+ "integrity": "sha1-p96IkUGgWpSwhUQDstCg+/qY87c=",
+ "requires": {
+ "d": "1",
+ "es5-ext": "^0.10.35",
+ "es6-symbol": "^3.1.1"
+ }
+ },
+ "es6-symbol": {
+ "version": "3.1.3",
+ "resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.3.tgz",
+ "integrity": "sha512-NJ6Yn3FuDinBaBRWl/q5X/s4koRHBrgKAu+yGI6JCBeiu3qrcbJhwT2GeR/EXVfylRk8dpQVJoLEFhK+Mu31NA==",
+ "requires": {
+ "d": "^1.0.1",
+ "ext": "^1.1.2"
+ }
+ },
+ "es6-weak-map": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/es6-weak-map/-/es6-weak-map-2.0.3.tgz",
+ "integrity": "sha512-p5um32HOTO1kP+w7PRnB+5lQ43Z6muuMuIMffvDN8ZB4GcnjLBV6zGStpbASIMk4DCAvEaamhe2zhyCb/QXXsA==",
+ "requires": {
+ "d": "1",
+ "es5-ext": "^0.10.46",
+ "es6-iterator": "^2.0.3",
+ "es6-symbol": "^3.1.1"
+ }
+ },
+ "escape-html": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz",
+ "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg="
+ },
+ "etag": {
+ "version": "1.8.1",
+ "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz",
+ "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc="
+ },
+ "event-emitter": {
+ "version": "0.3.5",
+ "resolved": "https://registry.npmjs.org/event-emitter/-/event-emitter-0.3.5.tgz",
+ "integrity": "sha1-34xp7vFkeSPHFXuc6DhAYQsCzDk=",
+ "requires": {
+ "d": "1",
+ "es5-ext": "~0.10.14"
+ }
+ },
+ "express": {
+ "version": "4.18.1",
+ "resolved": "https://registry.npmjs.org/express/-/express-4.18.1.tgz",
+ "integrity": "sha512-zZBcOX9TfehHQhtupq57OF8lFZ3UZi08Y97dwFCkD8p9d/d2Y3M+ykKcwaMDEL+4qyUolgBDX6AblpR3fL212Q==",
+ "requires": {
+ "accepts": "~1.3.8",
+ "array-flatten": "1.1.1",
+ "body-parser": "1.20.0",
+ "content-disposition": "0.5.4",
+ "content-type": "~1.0.4",
+ "cookie": "0.5.0",
+ "cookie-signature": "1.0.6",
+ "debug": "2.6.9",
+ "depd": "2.0.0",
+ "encodeurl": "~1.0.2",
+ "escape-html": "~1.0.3",
+ "etag": "~1.8.1",
+ "finalhandler": "1.2.0",
+ "fresh": "0.5.2",
+ "http-errors": "2.0.0",
+ "merge-descriptors": "1.0.1",
+ "methods": "~1.1.2",
+ "on-finished": "2.4.1",
+ "parseurl": "~1.3.3",
+ "path-to-regexp": "0.1.7",
+ "proxy-addr": "~2.0.7",
+ "qs": "6.10.3",
+ "range-parser": "~1.2.1",
+ "safe-buffer": "5.2.1",
+ "send": "0.18.0",
+ "serve-static": "1.15.0",
+ "setprototypeof": "1.2.0",
+ "statuses": "2.0.1",
+ "type-is": "~1.6.18",
+ "utils-merge": "1.0.1",
+ "vary": "~1.1.2"
+ }
+ },
+ "ext": {
+ "version": "1.6.0",
+ "resolved": "https://registry.npmjs.org/ext/-/ext-1.6.0.tgz",
+ "integrity": "sha512-sdBImtzkq2HpkdRLtlLWDa6w4DX22ijZLKx8BMPUuKe1c5lbN6xwQDQCxSfxBQnHZ13ls/FH0MQZx/q/gr6FQg==",
+ "requires": {
+ "type": "^2.5.0"
+ },
+ "dependencies": {
+ "type": {
+ "version": "2.6.0",
+ "resolved": "https://registry.npmjs.org/type/-/type-2.6.0.tgz",
+ "integrity": "sha512-eiDBDOmkih5pMbo9OqsqPRGMljLodLcwd5XD5JbtNB0o89xZAwynY9EdCDsJU7LtcVCClu9DvM7/0Ep1hYX3EQ=="
+ }
+ }
+ },
+ "fast-deep-equal": {
+ "version": "3.1.3",
+ "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
+ "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q=="
+ },
+ "file-type": {
+ "version": "12.4.2",
+ "resolved": "https://registry.npmjs.org/file-type/-/file-type-12.4.2.tgz",
+ "integrity": "sha512-UssQP5ZgIOKelfsaB5CuGAL+Y+q7EmONuiwF3N5HAH0t27rvrttgi6Ra9k/+DVaY9UF6+ybxu5pOXLUdA8N7Vg=="
+ },
+ "finalhandler": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz",
+ "integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==",
+ "requires": {
+ "debug": "2.6.9",
+ "encodeurl": "~1.0.2",
+ "escape-html": "~1.0.3",
+ "on-finished": "2.4.1",
+ "parseurl": "~1.3.3",
+ "statuses": "2.0.1",
+ "unpipe": "~1.0.0"
+ }
+ },
+ "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==",
+ "requires": {
+ "asynckit": "^0.4.0",
+ "combined-stream": "^1.0.8",
+ "mime-types": "^2.1.12"
+ }
+ },
+ "forwarded": {
+ "version": "0.2.0",
+ "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz",
+ "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow=="
+ },
+ "fresh": {
+ "version": "0.5.2",
+ "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz",
+ "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac="
+ },
+ "fs.realpath": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
+ "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8="
+ },
+ "function-bind": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz",
+ "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A=="
+ },
+ "get-intrinsic": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.1.tgz",
+ "integrity": "sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q==",
+ "requires": {
+ "function-bind": "^1.1.1",
+ "has": "^1.0.3",
+ "has-symbols": "^1.0.1"
+ }
+ },
+ "glob": {
+ "version": "5.0.15",
+ "resolved": "https://registry.npmjs.org/glob/-/glob-5.0.15.tgz",
+ "integrity": "sha1-G8k2ueAvSmA/zCIuz3Yz0wuLk7E=",
+ "requires": {
+ "inflight": "^1.0.4",
+ "inherits": "2",
+ "minimatch": "2 || 3",
+ "once": "^1.3.0",
+ "path-is-absolute": "^1.0.0"
+ }
+ },
+ "has": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz",
+ "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==",
+ "requires": {
+ "function-bind": "^1.1.1"
+ }
+ },
+ "has-symbols": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz",
+ "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A=="
+ },
+ "heap": {
+ "version": "0.2.7",
+ "resolved": "https://registry.npmjs.org/heap/-/heap-0.2.7.tgz",
+ "integrity": "sha512-2bsegYkkHO+h/9MGbn6KWcE45cHZgPANo5LXF7EvWdT0yT2EguSVO1nDgU5c8+ZOPwp2vMNa7YFsJhVcDR9Sdg=="
+ },
+ "http-errors": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz",
+ "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==",
+ "requires": {
+ "depd": "2.0.0",
+ "inherits": "2.0.4",
+ "setprototypeof": "1.2.0",
+ "statuses": "2.0.1",
+ "toidentifier": "1.0.1"
+ }
+ },
+ "humanize": {
+ "version": "0.0.9",
+ "resolved": "https://registry.npmjs.org/humanize/-/humanize-0.0.9.tgz",
+ "integrity": "sha1-GZT/rs3+nEQe0r2sdFK3u0yeQaQ="
+ },
+ "humanize-duration": {
+ "version": "3.27.1",
+ "resolved": "https://registry.npmjs.org/humanize-duration/-/humanize-duration-3.27.1.tgz",
+ "integrity": "sha512-jCVkMl+EaM80rrMrAPl96SGG4NRac53UyI1o/yAzebDntEY6K6/Fj2HOjdPg8omTqIe5Y0wPBai2q5xXrIbarA=="
+ },
+ "iconv-lite": {
+ "version": "0.4.24",
+ "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
+ "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==",
+ "requires": {
+ "safer-buffer": ">= 2.1.2 < 3"
+ }
+ },
+ "idb-keyval": {
+ "version": "3.2.0",
+ "resolved": "https://registry.npmjs.org/idb-keyval/-/idb-keyval-3.2.0.tgz",
+ "integrity": "sha512-slx8Q6oywCCSfKgPgL0sEsXtPVnSbTLWpyiDcu6msHOyKOLari1TD1qocXVCft80umnkk3/Qqh3lwoFt8T/BPQ=="
+ },
+ "ieee754": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz",
+ "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA=="
+ },
+ "inflight": {
+ "version": "1.0.6",
+ "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
+ "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=",
+ "requires": {
+ "once": "^1.3.0",
+ "wrappy": "1"
+ }
+ },
+ "inherits": {
+ "version": "2.0.4",
+ "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
+ "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="
+ },
+ "ip": {
+ "version": "1.1.8",
+ "resolved": "https://registry.npmjs.org/ip/-/ip-1.1.8.tgz",
+ "integrity": "sha512-PuExPYUiu6qMBQb4l06ecm6T6ujzhmh+MeJcW9wa89PoAz5pvd4zPgN5WJV104mb6S2T1AwNIAaB70JNrLQWhg=="
+ },
+ "ipaddr.js": {
+ "version": "1.9.1",
+ "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz",
+ "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g=="
+ },
+ "is-electron": {
+ "version": "2.2.1",
+ "resolved": "https://registry.npmjs.org/is-electron/-/is-electron-2.2.1.tgz",
+ "integrity": "sha512-r8EEQQsqT+Gn0aXFx7lTFygYQhILLCB+wn0WCDL5LZRINeLH/Rvw1j2oKodELLXYNImQ3CRlVsY8wW4cGOsyuw=="
+ },
+ "is-promise": {
+ "version": "2.2.2",
+ "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.2.2.tgz",
+ "integrity": "sha512-+lP4/6lKUBfQjZ2pdxThZvLUAafmZb8OAxFb8XXtiQmS35INgr85hdOGoEs124ez1FCnZJt6jau/T+alh58QFQ=="
+ },
+ "is-url": {
+ "version": "1.2.4",
+ "resolved": "https://registry.npmjs.org/is-url/-/is-url-1.2.4.tgz",
+ "integrity": "sha512-ITvGim8FhRiYe4IQ5uHSkj7pVaPDrCTkNd3yq3cV7iZAcJdHTUMPMEHcqSOy9xZ9qFenQCvi+2wjH9a1nXqHww=="
+ },
+ "jpeg-autorotate": {
+ "version": "7.1.1",
+ "resolved": "https://registry.npmjs.org/jpeg-autorotate/-/jpeg-autorotate-7.1.1.tgz",
+ "integrity": "sha512-ewTZTG/QWOM0D5h/yKcQ3QgyrnQYsr3qmcS+bqoAwgQAY1KBa31aJ+q+FlElaxo/rSYqfF1ixf+8EIgluBkgTg==",
+ "requires": {
+ "colors": "^1.4.0",
+ "glob": "^7.1.6",
+ "jpeg-js": "^0.4.2",
+ "piexifjs": "^1.0.6",
+ "yargs-parser": "^20.2.1"
+ },
+ "dependencies": {
+ "glob": {
+ "version": "7.2.0",
+ "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz",
+ "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==",
+ "requires": {
+ "fs.realpath": "^1.0.0",
+ "inflight": "^1.0.4",
+ "inherits": "2",
+ "minimatch": "^3.0.4",
+ "once": "^1.3.0",
+ "path-is-absolute": "^1.0.0"
+ }
+ }
+ }
+ },
+ "jpeg-js": {
+ "version": "0.4.3",
+ "resolved": "https://registry.npmjs.org/jpeg-js/-/jpeg-js-0.4.3.tgz",
+ "integrity": "sha512-ru1HWKek8octvUHFHvE5ZzQ1yAsJmIvRdGWvSoKV52XKyuyYA437QWDttXT8eZXDSbuMpHlLzPDZUPd6idIz+Q=="
+ },
+ "jshaiku": {
+ "version": "file:../haiku",
+ "requires": {
+ "@babel/core": "^7.16.7",
+ "@babel/preset-env": "^7.16.8",
+ "@babel/preset-typescript": "^7.16.7",
+ "@discordjs/builders": "^0.11.0",
+ "@discordjs/rest": "^0.2.0-canary.0",
+ "@types/jest": "^27.4.0",
+ "@types/node-cron": "^3.0.1",
+ "ansi-styles": "^6.1.0",
+ "babel-jest": "^27.4.6",
+ "chalk": "^5.0.0",
+ "discord-api-types": "^0.26.1",
+ "discord.js": "^13.8.0",
+ "jest": "^27.4.7",
+ "node-cron": "^3.0.0",
+ "ts-node": "^10.4.0",
+ "typescript": "4.5.4"
+ }
+ },
+ "json-diff": {
+ "version": "0.7.3",
+ "resolved": "https://registry.npmjs.org/json-diff/-/json-diff-0.7.3.tgz",
+ "integrity": "sha512-VBvNBt3cIrCBHa3gYbVsCFUEReqWZPf+Biq1ZtFdIiQ6rytRLDp3qvtrGv7z/iZDd1D4vXWpW7Nx1nP8muLzkg==",
+ "requires": {
+ "cli-color": "^2.0.0",
+ "difflib": "~0.2.1",
+ "dreamopt": "~0.8.0"
+ }
+ },
+ "lru-queue": {
+ "version": "0.1.0",
+ "resolved": "https://registry.npmjs.org/lru-queue/-/lru-queue-0.1.0.tgz",
+ "integrity": "sha1-Jzi9nw089PhEkMVzbEhpmsYyzaM=",
+ "requires": {
+ "es5-ext": "~0.10.2"
+ }
+ },
+ "media-typer": {
+ "version": "0.3.0",
+ "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz",
+ "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g="
+ },
+ "memoizee": {
+ "version": "0.4.15",
+ "resolved": "https://registry.npmjs.org/memoizee/-/memoizee-0.4.15.tgz",
+ "integrity": "sha512-UBWmJpLZd5STPm7PMUlOw/TSy972M+z8gcyQ5veOnSDRREz/0bmpyTfKt3/51DhEBqCZQn1udM/5flcSPYhkdQ==",
+ "requires": {
+ "d": "^1.0.1",
+ "es5-ext": "^0.10.53",
+ "es6-weak-map": "^2.0.3",
+ "event-emitter": "^0.3.5",
+ "is-promise": "^2.2.2",
+ "lru-queue": "^0.1.0",
+ "next-tick": "^1.1.0",
+ "timers-ext": "^0.1.7"
+ }
+ },
+ "memory-pager": {
+ "version": "1.5.0",
+ "resolved": "https://registry.npmjs.org/memory-pager/-/memory-pager-1.5.0.tgz",
+ "integrity": "sha512-ZS4Bp4r/Zoeq6+NLJpP+0Zzm0pR8whtGPf1XExKLJBAczGMnSi3It14OiNCStjQjM6NU1okjQGSxgEZN8eBYKg==",
+ "optional": true
+ },
+ "merge-descriptors": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz",
+ "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E="
+ },
+ "methods": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz",
+ "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4="
+ },
+ "mime": {
+ "version": "1.6.0",
+ "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz",
+ "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg=="
+ },
+ "mime-db": {
+ "version": "1.51.0",
+ "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.51.0.tgz",
+ "integrity": "sha512-5y8A56jg7XVQx2mbv1lu49NR4dokRnhZYTtL+KGfaa27uq4pSTXkwQkFJl4pkRMyNFz/EtYDSkiiEHx3F7UN6g=="
+ },
+ "mime-types": {
+ "version": "2.1.34",
+ "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.34.tgz",
+ "integrity": "sha512-6cP692WwGIs9XXdOO4++N+7qjqv0rqxxVvJ3VHPh/Sc9mVZcQP+ZGhkKiTvWMQRr2tbHkJP/Yn7Y0npb3ZBs4A==",
+ "requires": {
+ "mime-db": "1.51.0"
+ }
+ },
+ "minimatch": {
+ "version": "3.1.2",
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
+ "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
+ "requires": {
+ "brace-expansion": "^1.1.7"
+ }
+ },
+ "mongodb": {
+ "version": "4.7.0",
+ "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-4.7.0.tgz",
+ "integrity": "sha512-HhVar6hsUeMAVlIbwQwWtV36iyjKd9qdhY+s4wcU8K6TOj4Q331iiMy+FoPuxEntDIijTYWivwFJkLv8q/ZgvA==",
+ "requires": {
+ "bson": "^4.6.3",
+ "denque": "^2.0.1",
+ "mongodb-connection-string-url": "^2.5.2",
+ "saslprep": "^1.0.3",
+ "socks": "^2.6.2"
+ }
+ },
+ "mongodb-connection-string-url": {
+ "version": "2.5.2",
+ "resolved": "https://registry.npmjs.org/mongodb-connection-string-url/-/mongodb-connection-string-url-2.5.2.tgz",
+ "integrity": "sha512-tWDyIG8cQlI5k3skB6ywaEA5F9f5OntrKKsT/Lteub2zgwSUlhqEN2inGgBTm8bpYJf8QYBdA/5naz65XDpczA==",
+ "requires": {
+ "@types/whatwg-url": "^8.2.1",
+ "whatwg-url": "^11.0.0"
+ }
+ },
+ "ms": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+ "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
+ },
+ "negotiator": {
+ "version": "0.6.3",
+ "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz",
+ "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg=="
+ },
+ "next-tick": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/next-tick/-/next-tick-1.1.0.tgz",
+ "integrity": "sha512-CXdUiJembsNjuToQvxayPZF9Vqht7hewsvy2sOWafLvi2awflj9mOC6bHIg50orX8IJvWKY9wYQ/zB2kogPslQ=="
+ },
+ "node-fetch": {
+ "version": "2.6.7",
+ "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz",
+ "integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==",
+ "requires": {
+ "whatwg-url": "^5.0.0"
+ },
+ "dependencies": {
+ "tr46": {
+ "version": "0.0.3",
+ "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz",
+ "integrity": "sha1-gYT9NH2snNwYWZLzpmIuFLnZq2o="
+ },
+ "whatwg-url": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz",
+ "integrity": "sha1-lmRU6HZUYuN2RNNib2dCzotwll0=",
+ "requires": {
+ "tr46": "~0.0.3",
+ "webidl-conversions": "^3.0.0"
+ }
+ }
+ }
+ },
+ "node-tesseract": {
+ "version": "0.2.7",
+ "resolved": "https://registry.npmjs.org/node-tesseract/-/node-tesseract-0.2.7.tgz",
+ "integrity": "sha1-yPAvuDUaQnByc1d4wFGYI/JgG4Q=",
+ "requires": {
+ "glob": "^5.0.10",
+ "node-uuid": "^1.4.1"
+ }
+ },
+ "node-uuid": {
+ "version": "1.4.8",
+ "resolved": "https://registry.npmjs.org/node-uuid/-/node-uuid-1.4.8.tgz",
+ "integrity": "sha1-sEDrCSOWivq/jTL7HxfxFn/auQc="
+ },
+ "object-inspect": {
+ "version": "1.12.0",
+ "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.0.tgz",
+ "integrity": "sha512-Ho2z80bVIvJloH+YzRmpZVQe87+qASmBUKZDWgx9cu+KDrX2ZDH/3tMy+gXbZETVGs2M8YdxObOh7XAtim9Y0g=="
+ },
+ "on-finished": {
+ "version": "2.4.1",
+ "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz",
+ "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==",
+ "requires": {
+ "ee-first": "1.1.1"
+ }
+ },
+ "once": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
+ "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=",
+ "requires": {
+ "wrappy": "1"
+ }
+ },
+ "opencollective-postinstall": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/opencollective-postinstall/-/opencollective-postinstall-2.0.3.tgz",
+ "integrity": "sha512-8AV/sCtuzUeTo8gQK5qDZzARrulB3egtLzFgteqB2tcT4Mw7B8Kt7JcDHmltjz6FOAHsvTevk70gZEbhM4ZS9Q=="
+ },
+ "parseurl": {
+ "version": "1.3.3",
+ "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz",
+ "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ=="
+ },
+ "path-is-absolute": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
+ "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18="
+ },
+ "path-to-regexp": {
+ "version": "0.1.7",
+ "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz",
+ "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w="
+ },
+ "piexifjs": {
+ "version": "1.0.6",
+ "resolved": "https://registry.npmjs.org/piexifjs/-/piexifjs-1.0.6.tgz",
+ "integrity": "sha512-0wVyH0cKohzBQ5Gi2V1BuxYpxWfxF3cSqfFXfPIpl5tl9XLS5z4ogqhUCD20AbHi0h9aJkqXNJnkVev6gwh2ag=="
+ },
+ "proxy-addr": {
+ "version": "2.0.7",
+ "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz",
+ "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==",
+ "requires": {
+ "forwarded": "0.2.0",
+ "ipaddr.js": "1.9.1"
+ }
+ },
+ "punycode": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz",
+ "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A=="
+ },
+ "qs": {
+ "version": "6.10.3",
+ "resolved": "https://registry.npmjs.org/qs/-/qs-6.10.3.tgz",
+ "integrity": "sha512-wr7M2E0OFRfIfJZjKGieI8lBKb7fRCH4Fv5KNPEs7gJ8jadvotdsS08PzOKR7opXhZ/Xkjtt3WF9g38drmyRqQ==",
+ "requires": {
+ "side-channel": "^1.0.4"
+ }
+ },
+ "range-parser": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz",
+ "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg=="
+ },
+ "raw-body": {
+ "version": "2.5.1",
+ "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.1.tgz",
+ "integrity": "sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==",
+ "requires": {
+ "bytes": "3.1.2",
+ "http-errors": "2.0.0",
+ "iconv-lite": "0.4.24",
+ "unpipe": "1.0.0"
+ }
+ },
+ "regenerator-runtime": {
+ "version": "0.13.9",
+ "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz",
+ "integrity": "sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA=="
+ },
+ "resolve-url": {
+ "version": "0.2.1",
+ "resolved": "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz",
+ "integrity": "sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo="
+ },
+ "safe-buffer": {
+ "version": "5.2.1",
+ "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
+ "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ=="
+ },
+ "safer-buffer": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
+ "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="
+ },
+ "saslprep": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/saslprep/-/saslprep-1.0.3.tgz",
+ "integrity": "sha512-/MY/PEMbk2SuY5sScONwhUDsV2p77Znkb/q3nSVstq/yQzYJOH/Azh29p9oJLsl3LnQwSvZDKagDGBsBwSooag==",
+ "optional": true,
+ "requires": {
+ "sparse-bitfield": "^3.0.3"
+ }
+ },
+ "send": {
+ "version": "0.18.0",
+ "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz",
+ "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==",
+ "requires": {
+ "debug": "2.6.9",
+ "depd": "2.0.0",
+ "destroy": "1.2.0",
+ "encodeurl": "~1.0.2",
+ "escape-html": "~1.0.3",
+ "etag": "~1.8.1",
+ "fresh": "0.5.2",
+ "http-errors": "2.0.0",
+ "mime": "1.6.0",
+ "ms": "2.1.3",
+ "on-finished": "2.4.1",
+ "range-parser": "~1.2.1",
+ "statuses": "2.0.1"
+ },
+ "dependencies": {
+ "ms": {
+ "version": "2.1.3",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
+ "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="
+ }
+ }
+ },
+ "serve-static": {
+ "version": "1.15.0",
+ "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz",
+ "integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==",
+ "requires": {
+ "encodeurl": "~1.0.2",
+ "escape-html": "~1.0.3",
+ "parseurl": "~1.3.3",
+ "send": "0.18.0"
+ }
+ },
+ "setprototypeof": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz",
+ "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw=="
+ },
+ "side-channel": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz",
+ "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==",
+ "requires": {
+ "call-bind": "^1.0.0",
+ "get-intrinsic": "^1.0.2",
+ "object-inspect": "^1.9.0"
+ }
+ },
+ "smart-buffer": {
+ "version": "4.2.0",
+ "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz",
+ "integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg=="
+ },
+ "socks": {
+ "version": "2.6.2",
+ "resolved": "https://registry.npmjs.org/socks/-/socks-2.6.2.tgz",
+ "integrity": "sha512-zDZhHhZRY9PxRruRMR7kMhnf3I8hDs4S3f9RecfnGxvcBHQcKcIH/oUcEWffsfl1XxdYlA7nnlGbbTvPz9D8gA==",
+ "requires": {
+ "ip": "^1.1.5",
+ "smart-buffer": "^4.2.0"
+ }
+ },
+ "sparse-bitfield": {
+ "version": "3.0.3",
+ "resolved": "https://registry.npmjs.org/sparse-bitfield/-/sparse-bitfield-3.0.3.tgz",
+ "integrity": "sha512-kvzhi7vqKTfkh0PZU+2D2PIllw2ymqJKujUcyPMd9Y75Nv4nPbGJZXNhxsgdQab2BmlDct1YnfQCguEvHr7VsQ==",
+ "optional": true,
+ "requires": {
+ "memory-pager": "^1.0.2"
+ }
+ },
+ "statuses": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz",
+ "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ=="
+ },
+ "structured-clone": {
+ "version": "0.2.2",
+ "resolved": "https://registry.npmjs.org/structured-clone/-/structured-clone-0.2.2.tgz",
+ "integrity": "sha1-rJK2vjGVimQ9sw8TNavGobAt/cI="
+ },
+ "tesseract.js": {
+ "version": "2.1.5",
+ "resolved": "https://registry.npmjs.org/tesseract.js/-/tesseract.js-2.1.5.tgz",
+ "integrity": "sha512-7CIS3SWr7TXpeaH9+HS7iUtVbCfPFYOO3p6rkRAkdtsOtrbz6496x59na6SCbFAIaZulQxy8BjwSu3qL3AoDRg==",
+ "requires": {
+ "blueimp-load-image": "^3.0.0",
+ "bmp-js": "^0.1.0",
+ "file-type": "^12.4.1",
+ "idb-keyval": "^3.2.0",
+ "is-electron": "^2.2.0",
+ "is-url": "^1.2.4",
+ "jpeg-autorotate": "^7.1.1",
+ "node-fetch": "^2.6.0",
+ "opencollective-postinstall": "^2.0.2",
+ "regenerator-runtime": "^0.13.3",
+ "resolve-url": "^0.2.1",
+ "tesseract.js-core": "^2.2.0",
+ "zlibjs": "^0.3.1"
+ }
+ },
+ "tesseract.js-core": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/tesseract.js-core/-/tesseract.js-core-2.2.0.tgz",
+ "integrity": "sha512-a8L+OJTbUipBsEDsJhDPlnLB0TY1MkTZqw5dqUwmiDSjUzwvU7HWLg/2+WDRulKUi4LE+7PnHlaBlW0k+V0U0w=="
+ },
+ "timers-ext": {
+ "version": "0.1.7",
+ "resolved": "https://registry.npmjs.org/timers-ext/-/timers-ext-0.1.7.tgz",
+ "integrity": "sha512-b85NUNzTSdodShTIbky6ZF02e8STtVVfD+fu4aXXShEELpozH+bCpJLYMPZbsABN2wDH7fJpqIoXxJpzbf0NqQ==",
+ "requires": {
+ "es5-ext": "~0.10.46",
+ "next-tick": "1"
+ }
+ },
+ "toidentifier": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz",
+ "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA=="
+ },
+ "tr46": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/tr46/-/tr46-3.0.0.tgz",
+ "integrity": "sha512-l7FvfAHlcmulp8kr+flpQZmVwtu7nfRV7NZujtN0OqES8EL4O4e0qqzL0DC5gAvx/ZC/9lk6rhcUwYvkBnBnYA==",
+ "requires": {
+ "punycode": "^2.1.1"
+ }
+ },
+ "ts-mixer": {
+ "version": "6.0.1",
+ "resolved": "https://registry.npmjs.org/ts-mixer/-/ts-mixer-6.0.1.tgz",
+ "integrity": "sha512-hvE+ZYXuINrx6Ei6D6hz+PTim0Uf++dYbK9FFifLNwQj+RwKquhQpn868yZsCtJYiclZF1u8l6WZxxKi+vv7Rg=="
+ },
+ "tslib": {
+ "version": "2.4.0",
+ "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz",
+ "integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ=="
+ },
+ "type": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/type/-/type-1.2.0.tgz",
+ "integrity": "sha512-+5nt5AAniqsCnu2cEQQdpzCAh33kVx8n0VoFidKpB1dVVLAN/F+bgVOqOJqOnEnrhp222clB5p3vUlD+1QAnfg=="
+ },
+ "type-is": {
+ "version": "1.6.18",
+ "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz",
+ "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==",
+ "requires": {
+ "media-typer": "0.3.0",
+ "mime-types": "~2.1.24"
+ }
+ },
+ "typescript": {
+ "version": "4.6.2",
+ "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.6.2.tgz",
+ "integrity": "sha512-HM/hFigTBHZhLXshn9sN37H085+hQGeJHJ/X7LpBWLID/fbc2acUMfU+lGD98X81sKP+pFa9f0DZmCwB9GnbAg=="
+ },
+ "unpipe": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz",
+ "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw="
+ },
+ "unscan": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/unscan/-/unscan-1.1.2.tgz",
+ "integrity": "sha512-a5RcGaBFMO9l78QWKffeWUo2cvfqUv05JCXuphE8MFOA92qyqp1Da7isnR+zjJspi45+yS8tTSuhd0vV3asWdA==",
+ "requires": {
+ "commander": "^8.3.0",
+ "form-data": "^4.0.0",
+ "node-fetch": "^2.6.5"
+ }
+ },
+ "utils-merge": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz",
+ "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM="
+ },
+ "vary": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz",
+ "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw="
+ },
+ "webidl-conversions": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz",
+ "integrity": "sha1-JFNCdeKnvGvnvIZhHMFq4KVlSHE="
+ },
+ "whatwg-url": {
+ "version": "11.0.0",
+ "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-11.0.0.tgz",
+ "integrity": "sha512-RKT8HExMpoYx4igMiVMY83lN6UeITKJlBQ+vR/8ZJ8OCdSiN3RwCq+9gH0+Xzj0+5IrM6i4j/6LuvzbZIQgEcQ==",
+ "requires": {
+ "tr46": "^3.0.0",
+ "webidl-conversions": "^7.0.0"
+ },
+ "dependencies": {
+ "webidl-conversions": {
+ "version": "7.0.0",
+ "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz",
+ "integrity": "sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g=="
+ }
+ }
+ },
+ "wordwrap": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz",
+ "integrity": "sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus="
+ },
+ "wrappy": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
+ "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8="
+ },
+ "ws": {
+ "version": "8.8.0",
+ "resolved": "https://registry.npmjs.org/ws/-/ws-8.8.0.tgz",
+ "integrity": "sha512-JDAgSYQ1ksuwqfChJusw1LSJ8BizJ2e/vVu5Lxjq3YvNJNlROv1ui4i+c/kUUrPheBvQl4c5UbERhTwKa6QBJQ==",
+ "requires": {}
+ },
+ "yargs-parser": {
+ "version": "20.2.9",
+ "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz",
+ "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w=="
+ },
+ "zlibjs": {
+ "version": "0.3.1",
+ "resolved": "https://registry.npmjs.org/zlibjs/-/zlibjs-0.3.1.tgz",
+ "integrity": "sha1-UBl+2yihxCymWcyLTmqd3W1ERVQ="
+ },
+ "zod": {
+ "version": "3.13.4",
+ "resolved": "https://registry.npmjs.org/zod/-/zod-3.13.4.tgz",
+ "integrity": "sha512-LZRucWt4j/ru5azOkJxCfpR87IyFDn8h2UODdqvXzZLb3K7bb9chUrUIGTy3BPsr8XnbQYfQ5Md5Hu2OYIo1mg=="
+ }
+ }
+}
diff --git a/package.json b/package.json
index 9706070..39257d9 100644
--- a/package.json
+++ b/package.json
@@ -1,8 +1,9 @@
{
"dependencies": {
"@discordjs/builders": "^0.12.0",
+ "@ungap/structured-clone": "^1.0.1",
"body-parser": "^1.20.0",
- "discord.js": "^13.6.0",
+ "discord.js": "^13.8.0",
"express": "^4.18.1",
"humanize": "^0.0.9",
"humanize-duration": "^3.27.1",
diff --git a/src/api/index.ts b/src/api/index.ts
index 570ca5b..07131ff 100644
--- a/src/api/index.ts
+++ b/src/api/index.ts
@@ -2,6 +2,8 @@
import express from 'express';
import bodyParser from 'body-parser';
import generateEmojiEmbed from "../utils/generateEmojiEmbed.js";
+import structuredClone from '@ungap/structured-clone';
+
const jsonParser = bodyParser.json();
const app = express();
@@ -9,7 +11,7 @@
const runServer = (client: HaikuClient) => {
app.get('/', (req, res) => {
- res.send(client.ws.ping);
+ res.status(200).send(client.ws.ping);
});
app.post('/verify/:code', jsonParser, async function (req, res) {
@@ -32,9 +34,9 @@
.setEmoji("MEMBER.JOIN")
], components: []});
}
- res.status(200).send();
+ res.sendStatus(200);
} else {
- res.status(403).send();
+ res.sendStatus(403);
}
});
@@ -51,17 +53,17 @@
]});
}
} catch {}
- res.status(200).send();
+ res.sendStatus(200);
})
app.get('/verify/:code', jsonParser, function (req, res) {
const code = req.params.code;
if (client.verify[code]) {
- // let data = structuredClone(client.verify[code])
- // delete data.interaction;
- // return res.status(200).send(data);
+ let data = structuredClone(client.verify[code])
+ delete data.interaction;
+ return res.status(200).send(data);
}
- return res.status(404).send();
+ return res.sendStatus(404);
})
app.listen(port);
diff --git a/src/automations/createModActionTicket.ts b/src/automations/createModActionTicket.ts
index ef317b7..a9a5a27 100644
--- a/src/automations/createModActionTicket.ts
+++ b/src/automations/createModActionTicket.ts
@@ -1,10 +1,10 @@
import Discord, { MessageActionRow, MessageButton } from 'discord.js';
-import readConfig from '../utils/readConfig.js'
import generateEmojiEmbed from '../utils/generateEmojiEmbed.js';
import getEmojiByName from "../utils/getEmojiByName.js";
+import client from "../utils/client.js";
-export async function create(guild: Discord.Guild, member: Discord.User, createdBy: Discord.User, client) {
- let config = await readConfig(guild.id);
+export async function create(guild: Discord.Guild, member: Discord.User, createdBy: Discord.User, reason: string) {
+ let config = await client.database.read(guild.id);
// @ts-ignore
const { log, NucleusColors, entry, renderUser, renderChannel, renderDelta } = client.logger
let overwrites = [{
@@ -12,6 +12,11 @@
allow: ["VIEW_CHANNEL", "SEND_MESSAGES", "ATTACH_FILES", "ADD_REACTIONS", "READ_MESSAGE_HISTORY"],
type: "member"
}] as Discord.OverwriteResolvable[];
+ overwrites.push({
+ id: guild.roles.everyone,
+ deny: ["VIEW_CHANNEL"],
+ type: "role"
+ })
if (config.tickets.supportRole != null) {
overwrites.push({
id: guild.roles.cache.get(config.tickets.supportRole),
@@ -47,7 +52,7 @@
.setTitle("New Ticket")
.setDescription(
`Ticket created by a Moderator\n` +
- `**Support type:** Appeal submission\n` +
+ `**Support type:** Appeal submission\n` + (reason != null ? `**Reason:**\n> ${reason}\n` : "") +
`**Ticket ID:** \`${c.id}\`\n` +
`Type \`/ticket close\` to archive this ticket.`,
)
@@ -84,6 +89,6 @@
}
export async function areTicketsEnabled(guild: string) {
- let config = await readConfig(guild);
+ let config = await client.database.read(guild);
return config.tickets.enabled;
}
\ No newline at end of file
diff --git a/src/automations/guide.ts b/src/automations/guide.ts
index 6a9b0b5..d443a42 100644
--- a/src/automations/guide.ts
+++ b/src/automations/guide.ts
@@ -96,7 +96,20 @@
)
.setEmoji("NUCLEUS.LOGO")
.setStatus("Danger")
- ).setTitle("Tickets").setDescription("Ticket system").setPageId(5)
+ ).setTitle("Tickets").setDescription("Ticket system").setPageId(5),
+ new Embed()
+ .setEmbed(new generateEmojiEmbed()
+ .setTitle("Tags")
+ .setDescription(
+ "Add a tag system to your server with the `/tag` and `/tags` commands.\n" +
+ "To create a tag, type `/tags create <tag name> <tag content>`.\n" +
+ "Tag names and content can be edited with `/tags edit`.\n" +
+ "To delete a tag, type `/tags delete <tag name>`.\n" +
+ "To view all tags, type `/tags list`.\n"
+ )
+ .setEmoji("NUCLEUS.LOGO")
+ .setStatus("Danger")
+ ).setTitle("Tags").setDescription("Tag system").setPageId(6)
]
let m;
if (interaction) {
@@ -144,30 +157,25 @@
.setPlaceholder("Choose a page...")
])]
}
+ let components = selectPane.concat([new MessageActionRow().addComponents([
+ new MessageButton().setCustomId("left").setEmoji(getEmojiByName("CONTROL.LEFT", "id")).setStyle("SECONDARY").setDisabled(page === 0),
+ new MessageButton().setCustomId("select").setEmoji(getEmojiByName("CONTROL.MENU", "id")).setStyle(selectPaneOpen ? "PRIMARY" : "SECONDARY").setDisabled(false),
+ new MessageButton().setCustomId("right").setEmoji(getEmojiByName("CONTROL.RIGHT", "id")).setStyle("SECONDARY").setDisabled(page === pages.length - 1),
+ new MessageButton().setCustomId("close").setEmoji(getEmojiByName("CONTROL.CROSS", "id")).setStyle("DANGER")
+ ])])
if (interaction) {
let em = new Discord.MessageEmbed(pages[page].embed)
em.setDescription(em.description + "\n\n" + createPageIndicator(pages.length, page));
await interaction.editReply({
embeds: [em],
- components: selectPane.concat([new MessageActionRow().addComponents([
- new MessageButton().setCustomId("left").setEmoji(getEmojiByName("CONTROL.LEFT", "id")).setStyle("SECONDARY").setDisabled(page === 0),
- new MessageButton().setCustomId("select").setEmoji(getEmojiByName("CONTROL.MENU", "id")).setStyle(selectPaneOpen ? "PRIMARY" : "SECONDARY").setDisabled(false),
- new MessageButton().setCustomId("right").setEmoji(getEmojiByName("CONTROL.RIGHT", "id")).setStyle("SECONDARY").setDisabled(page === pages.length - 1),
- new MessageButton().setCustomId("close").setEmoji(getEmojiByName("CONTROL.CROSS", "id")).setStyle("DANGER")
- ])]),
- fetchReply: true
+ components: components
});
} else {
let em = new Discord.MessageEmbed(pages[page].embed)
em.setDescription(em.description + "\n\n" + createPageIndicator(pages.length, page));
await m.edit({
embeds: [em],
- components: selectPane.concat([new MessageActionRow().addComponents([
- new MessageButton().setCustomId("left").setEmoji(getEmojiByName("CONTROL.LEFT", "id")).setStyle("SECONDARY").setDisabled(page === 0),
- new MessageButton().setCustomId("select").setEmoji(getEmojiByName("CONTROL.MENU", "id")).setStyle(selectPaneOpen ? "PRIMARY" : "SECONDARY").setDisabled(false),
- new MessageButton().setCustomId("right").setEmoji(getEmojiByName("CONTROL.RIGHT", "id")).setStyle("SECONDARY").setDisabled(page === pages.length - 1),
- new MessageButton().setCustomId("close").setEmoji(getEmojiByName("CONTROL.CROSS", "id")).setStyle("DANGER")
- ])]),
+ components: components,
fetchReply: true
});
}
diff --git a/src/automations/roleMenu.ts b/src/automations/roleMenu.ts
index c7073c5..cac15a5 100644
--- a/src/automations/roleMenu.ts
+++ b/src/automations/roleMenu.ts
@@ -1,18 +1,18 @@
import { Message, MessageButton } from "discord.js";
-import readConfig from '../utils/readConfig.js'
import generateEmojiEmbed from '../utils/generateEmojiEmbed.js'
import { MessageActionRow, MessageSelectMenu } from 'discord.js';
import getEmojiByName from "../utils/getEmojiByName.js";
+import client from "../utils/client.js";
export async function callback(interaction) {
- let config = await readConfig(interaction.guild.id);
- if (!config.roleMenu.enabled) await interaction.reply({embeds: [new generateEmojiEmbed()
+ let config = await client.database.read(interaction.guild.id);
+ if (!config.roleMenu.enabled) return await interaction.reply({embeds: [new generateEmojiEmbed()
.setTitle("Roles")
.setDescription("Self roles are currently disabled. Please contact a staff member or try again later.")
.setStatus("Danger")
.setEmoji("CONTROL.BLOCKCROSS")
], ephemeral: true})
- if (config.roleMenu.options.length === 0) await interaction.reply({embeds: [new generateEmojiEmbed()
+ if (config.roleMenu.options.length === 0) return await interaction.reply({embeds: [new generateEmojiEmbed()
.setTitle("Roles")
.setDescription("There are no roles available. Please contact a staff member or try again later.")
.setStatus("Danger")
@@ -136,7 +136,7 @@
.setDescription("Something went wrong and your roles were not added. Please contact a staff member or try again later.")
.setStatus("Danger")
.setEmoji("GUILD.RED")
- ]})
+ ], components: []})
}
await interaction.editReply({embeds: [new generateEmojiEmbed()
.setTitle("Roles")
diff --git a/src/automations/statsChannelAdd.ts b/src/automations/statsChannelAdd.ts
index 42ec580..01dfef1 100644
--- a/src/automations/statsChannelAdd.ts
+++ b/src/automations/statsChannelAdd.ts
@@ -1,19 +1,28 @@
-import log from '../utils/log.js'
-import readConfig from '../utils/readConfig.js'
import convertCurlyBracketString from '../utils/convertCurlyBracketString.js'
+import singleNotify from '../utils/singleNotify.js';
+import client from '../utils/client.js';
export async function callback(_, member) {
- let config = await readConfig(member.guild.id);
+ let config = await client.database.read(member.guild.id);
config.stats.forEach(async element => {
if (element.enabled) {
let string = element.text
if (!string) return
string = await convertCurlyBracketString(string, member.id, member.displayName, member.guild.name, member.guild.members)
-
- let channel = await member.client.channels.fetch(element.channel)
+ let channel;
+ try {
+ channel = await member.client.channels.fetch(element.channel)
+ } catch (error) { channel = null }
+ if (!channel) {
+ return singleNotify(
+ "statsChannelDeleted",
+ member.guild.id,
+ "One or more of your stats channels have been deleted. Please open the settings menu to change this.",
+ "Critical"
+ )
+ }
if (channel.guild.id !== member.guild.id) return
- if (!channel) return // TODO: Notify mods
try {
await channel.edit({ name: string })
} catch (err) {
@@ -21,4 +30,4 @@
}
}
});
-}
\ No newline at end of file
+}
diff --git a/src/automations/statsChannelRemove.ts b/src/automations/statsChannelRemove.ts
index 4b24768..fee0d2d 100644
--- a/src/automations/statsChannelRemove.ts
+++ b/src/automations/statsChannelRemove.ts
@@ -1,10 +1,9 @@
-import log from '../utils/log.js'
-import readConfig from '../utils/readConfig.js'
+import client from '../utils/client.js';
import convertCurlyBracketString from '../utils/convertCurlyBracketString.js'
import singleNotify from '../utils/singleNotify.js';
-export async function callback(interaction, member) {
- let config = await readConfig(member.guild.id);
+export async function callback(_, member) {
+ let config = await client.database.read(member.guild.id);
config.stats.forEach(async element => {
if (element.enabled) {
@@ -14,10 +13,10 @@
let channel = await member.client.channels.fetch(element.channel)
if (channel.guild.id !== member.guild.id) return
- if (!channel) return await singleNotify(interaction.client,
+ if (!channel) return singleNotify(
"statsChannelDeleted",
member.guild.id,
- "The stats channel has been deleted. Please set a new channel to use this feature.",
+ "One or more of your stats channels have been deleted. Please open the settings menu to change this.",
"Critical"
)
try {
diff --git a/src/automations/tickets/create.ts b/src/automations/tickets/create.ts
index fd0ae57..9642089 100644
--- a/src/automations/tickets/create.ts
+++ b/src/automations/tickets/create.ts
@@ -1,6 +1,6 @@
import Discord, { MessageActionRow, MessageButton } from "discord.js";
import { tickets, toHexArray } from "../../utils/calculate.js";
-import readConfig from "../../utils/readConfig.js";
+import client from "../../utils/client.js";
import generateEmojiEmbed from "../../utils/generateEmojiEmbed.js";
import getEmojiByName from "../../utils/getEmojiByName.js";
@@ -13,7 +13,7 @@
// @ts-ignore
const { log, NucleusColors, entry, renderUser, renderChannel, renderDelta } = interaction.client.logger
- let config = await readConfig(interaction.guild.id);
+ let config = await client.database.read(interaction.guild.id);
if (!config.tickets.enabled || !config.tickets.category) {
return await interaction.reply({embeds: [new generateEmojiEmbed()
.setTitle("Tickets are disabled")
@@ -63,8 +63,8 @@
.setEmoji(getEmojiByName(("TICKETS." + type.toString().toUpperCase()), "id"));
}
});
- for (let i = 0; i < formattedTicketTypes.length; i += 4) {
- splitFormattedTicketTypes.push(new MessageActionRow().addComponents(formattedTicketTypes.slice(i, i + 4)));
+ for (let i = 0; i < formattedTicketTypes.length; i += 5) {
+ splitFormattedTicketTypes.push(new MessageActionRow().addComponents(formattedTicketTypes.slice(i, i + 5)));
}
let m = await interaction.reply({embeds: [new generateEmojiEmbed()
.setTitle("Create Ticket")
@@ -97,8 +97,8 @@
.setDisabled(true)
}
});
- for (let i = 0; i < formattedTicketTypes.length; i += 4) {
- splitFormattedTicketTypes.push(new MessageActionRow().addComponents(formattedTicketTypes.slice(i, i + 4)));
+ for (let i = 0; i < formattedTicketTypes.length; i += 5) {
+ splitFormattedTicketTypes.push(new MessageActionRow().addComponents(formattedTicketTypes.slice(i, i + 5)));
}
component.update({embeds: [new generateEmojiEmbed()
.setTitle("Create Ticket")
diff --git a/src/automations/tickets/delete.ts b/src/automations/tickets/delete.ts
index 17d889a..1d577a4 100644
--- a/src/automations/tickets/delete.ts
+++ b/src/automations/tickets/delete.ts
@@ -1,18 +1,20 @@
import Discord, { MessageButton, MessageActionRow } from "discord.js";
+import client from "../../utils/client.js";
import generateEmojiEmbed from "../../utils/generateEmojiEmbed.js";
import getEmojiByName from "../../utils/getEmojiByName.js";
-import readConfig from "../../utils/readConfig.js";
export default async function (interaction) {
// @ts-ignore
const { log, NucleusColors, entry, renderUser, renderChannel, renderDelta } = interaction.client.logger
- let config = await readConfig(interaction.guild.id);
+ let config = await client.database.read(interaction.guild.id);
+ let thread = false; let threadChannel
+ if (interaction.channel instanceof Discord.ThreadChannel) thread = true; threadChannel = interaction.channel as Discord.ThreadChannel
let channel = (interaction.channel as Discord.TextChannel)
- if (!channel.parent || config.tickets.category != channel.parent.id) {
+ if (!channel.parent || config.tickets.category != channel.parent.id || (thread ? (threadChannel.parent.parent.id != config.tickets.category) : false)) {
return interaction.reply({embeds: [new generateEmojiEmbed()
.setTitle("Deleting Ticket...")
- .setDescription("This ticket is not in your tickets category, so cannot be deleted. You cannot run close in a thread.") // TODO bridge to cross later!
+ .setDescription("This ticket is not in your tickets category, so cannot be deleted. You cannot run close in a thread.")
.setStatus("Danger")
.setEmoji("CONTROL.BLOCKCROSS")
], ephemeral: true});
@@ -110,7 +112,7 @@
}
async function purgeByUser(member, guild) {
- let config = await readConfig(guild.id);
+ let config = await client.database.read(guild.id);
if (!config.tickets.category) return;
let tickets = guild.channels.cache.get(config.tickets.category);
if (!tickets) return;
diff --git a/src/automations/verify.ts b/src/automations/verify.ts
index 3d4e658..bf26505 100644
--- a/src/automations/verify.ts
+++ b/src/automations/verify.ts
@@ -1,9 +1,9 @@
-import Discord, { CommandInteraction, GuildMember } from "discord.js";
+import Discord, { GuildMember } from "discord.js";
import generateEmojiEmbed from "../utils/generateEmojiEmbed.js";
-import readConfig from "../utils/readConfig.js";
import fetch from "node-fetch";
import { TestString, NSFWCheck } from "../automations/unscan.js";
import createPageIndicator from "../utils/createPageIndicator.js";
+import client from "../utils/client.js";
function step(i) {
return "\n\n" + createPageIndicator(5, i);
@@ -18,7 +18,13 @@
.setStatus("Danger")
.setEmoji("NUCLEUS.LOADING")
], ephemeral: true, fetchReply: true});
- let config = await readConfig(interaction.guild.id);
+ let config = await client.database.read(interaction.guild.id);
+ if ((!config.verify.enabled ) || (!config.verify.role)) return interaction.editReply({embeds: [new generateEmojiEmbed()
+ .setTitle("Verify")
+ .setDescription(`Verify is not enabled on this server`)
+ .setStatus("Danger")
+ .setEmoji("CONTROL.BLOCKCROSS")
+ ], ephemeral: true, fetchReply: true});
if ((interaction.member as GuildMember).roles.cache.has(config.verify.role)) {
return await interaction.editReply({embeds: [new generateEmojiEmbed()
.setTitle("Verify")
@@ -34,7 +40,7 @@
.setEmoji("NUCLEUS.LOADING")
]});
try {
- let status = await fetch(`https://clicks.codes/`).then(res => res.status);
+ let status = await fetch(client.config.baseUrl).then(res => res.status);
if (status != 200) {
return await interaction.editReply({embeds: [new generateEmojiEmbed()
.setTitle("Verify")
@@ -53,7 +59,7 @@
new Discord.MessageButton()
.setLabel("Check webpage")
.setStyle("LINK")
- .setURL("https://clicks.codes/"),
+ .setURL(client.config.baseUrl),
new Discord.MessageButton()
.setLabel("Support")
.setStyle("LINK")
@@ -132,7 +138,6 @@
], components: [new Discord.MessageActionRow().addComponents([new Discord.MessageButton()
.setLabel("Verify")
.setStyle("LINK")
- // .setURL(`https://clicks.codes/nucleus/verify?code=${code}`)
- .setURL(`https://insulation-coin-hoping-nevertheless.trycloudflare.com/nucleus/verify?code=${code}`)
+ .setURL(`${client.config.baseUrl}/nucleus/verify?code=${code}`)
])]});
}
diff --git a/src/automations/welcome.ts b/src/automations/welcome.ts
index 84a87ec..11c4844 100644
--- a/src/automations/welcome.ts
+++ b/src/automations/welcome.ts
@@ -1,10 +1,10 @@
import log from '../utils/log.js'
-import readConfig from '../utils/readConfig.js'
import convertCurlyBracketString from '../utils/convertCurlyBracketString.js'
+import client from '../utils/client.js';
export async function callback(_, member) {
if (member.bot) return
- let config = await readConfig(member.guild.id);
+ let config = await client.database.read(member.guild.id);
if (!config.welcome.enabled) return
if (!config.welcome.verificationRequired.role) {
diff --git a/src/commands/categorisationTest.ts b/src/commands/categorisationTest.ts
index 2852a2b..33f99e9 100644
--- a/src/commands/categorisationTest.ts
+++ b/src/commands/categorisationTest.ts
@@ -60,7 +60,6 @@
.setCustomId("category")
.setMinValues(0)
.setMaxValues(1)
- // .setMaxValues(Object.keys(types).length)
.setOptions(Object.keys(types).map(type => {return {label: toCapitals(type), value: type}}))
])]});
}
diff --git a/src/commands/mod/ban.ts b/src/commands/mod/ban.ts
index 1e17e53..8b17db3 100644
--- a/src/commands/mod/ban.ts
+++ b/src/commands/mod/ban.ts
@@ -4,8 +4,8 @@
import confirmationMessage from "../../utils/confirmationMessage.js";
import generateEmojiEmbed from "../../utils/generateEmojiEmbed.js";
import keyValueList from "../../utils/generateKeyValueList.js";
-import readConfig from '../../utils/readConfig.js';
import addPlurals from "../../utils/plurals.js";
+import client from "../../utils/client.js";
const command = (builder: SlashCommandSubcommandBuilder) =>
builder
@@ -31,13 +31,11 @@
+ `${addPlurals(interaction.options.getInteger("delete") ? interaction.options.getInteger("delete") : 0, "day")} of messages will be deleted\n\n`
+ `Are you sure you want to ban <@!${(interaction.options.getMember("user") as GuildMember).id}>?`)
.setColor("Danger")
-// pluralize("day", interaction.options.getInteger("delete"))
-// const pluralize = (word: string, count: number) => { return count === 1 ? word : word + "s" }
.send()
if (confirmation.success) {
let dmd = false
let dm;
- let config = await readConfig(interaction.guild.id);
+ let config = await client.database.read(interaction.guild.id);
try {
if (interaction.options.getString("notify") != "no") {
dm = await (interaction.options.getMember("user") as GuildMember).send({
diff --git a/src/commands/mod/kick.ts b/src/commands/mod/kick.ts
index 9dc447b..20fbc01 100644
--- a/src/commands/mod/kick.ts
+++ b/src/commands/mod/kick.ts
@@ -5,7 +5,7 @@
import confirmationMessage from "../../utils/confirmationMessage.js";
import generateEmojiEmbed from "../../utils/generateEmojiEmbed.js";
import keyValueList from "../../utils/generateKeyValueList.js";
-import readConfig from '../../utils/readConfig.js'
+import client from "../../utils/client.js";
const command = (builder: SlashCommandSubcommandBuilder) =>
builder
@@ -29,13 +29,11 @@
+ `The user **will${interaction.options.getString("notify") === "no" ? ' not' : ''}** be notified\n\n`
+ `Are you sure you want to kick <@!${(interaction.options.getMember("user") as GuildMember).id}>?`)
.setColor("Danger")
-// pluralize("day", interaction.options.getInteger("delete"))
-// const pluralize = (word: string, count: number) => { return count === 1 ? word : word + "s" }
.send()
if (confirmation.success) {
let dmd = false
let dm;
- let config = await readConfig(interaction.guild.id);
+ let config = await client.database.read(interaction.guild.id);
try {
if (interaction.options.getString("notify") != "no") {
dm = await (interaction.options.getMember("user") as GuildMember).send({
diff --git a/src/commands/mod/mute.ts b/src/commands/mod/mute.ts
index b2cc94e..854f38f 100644
--- a/src/commands/mod/mute.ts
+++ b/src/commands/mod/mute.ts
@@ -6,7 +6,7 @@
import confirmationMessage from "../../utils/confirmationMessage.js";
import keyValueList from "../../utils/generateKeyValueList.js";
import humanizeDuration from "humanize-duration";
-import readConfig from "../../utils/readConfig.js";
+import client from "../../utils/client.js";
const command = (builder: SlashCommandSubcommandBuilder) =>
builder
@@ -21,7 +21,7 @@
.addStringOption(option => option.setName("notify").setDescription("If the user should get a message when they are muted | Default yes").setRequired(false)
.addChoices([["Yes", "yes"], ["No", "no"]]))
-const callback = async (interaction: CommandInteraction) => {
+const callback = async (interaction: CommandInteraction): Promise<any> => {
// @ts-ignore
const { log, NucleusColors, renderUser, entry } = interaction.client.logger
const user = interaction.options.getMember("user") as GuildMember
@@ -32,7 +32,7 @@
minutes: interaction.options.getInteger("minutes") || 0,
seconds: interaction.options.getInteger("seconds") || 0
}
- let config = await readConfig(interaction.guild.id)
+ let config = await client.database.read(interaction.guild.id)
let serverSettingsDescription = (config.moderation.mute.timeout ? "given a timeout" : "")
if (config.moderation.mute.role) serverSettingsDescription += (serverSettingsDescription ? " and " : "") + `given the <@&${config.moderation.mute.role}> role`
@@ -132,13 +132,11 @@
+ `The user **will${interaction.options.getString("notify") === "no" ? ' not' : ''}** be notified\n\n`
+ `Are you sure you want to mute <@!${(interaction.options.getMember("user") as GuildMember).id}>?`)
.setColor("Danger")
-// pluralize("day", interaction.options.getInteger("delete"))
-// const pluralize = (word: string, count: number) => { return count === 1 ? word : word + "s" }
.send(true)
if (confirmation.success) {
let dmd = false
let dm;
- let config = await readConfig(interaction.guild.id);
+ let config = await client.database.read(interaction.guild.id);
try {
if (interaction.options.getString("notify") != "no") {
dm = await (interaction.options.getMember("user") as GuildMember).send({
diff --git a/src/commands/mod/nick.ts b/src/commands/mod/nick.ts
index 6a0410a..96738c6 100644
--- a/src/commands/mod/nick.ts
+++ b/src/commands/mod/nick.ts
@@ -4,7 +4,6 @@
import confirmationMessage from "../../utils/confirmationMessage.js";
import generateEmojiEmbed from "../../utils/generateEmojiEmbed.js";
import keyValueList from "../../utils/generateKeyValueList.js";
-import readConfig from '../../utils/readConfig.js';
import { create, areTicketsEnabled } from "../../automations/createModActionTicket.js";
const command = (builder: SlashCommandSubcommandBuilder) =>
@@ -31,10 +30,8 @@
.setColor("Danger")
.addCustomBoolean(
"Create appeal ticket", !(await areTicketsEnabled(interaction.guild.id)),
- async () => await create(interaction.guild, interaction.options.getUser("user"), interaction.user, interaction.client),
+ async () => await create(interaction.guild, interaction.options.getUser("user"), interaction.user, interaction.options.getString("reason")),
"An appeal ticket will be created when Confirm is clicked")
-// pluralize("day", interaction.options.getInteger("delete"))
-// const pluralize = (word: string, count: number) => { return count === 1 ? word : word + "s" }
.send()
if (confirmation.success) {
let dmd = false
diff --git a/src/commands/mod/purge.ts b/src/commands/mod/purge.ts
index 924e507..8e6762e 100644
--- a/src/commands/mod/purge.ts
+++ b/src/commands/mod/purge.ts
@@ -19,7 +19,7 @@
.addUserOption(option => option.setName("user").setDescription("The user to purge messages from").setRequired(false))
.addStringOption(option => option.setName("reason").setDescription("The reason for the purge").setRequired(false))
-const callback = async (interaction: CommandInteraction) => {
+const callback = async (interaction: CommandInteraction): Promise<any> => {
let user = interaction.options.getMember("user") as GuildMember ?? null
let channel = (interaction.channel as GuildChannel)
if (!(["GUILD_TEXT", "GUILD_NEWS", "GUILD_NEWS_THREAD", "GUILD_PUBLIC_THREAD", "GUILD_PRIVATE_THREAD"].includes(channel.type.toString()))) {
@@ -205,8 +205,6 @@
"reason": `\n> ${interaction.options.getString("reason") ? interaction.options.getString("reason") : "*No reason provided*"}`
}))
.setColor("Danger")
- // pluralize("day", interaction.options.getInteger("amount"))
- // const pluralize = (word: string, count: number) => { return count === 1 ? word : word + "s" }
.send()
if (confirmation.success) {
let messages;
diff --git a/src/commands/mod/slowmode.ts b/src/commands/mod/slowmode.ts
index b91f065..2498746 100644
--- a/src/commands/mod/slowmode.ts
+++ b/src/commands/mod/slowmode.ts
@@ -29,8 +29,6 @@
})
+ `Are you sure you want to set the slowmode in this channel?`)
.setColor("Danger")
-// pluralize("day", interaction.options.getInteger("delete"))
-// const pluralize = (word: string, count: number) => { return count === 1 ? word : word + "s" }
.send()
if (confirmation.success) {
try {
@@ -39,7 +37,7 @@
await interaction.editReply({embeds: [new generateEmojiEmbed()
.setEmoji("CHANNEL.SLOWMODE.RED")
.setTitle(`Slowmode`)
- .setDescription("An error occurred while setting the slowmode")
+ .setDescription("Something went wrong while setting the slowmode")
.setStatus("Danger")
], components: []})
}
diff --git a/src/commands/mod/softban.ts b/src/commands/mod/softban.ts
index 29d3bef..5a01287 100644
--- a/src/commands/mod/softban.ts
+++ b/src/commands/mod/softban.ts
@@ -4,8 +4,8 @@
import confirmationMessage from "../../utils/confirmationMessage.js";
import generateEmojiEmbed from "../../utils/generateEmojiEmbed.js";
import keyValueList from "../../utils/generateKeyValueList.js";
-import readConfig from '../../utils/readConfig.js';
-import addPlurals from '../../utils/plurals.js';
+import client from "../../utils/client.js";
+import addPlural from "../../utils/plurals.js";
const command = (builder: SlashCommandSubcommandBuilder) =>
builder
@@ -28,15 +28,13 @@
"reason": `\n> ${interaction.options.getString("reason") ? interaction.options.getString("reason") : "*No reason provided*"}`
})
+ `The user **will${interaction.options.getString("notify") === "no" ? ' not' : ''}** be notified\n`
- + `${addPlurals(interaction.options.getInteger("delete") ? interaction.options.getInteger("delete") : 0, "day")} of messages will be deleted\n\n`
+ + `${addPlural(interaction.options.getInteger("delete") ? interaction.options.getInteger("delete") : 0, "day")} of messages will be deleted\n\n`
+ `Are you sure you want to softban <@!${(interaction.options.getMember("user") as GuildMember).id}>?`)
.setColor("Danger")
-// pluralize("day", interaction.options.getInteger("delete"))
-// const pluralize = (word: string, count: number) => { return count === 1 ? word : word + "s" }
.send()
if (confirmation.success) {
let dmd = false;
- let config = await readConfig(interaction.guild.id);
+ let config = await client.database.read(interaction.guild.id);
try {
if (interaction.options.getString("notify") != "no") {
await (interaction.options.getMember("user") as GuildMember).send({
diff --git a/src/commands/mod/unban.ts b/src/commands/mod/unban.ts
index 8231752..f201142 100644
--- a/src/commands/mod/unban.ts
+++ b/src/commands/mod/unban.ts
@@ -11,7 +11,7 @@
.setDescription("Unbans a user")
.addStringOption(option => option.setName("user").setDescription("The user to unban (Username or ID)").setRequired(true))
-const callback = async (interaction: CommandInteraction) => { // TODO: User search
+const callback = async (interaction: CommandInteraction) => { // TODO: User search UI
let bans = await interaction.guild.bans.fetch()
let user = interaction.options.getString("user")
let resolved = bans.find(ban => ban.user.id == user)
diff --git a/src/commands/mod/unmute.ts b/src/commands/mod/unmute.ts
index b2f8234..2a98c54 100644
--- a/src/commands/mod/unmute.ts
+++ b/src/commands/mod/unmute.ts
@@ -27,8 +27,6 @@
+ `The user **will${interaction.options.getString("notify") === "yes" ? '' : ' not'}** be notified\n\n`
+ `Are you sure you want to unmute <@!${(interaction.options.getMember("user") as GuildMember).id}>?`)
.setColor("Danger")
-// pluralize("day", interaction.options.getInteger("delete"))
-// const pluralize = (word: string, count: number) => { return count === 1 ? word : word + "s" }
.send()
if (confirmation.success) {
let dmd = false
diff --git a/src/commands/mod/unnamed.ts b/src/commands/mod/unnamed.ts
deleted file mode 100644
index ca0bcef..0000000
--- a/src/commands/mod/unnamed.ts
+++ /dev/null
@@ -1,233 +0,0 @@
-import Discord, { CommandInteraction, GuildMember, MessageActionRow } from "discord.js";
-import { SlashCommandSubcommandBuilder } from "@discordjs/builders";
-import { WrappedCheck } from "jshaiku";
-import generateEmojiEmbed from "../../utils/generateEmojiEmbed.js";
-import getEmojiByName from "../../utils/getEmojiByName.js";
-import confirmationMessage from "../../utils/confirmationMessage.js";
-import keyValueList from "../../utils/generateKeyValueList.js";
-import humanizeDuration from "humanize-duration";
-import { create, areTicketsEnabled } from "../../automations/createModActionTicket.js";
-import readConfig from '../../utils/readConfig.js'
-
-const command = (builder: SlashCommandSubcommandBuilder) =>
- builder
- .setName("unnamed")
- .setDescription("Gives a user a role")
- .addUserOption(option => option.setName("user").setDescription("The user to UNNAMED").setRequired(true)) // TODO
- .addIntegerOption(option => option.setName("days").setDescription("The number of days to UNNAMED the user for | Default 0").setMinValue(0).setMaxValue(27).setRequired(false))
- .addIntegerOption(option => option.setName("hours").setDescription("The number of hours to UNNAMED the user for | Default 0").setMinValue(0).setMaxValue(23).setRequired(false))
- .addIntegerOption(option => option.setName("minutes").setDescription("The number of minutes to UNNAMED the user for | Default 0").setMinValue(0).setMaxValue(59).setRequired(false))
- .addIntegerOption(option => option.setName("seconds").setDescription("The number of seconds to UNNAMED the user for | Default 0").setMinValue(0).setMaxValue(59).setRequired(false))
- .addStringOption(option => option.setName("reason").setDescription("The reason for the UNNAMED").setRequired(false))
- .addStringOption(option => option.setName("notify").setDescription("If the user should get a message when they are UNNAMED | Default yes").setRequired(false)
- .addChoices([["Yes", "yes"], ["No", "no"]]))
-
-const callback = async (interaction: CommandInteraction) => {
- // @ts-ignore
- const { log, NucleusColors, renderUser, entry } = interaction.client.logger
- let config = await readConfig(interaction.guild.id);
- const user = interaction.options.getMember("user") as GuildMember
- const reason = interaction.options.getString("reason")
- const time = {
- days: interaction.options.getInteger("days") || 0,
- hours: interaction.options.getInteger("hours") || 0,
- minutes: interaction.options.getInteger("minutes") || 0,
- seconds: interaction.options.getInteger("seconds") || 0
- }
- let muteTime = (time.days * 24 * 60 * 60) + (time.hours * 60 * 60) + (time.minutes * 60) + time.seconds
- if (muteTime == 0) {
- let m = await interaction.reply({embeds: [
- new generateEmojiEmbed()
- .setEmoji("PUNISH.MUTE.GREEN") // TODO
- .setTitle("UNNAMED")
- .setDescription("How long should the user be UNNAMED")
- .setStatus("Success")
- ], components: [
- new MessageActionRow().addComponents([
- new Discord.MessageButton()
- .setCustomId("1m")
- .setLabel("1 Minute")
- .setStyle("SECONDARY"),
- new Discord.MessageButton()
- .setCustomId("10m")
- .setLabel("10 Minutes")
- .setStyle("SECONDARY"),
- new Discord.MessageButton()
- .setCustomId("30m")
- .setLabel("30 Minutes")
- .setStyle("SECONDARY"),
- new Discord.MessageButton()
- .setCustomId("1h")
- .setLabel("1 Hour")
- .setStyle("SECONDARY")
- ]),
- new MessageActionRow().addComponents([
- new Discord.MessageButton()
- .setCustomId("6h")
- .setLabel("6 Hours")
- .setStyle("SECONDARY"),
- new Discord.MessageButton()
- .setCustomId("12h")
- .setLabel("12 Hours")
- .setStyle("SECONDARY"),
- new Discord.MessageButton()
- .setCustomId("1d")
- .setLabel("1 Day")
- .setStyle("SECONDARY"),
- new Discord.MessageButton()
- .setCustomId("1w")
- .setLabel("1 Week")
- .setStyle("SECONDARY")
- ]),
- new MessageActionRow().addComponents([
- new Discord.MessageButton()
- .setCustomId("cancel")
- .setLabel("Cancel")
- .setStyle("DANGER")
- .setEmoji(getEmojiByName("CONTROL.CROSS", "id"))
- ])
- ], ephemeral: true, fetchReply: true})
- let component;
- try {
- component = await (m as Discord.Message).awaitMessageComponent({filter: (m) => m.user.id === interaction.user.id, time: 2.5 * 60 * 1000});
- } catch { return }
- component.deferUpdate();
- if (component.customId == "cancel") return interaction.editReply({embeds: [new generateEmojiEmbed()
- .setEmoji("PUNISH.MUTE.RED") // TODO
- .setTitle("UNNAMED")
- .setDescription("UNNAMED cancelled")
- .setStatus("Danger")
- ]})
- switch (component.customId) {
- case "1m": { muteTime = 60; break; }
- case "10m": { muteTime = 60 * 10; break; }
- case "30m": { muteTime = 60 * 30; break; }
- case "1h": { muteTime = 60 * 60; break; }
- case "6h": { muteTime = 60 * 60 * 6; break; }
- case "12h": { muteTime = 60 * 60 * 12; break; }
- case "1d": { muteTime = 60 * 60 * 24; break; }
- case "1w": { muteTime = 60 * 60 * 24 * 7; break; }
- }
- } else {
- await interaction.reply({embeds: [
- new generateEmojiEmbed()
- .setEmoji("PUNISH.MUTE.GREEN") // TODO
- .setTitle("UNNAMED")
- .setDescription("Loading...")
- .setStatus("Success")
- ], ephemeral: true, fetchReply: true})
- }
- // TODO:[Modals] Replace this with a modal
- let confirmation = await new confirmationMessage(interaction)
- .setEmoji("PUNISH.MUTE.RED") // TODO
- .setTitle("UNNAMED")
- .setDescription(keyValueList({
- "user": `<@!${user.id}> (${user.user.username})`,
- "time": `${humanizeDuration(muteTime * 1000, {round: true})}`,
- "reason": `\n> ${reason ? reason : "*No reason provided*"}`
- })
- + `The user **will${interaction.options.getString("notify") === "no" ? ' not' : ''}** be notified\n\n`
- + `Are you sure you want to mute <@!${(interaction.options.getMember("user") as GuildMember).id}>?`) // TODO
- .setColor("Danger")
- .addCustomBoolean(
- "Create appeal ticket", !(await areTicketsEnabled(interaction.guild.id)),
- async () => await create(interaction.guild, interaction.options.getUser("user"), interaction.user, interaction.client),
- "An appeal ticket will be created when Confirm is clicked")
-// pluralize("day", interaction.options.getInteger("delete"))
-// const pluralize = (word: string, count: number) => { return count === 1 ? word : word + "s" }
- .send()
- if (confirmation.success) {
- let dmd = false
- let dm;
- try {
- if (interaction.options.getString("notify") != "no") {
- dm = await (interaction.options.getMember("user") as GuildMember).send({
- embeds: [new generateEmojiEmbed()
- .setEmoji("PUNISH.MUTE.RED") // TODO
- .setTitle("UNNAMED")
- .setDescription(`You have been muted in ${interaction.guild.name}` + // TODO
- (interaction.options.getString("reason") ? ` for:\n> ${interaction.options.getString("reason")}` : ".\n\n" +
- `You will be unmuted at: <t:${Math.round((new Date).getTime() / 1000) + muteTime}:D> at <t:${Math.round((new Date).getTime() / 1000) + muteTime}:T> (<t:${Math.round((new Date).getTime() / 1000) + muteTime}:R>)`)) // TODO
- .setStatus("Danger")
- ]
- })
- dmd = true
- }
- } catch {}
- try {
- await ((interaction.options.getMember("user") as GuildMember).roles.add(interaction.guild.roles.cache.find((r) => r.id === config.moderation.role.role)))
- // TODO: Store when to remove the role
- } catch {
- await interaction.editReply({embeds: [new generateEmojiEmbed()
- .setEmoji("PUNISH.MUTE.RED")
- .setTitle(`Mute`)
- .setDescription("Something went wrong and the user was not UNNAMED")
- .setStatus("Danger")
- ], components: []})
- if (dmd) await dm.delete()
- return
- }
- let failed = (dmd == false && interaction.options.getString("notify") != "no")
- await interaction.editReply({embeds: [new generateEmojiEmbed()
- .setEmoji(`PUNISH.MUTE.${failed ? "YELLOW" : "GREEN"}`) // TODO
- .setTitle(`Mute`) // TODO
- .setDescription("The member was muted" + (failed ? ", but could not be notified" : "")) // TODO
- .setStatus(failed ? "Warning" : "Success")
- ], components: []})
- let data = {
- meta:{
- type: 'memberMute', // TODO
- displayName: 'Member Muted', // TODO
- calculateType: 'guildMemberPunish',
- color: NucleusColors.yellow,
- emoji: 'PUNISH.WARN.YELLOW', // TODO
- timestamp: new Date().getTime()
- },
- list: {
- user: entry((interaction.options.getMember("user") as GuildMember).user.id, renderUser((interaction.options.getMember("user") as GuildMember).user)),
- mutedBy: entry(interaction.member.user.id, renderUser(interaction.member.user)), // TODO
- time: entry(muteTime, `${humanizeDuration(muteTime * 1000, {round: true})}`),
- reason: (interaction.options.getString("reason") ? `\n> ${interaction.options.getString("reason")}` : "No reason provided")
- },
- hidden: {
- guild: interaction.guild.id
- }
- }
- log(data, interaction.client);
- } else {
- await interaction.editReply({embeds: [new generateEmojiEmbed()
- .setEmoji("PUNISH.MUTE.GREEN") // TODO
- .setTitle(`Mute`) // TODO
- .setDescription("No changes were made")
- .setStatus("Success")
- ], components: []})
- }
-}
-
-const check = (interaction: CommandInteraction, defaultCheck: WrappedCheck) => {
- let member = (interaction.member as GuildMember)
- let me = (interaction.guild.me as GuildMember)
- let apply = (interaction.options.getMember("user") as GuildMember)
- if (member == null || me == null || apply == null) throw "That member is not in the server"
- let memberPos = member.roles ? member.roles.highest.position : 0
- let mePos = me.roles ? me.roles.highest.position : 0
- let applyPos = apply.roles ? apply.roles.highest.position : 0
- // Check if Nucleus can UNNAMED the member
- if (! (mePos > applyPos)) throw "I do not have a role higher than that member"
- // Check if Nucleus has permission to UNNAMED
- if (! me.permissions.has("MANAGE_ROLES")) throw "I do not have the `manage_roles` permission";
- // Do not allow the user to have admin or be the owner
- if (apply.permissions.has("ADMINISTRATOR") || apply.id == interaction.guild.ownerId) throw "You cannot mute an admin or the owner"
- // Do not allow muting Nucleus
- if (member.id == me.id) throw "I cannot UNNAMED myself"
- // Allow the owner to UNNAMED anyone
- if (member.id == interaction.guild.ownerId) return true
- // Check if the user has moderate_members permission
- if (! member.permissions.has("MODERATE_MEMBERS")) throw "You do not have the `moderate_members` permission";
- // Check if the user is below on the role list
- if (! (memberPos > applyPos)) throw "You do not have a role higher than that member"
- // Allow UNNAMED
- return true
-}
-
-export { command, callback, check };
\ No newline at end of file
diff --git a/src/commands/mod/warn.ts b/src/commands/mod/warn.ts
index 715777e..46e2871 100644
--- a/src/commands/mod/warn.ts
+++ b/src/commands/mod/warn.ts
@@ -16,7 +16,7 @@
.addChoices([["Yes", "yes"], ["No", "no"]])
)
-const callback = async (interaction: CommandInteraction) => {
+const callback = async (interaction: CommandInteraction): Promise<any> => {
// @ts-ignore
const { log, NucleusColors, renderUser, entry } = interaction.client.logger
// TODO:[Modals] Replace this with a modal
@@ -32,10 +32,8 @@
.setColor("Danger")
.addCustomBoolean(
"Create appeal ticket", !(await areTicketsEnabled(interaction.guild.id)),
- async () => await create(interaction.guild, interaction.options.getUser("user"), interaction.user, interaction.client),
+ async () => await create(interaction.guild, interaction.options.getUser("user"), interaction.user, interaction.options.getString("reason")),
"An appeal ticket will be created when Confirm is clicked")
-// pluralize("day", interaction.options.getInteger("delete"))
-// const pluralize = (word: string, count: number) => { return count === 1 ? word : word + "s" }
.send()
if (confirmation.success) {
let dmd = false
diff --git a/src/commands/settings/automation.ts b/src/commands/settings/automation.ts
deleted file mode 100644
index 0053f76..0000000
--- a/src/commands/settings/automation.ts
+++ /dev/null
@@ -1,20 +0,0 @@
-import { CommandInteraction } from "discord.js";
-import { SlashCommandSubcommandBuilder } from "@discordjs/builders";
-import { WrappedCheck } from "jshaiku";
-
-const command = (builder: SlashCommandSubcommandBuilder) =>
- builder
- .setName("automation")
- .setDescription("Shows all automation options")
-
-const callback = (interaction: CommandInteraction) => {
- interaction.reply("This command is not yet finished [settings/automation]");
-}
-
-const check = (interaction: CommandInteraction, defaultCheck: WrappedCheck) => {
- return true;
-}
-
-export { command };
-export { callback };
-export { check };
\ No newline at end of file
diff --git a/src/commands/settings/log/channel.ts b/src/commands/settings/log/channel.ts
deleted file mode 100644
index 5843438..0000000
--- a/src/commands/settings/log/channel.ts
+++ /dev/null
@@ -1,20 +0,0 @@
-import { CommandInteraction } from "discord.js";
-import { SlashCommandSubcommandBuilder } from "@discordjs/builders";
-import { WrappedCheck } from "jshaiku";
-
-const command = (builder: SlashCommandSubcommandBuilder) =>
- builder
- .setName("channel")
- .setDescription("Sets the log channel")
-
-const callback = (interaction: CommandInteraction) => {
- interaction.reply("This command is not yet finished [settings/log/channel]");
-}
-
-const check = (interaction: CommandInteraction, defaultCheck: WrappedCheck) => {
- return true;
-}
-
-export { command };
-export { callback };
-export { check };
\ No newline at end of file
diff --git a/src/commands/settings/log/ignore.ts b/src/commands/settings/log/ignore.ts
deleted file mode 100644
index 1b4d245..0000000
--- a/src/commands/settings/log/ignore.ts
+++ /dev/null
@@ -1,20 +0,0 @@
-import { CommandInteraction } from "discord.js";
-import { SlashCommandSubcommandBuilder } from "@discordjs/builders";
-import { WrappedCheck } from "jshaiku";
-
-const command = (builder: SlashCommandSubcommandBuilder) =>
- builder
- .setName("ignore")
- .setDescription("Sets which users, channels and roles should be ignored")
-
-const callback = (interaction: CommandInteraction) => {
- interaction.reply("This command is not yet finished [settings/log/ignore]");
-}
-
-const check = (interaction: CommandInteraction, defaultCheck: WrappedCheck) => {
- return true;
-}
-
-export { command };
-export { callback };
-export { check };
\ No newline at end of file
diff --git a/src/commands/settings/log/ignored.ts b/src/commands/settings/log/ignored.ts
deleted file mode 100644
index bf4a30c..0000000
--- a/src/commands/settings/log/ignored.ts
+++ /dev/null
@@ -1,20 +0,0 @@
-import { CommandInteraction } from "discord.js";
-import { SlashCommandSubcommandBuilder } from "@discordjs/builders";
-import { WrappedCheck } from "jshaiku";
-
-const command = (builder: SlashCommandSubcommandBuilder) =>
- builder
- .setName("ignored")
- .setDescription("Gets the ignored users, channels and roles")
-
-const callback = (interaction: CommandInteraction) => {
- interaction.reply("This command is not yet finished [settings/log/ignored]");
-}
-
-const check = (interaction: CommandInteraction, defaultCheck: WrappedCheck) => {
- return true;
-}
-
-export { command };
-export { callback };
-export { check };
\ No newline at end of file
diff --git a/src/commands/settings/log/_meta.ts b/src/commands/settings/logs/_meta.ts
similarity index 100%
rename from src/commands/settings/log/_meta.ts
rename to src/commands/settings/logs/_meta.ts
diff --git a/src/commands/settings/logs/channel.ts b/src/commands/settings/logs/channel.ts
new file mode 100644
index 0000000..18ed8d9
--- /dev/null
+++ b/src/commands/settings/logs/channel.ts
@@ -0,0 +1,129 @@
+import { ChannelType } from 'discord-api-types';
+import Discord, { CommandInteraction, MessageActionRow, MessageButton } from "discord.js";
+import generateEmojiEmbed from "../../../utils/generateEmojiEmbed.js";
+import confirmationMessage from "../../../utils/confirmationMessage.js";
+import getEmojiByName from "../../../utils/getEmojiByName.js";
+import { SlashCommandSubcommandBuilder } from "@discordjs/builders";
+import { WrappedCheck } from "jshaiku";
+import client from "../../../utils/client.js";
+
+const command = (builder: SlashCommandSubcommandBuilder) =>
+ builder
+ .setName("channel")
+ .setDescription("Sets or shows the log channel")
+ .addChannelOption(option => option.setName("channel").setDescription("The channel to set the log channel to").addChannelTypes([
+ ChannelType.GuildNews, ChannelType.GuildText
+ ]))
+
+const callback = async (interaction: CommandInteraction): Promise<any> => {
+ let m;
+ m = await interaction.reply({embeds: [new generateEmojiEmbed()
+ .setTitle("Loading")
+ .setStatus("Danger")
+ .setEmoji("NUCLEUS.LOADING")
+ ], ephemeral: true, fetchReply: true});
+ if (interaction.options.getChannel("channel")) {
+ let channel
+ try {
+ channel = interaction.options.getChannel("channel")
+ } catch {
+ return await interaction.editReply({embeds: [new generateEmojiEmbed()
+ .setEmoji("CHANNEL.TEXT.DELETE")
+ .setTitle("Log Channel")
+ .setDescription("The channel you provided is not a valid channel")
+ .setStatus("Danger")
+ ]})
+ }
+ channel = channel as Discord.TextChannel
+ if (channel.guild.id != interaction.guild.id) {
+ return interaction.editReply({embeds: [new generateEmojiEmbed()
+ .setTitle("Log Channel")
+ .setDescription(`You must choose a channel in this server`)
+ .setStatus("Danger")
+ .setEmoji("CHANNEL.TEXT.DELETE")
+ ]});
+ }
+ let confirmation = await new confirmationMessage(interaction)
+ .setEmoji("CHANNEL.TEXT.EDIT")
+ .setTitle("Log Channel")
+ .setDescription(`Are you sure you want to set the log channel to <#${channel.id}>?`)
+ .setColor("Warning")
+ .setInverted(true)
+ .send(true)
+ if (confirmation.success) {
+ try {
+ await client.database.write(interaction.guild.id, {"logging.logs.channel": channel.id})
+ } catch (e) {
+ console.log(e)
+ return interaction.editReply({embeds: [new generateEmojiEmbed()
+ .setTitle("Log Channel")
+ .setDescription(`Something went wrong and the log channel could not be set`)
+ .setStatus("Danger")
+ .setEmoji("CHANNEL.TEXT.DELETE")
+ ], components: []});
+ }
+ } else {
+ return interaction.editReply({embeds: [new generateEmojiEmbed()
+ .setTitle("Log Channel")
+ .setDescription(`No changes were made`)
+ .setStatus("Success")
+ .setEmoji("CHANNEL.TEXT.CREATE")
+ ], components: []});
+ }
+ }
+ let clicks = 0;
+ let data = await client.database.read(interaction.guild.id);
+ let channel = data.logging.logs.channel;
+ while (true) {
+ await interaction.editReply({embeds: [new generateEmojiEmbed()
+ .setTitle("Log channel")
+ .setDescription(channel ? `Your log channel is currently set to <#${channel}>` : "This server does not have a log channel")
+ .setStatus("Success")
+ .setEmoji("CHANNEL.TEXT.CREATE")
+ ], components: [new MessageActionRow().addComponents([new MessageButton()
+ .setCustomId("clear")
+ .setLabel(clicks ? "Click again to confirm" : "Reset channel")
+ .setEmoji(getEmojiByName(clicks ? "TICKETS.ISSUE" : "CONTROL.CROSS", "id"))
+ .setStyle("DANGER")
+ .setDisabled(!channel)
+ ])]});
+ let i;
+ try {
+ i = await m.awaitMessageComponent({time: 600000});
+ } catch(e) { break }
+ i.deferUpdate()
+ if (i.component.customId == "clear") {
+ clicks += 1;
+ if (clicks == 2) {
+ clicks = 0;
+ await client.database.write(interaction.guild.id, {}, ["logging.logs.channel"])
+ channel = undefined;
+ }
+ } else {
+ break
+ }
+ }
+ await interaction.editReply({embeds: [new generateEmojiEmbed()
+ .setTitle("Log channel")
+ .setDescription(channel ? `Your log channel is currently set to <#${channel}>` : "This server does not have a log channel")
+ .setStatus("Success")
+ .setEmoji("CHANNEL.TEXT.CREATE")
+ .setFooter({text: "Message closed"})
+ ], components: [new MessageActionRow().addComponents([new MessageButton()
+ .setCustomId("clear")
+ .setLabel("Clear")
+ .setEmoji(getEmojiByName("CONTROL.CROSS", "id"))
+ .setStyle("SECONDARY")
+ .setDisabled(true)
+ ])]});
+}
+
+const check = (interaction: CommandInteraction, defaultCheck: WrappedCheck) => {
+ let member = (interaction.member as Discord.GuildMember)
+ if (!member.permissions.has("MANAGE_GUILD")) throw "You must have the `manage_server` permission to use this command"
+ return true;
+}
+
+export { command };
+export { callback };
+export { check };
diff --git a/src/commands/settings/log/events.ts b/src/commands/settings/logs/events.ts
similarity index 100%
rename from src/commands/settings/log/events.ts
rename to src/commands/settings/logs/events.ts
diff --git a/src/commands/settings/logs/ignore.ts b/src/commands/settings/logs/ignore.ts
new file mode 100644
index 0000000..4b66307
--- /dev/null
+++ b/src/commands/settings/logs/ignore.ts
@@ -0,0 +1,119 @@
+import { ChannelType } from 'discord-api-types';
+import Discord, { CommandInteraction } from "discord.js";
+import { SlashCommandSubcommandBuilder } from "@discordjs/builders";
+import generateEmojiEmbed from "../../../utils/generateEmojiEmbed.js";
+import { WrappedCheck } from "jshaiku";
+import confirmationMessage from '../../../utils/confirmationMessage.js';
+import keyValueList from '../../../utils/generateKeyValueList.js';
+import client from '../../../utils/client.js';
+
+const command = (builder: SlashCommandSubcommandBuilder) =>
+ builder
+ .setName("ignore")
+ .setDescription("Sets which users, channels and roles should be ignored")
+ .addStringOption(o => o.setName("action").setDescription("Add or remove from the list").addChoices([
+ ["Add", "add"], ["Remove", "remove"]
+ ]).setRequired(true))
+ .addChannelOption(o => o.setName("addchannel").setDescription("Add a channel that should be ignored").addChannelTypes([
+ ChannelType.GuildText, ChannelType.GuildVoice, ChannelType.GuildNews, ChannelType.GuildPublicThread, ChannelType.GuildPrivateThread, ChannelType.GuildNewsThread
+ ]))
+ .addUserOption(o => o.setName("adduser").setDescription("Add a user that should be ignored"))
+ .addRoleOption(o => o.setName("addrole").setDescription("Add a role that should be ignored"))
+
+const callback = async (interaction: CommandInteraction): Promise<any> => {
+ let channel = interaction.options.getChannel("addchannel")
+ let user = interaction.options.getUser("adduser")
+ let role = interaction.options.getRole("addrole")
+ await interaction.reply({embeds: [new generateEmojiEmbed()
+ .setTitle("Loading")
+ .setStatus("Danger")
+ .setEmoji("NUCLEUS.LOADING")
+ ], ephemeral: true, fetchReply: true});
+ if (channel || user || role) {
+ if (channel) {
+ try {
+ channel = interaction.guild.channels.cache.get(channel.id)
+ } catch {
+ return await interaction.editReply({embeds: [new generateEmojiEmbed()
+ .setEmoji("CHANNEL.TEXT.DELETE")
+ .setTitle("Logs > Ignore")
+ .setDescription("The channel you provided is not a valid channel")
+ .setStatus("Danger")
+ ]})
+ }
+ channel = channel as Discord.TextChannel
+ if (channel.guild.id != interaction.guild.id) {
+ return interaction.editReply({embeds: [new generateEmojiEmbed()
+ .setTitle("Logs > Ignore")
+ .setDescription(`You must choose a channel in this server`)
+ .setStatus("Danger")
+ .setEmoji("CHANNEL.TEXT.DELETE")
+ ]});
+ }
+ }
+ if (user) {
+ try {
+ user = interaction.guild.members.cache.get(user.id).user
+ } catch {
+ return await interaction.editReply({embeds: [new generateEmojiEmbed()
+ .setEmoji("USER.DELETE")
+ .setTitle("Logs > Ignore")
+ .setDescription("The user you provided is not a valid user")
+ .setStatus("Danger")
+ ]})
+ }
+ user = user as Discord.User
+ }
+ if (role) {
+ try {
+ role = interaction.guild.roles.cache.get(role.id)
+ } catch {
+ return await interaction.editReply({embeds: [new generateEmojiEmbed()
+ .setEmoji("ROLE.DELETE")
+ .setTitle("Logs > Ignore")
+ .setDescription("The role you provided is not a valid role")
+ .setStatus("Danger")
+ ]})
+ }
+ role = role as Discord.Role
+ if (role.guild.id != interaction.guild.id) {
+ return interaction.editReply({embeds: [new generateEmojiEmbed()
+ .setTitle("Logs > Ignore")
+ .setDescription(`You must choose a role in this server`)
+ .setStatus("Danger")
+ .setEmoji("ROLE.DELETE")
+ ]});
+ }
+ }
+ let changes = {}
+ if (channel) changes["channel"] = channel.id
+ if (user) changes["user"] = user.id
+ if (role) changes["role"] = role.id
+ let confirmation = await new confirmationMessage(interaction)
+ .setEmoji("NUCLEUS.COMMANDS.IGNORE")
+ .setTitle("Logs > Ignore")
+ .setDescription(keyValueList(changes)
+ + `Are you sure you want to **${interaction.options.getString("action") == "add" ? "add" : "remove"}** these to the ignore list?`)
+ .setColor("Warning")
+ .send(true)
+ if (confirmation.success) {
+ let data = client.database.read(interaction.guild.id)
+ if (channel) data.logging.logs.ignore.channels.concat([channel.id])
+ if (user) data.logging.logs.ignore.users.concat([user.id])
+ if (role) data.logging.logs.ignore.roles.concat([role.id])
+ if (interaction.options.getString("action") == "add") {
+ await client.database.append(interaction.guild.id, data)
+ }
+ }
+ }
+}
+
+const check = (interaction: CommandInteraction, defaultCheck: WrappedCheck) => {
+ let member = (interaction.member as Discord.GuildMember)
+ if (!member.permissions.has("MANAGE_GUILD")) throw "You must have the `manage_server` permission to use this command"
+ return true;
+}
+
+export { command };
+export { callback };
+export { check };
\ No newline at end of file
diff --git a/src/commands/settings/menu.ts b/src/commands/settings/menu.ts
deleted file mode 100644
index 9950fe4..0000000
--- a/src/commands/settings/menu.ts
+++ /dev/null
@@ -1,53 +0,0 @@
-import { CommandInteraction, MessageEmbed, MessageSelectMenu } from "discord.js";
-import { SlashCommandSubcommandBuilder } from "@discordjs/builders";
-import { WrappedCheck } from "jshaiku";
-import readConfig from "../../utils/readConfig.js";
-import { toHexArray, toHexInteger, logs } from "../../utils/calculate.js"
-import { capitalize } from "../../utils/generateKeyValueList.js";
-
-const command = (builder: SlashCommandSubcommandBuilder) =>
- builder
- .setName("menu")
- .setDescription("Shows a full UI of all settings")
-
-const callback = async (interaction: CommandInteraction) => {
- return
- let config = await readConfig(interaction.guild.id);
-
- let currentValues = toHexArray(config.logging.log.toLog);
-
- let toLogDropdownOptions = []
-
- for(let i of logs) {
- if(currentValues.includes(i)) {
- toLogDropdownOptions.push({
- name: capitalize(i),
- value: i,
- emoji: "TICK"
- })
- } else {
- toLogDropdownOptions.push({
- label: capitalize(i),
- value: i,
- emoji: "CROSS"
- })
- }
- }
-
- let toLogDropdown = new MessageSelectMenu()
- .setCustomId("log")
- .setMaxValues(22)
- .addOptions()
-
- let embed = new MessageEmbed()
-
- interaction.reply("This command is not yet finished [settings/all]");
-}
-
-const check = (interaction: CommandInteraction, defaultCheck: WrappedCheck) => {
- return true;
-}
-
-export { command };
-export { callback };
-export { check };
\ No newline at end of file
diff --git a/src/commands/settings/mod/channel.ts b/src/commands/settings/mod/channel.ts
deleted file mode 100644
index 88c8396..0000000
--- a/src/commands/settings/mod/channel.ts
+++ /dev/null
@@ -1,20 +0,0 @@
-import { CommandInteraction } from "discord.js";
-import { SlashCommandSubcommandBuilder } from "@discordjs/builders";
-import { WrappedCheck } from "jshaiku";
-
-const command = (builder: SlashCommandSubcommandBuilder) =>
- builder
- .setName("channel")
- .setDescription("Sets the channel for staff messages to go to")
-
-const callback = (interaction: CommandInteraction) => {
- interaction.reply("This command is not yet finished [settings/mod/channel]");
-}
-
-const check = (interaction: CommandInteraction, defaultCheck: WrappedCheck) => {
- return true;
-}
-
-export { command };
-export { callback };
-export { check };
\ No newline at end of file
diff --git a/src/commands/settings/mod/events.ts b/src/commands/settings/mod/events.ts
deleted file mode 100644
index be5de57..0000000
--- a/src/commands/settings/mod/events.ts
+++ /dev/null
@@ -1,20 +0,0 @@
-import { CommandInteraction } from "discord.js";
-import { SlashCommandSubcommandBuilder } from "@discordjs/builders";
-import { WrappedCheck } from "jshaiku";
-
-const command = (builder: SlashCommandSubcommandBuilder) =>
- builder
- .setName("events")
- .setDescription("Sets which events mods should be notified about")
-
-const callback = (interaction: CommandInteraction) => {
- interaction.reply("This command is not yet finished [settings/mod/events]");
-}
-
-const check = (interaction: CommandInteraction, defaultCheck: WrappedCheck) => {
- return true;
-}
-
-export { command };
-export { callback };
-export { check };
\ No newline at end of file
diff --git a/src/commands/settings/mod/_meta.ts b/src/commands/settings/staff/_meta.ts
similarity index 100%
rename from src/commands/settings/mod/_meta.ts
rename to src/commands/settings/staff/_meta.ts
diff --git a/src/commands/settings/staff/channel.ts b/src/commands/settings/staff/channel.ts
new file mode 100644
index 0000000..69ace92
--- /dev/null
+++ b/src/commands/settings/staff/channel.ts
@@ -0,0 +1,131 @@
+import { ChannelType } from 'discord-api-types';
+import Discord, { CommandInteraction, MessageActionRow, MessageButton } from "discord.js";
+import generateEmojiEmbed from "../../../utils/generateEmojiEmbed.js";
+import confirmationMessage from "../../../utils/confirmationMessage.js";
+import getEmojiByName from "../../../utils/getEmojiByName.js";
+import { SlashCommandSubcommandBuilder } from "@discordjs/builders";
+import { WrappedCheck } from "jshaiku";
+import client from "../../../utils/client.js";
+
+const command = (builder: SlashCommandSubcommandBuilder) =>
+ builder
+ .setName("channel")
+ .setDescription("Sets or shows the staff notifications channel")
+ .addChannelOption(option => option.setName("channel").setDescription("The channel to set the staff notifications channel to").addChannelTypes([
+ ChannelType.GuildNews, ChannelType.GuildText
+ ]))
+
+const callback = async (interaction: CommandInteraction): Promise<any> => {
+ let m;
+ m = await interaction.reply({embeds: [new generateEmojiEmbed()
+ .setTitle("Loading")
+ .setStatus("Danger")
+ .setEmoji("NUCLEUS.LOADING")
+ ], ephemeral: true, fetchReply: true});
+ if (interaction.options.getChannel("channel")) {
+ let channel
+ try {
+ channel = interaction.options.getChannel("channel")
+ } catch {
+ return await interaction.editReply({embeds: [new generateEmojiEmbed()
+ .setEmoji("CHANNEL.TEXT.DELETE")
+ .setTitle("Staff Notifications Channel")
+ .setDescription("The channel you provided is not a valid channel")
+ .setStatus("Danger")
+ ]})
+ }
+ channel = channel as Discord.TextChannel
+ if (channel.guild.id != interaction.guild.id) {
+ return interaction.editReply({embeds: [new generateEmojiEmbed()
+ .setTitle("Staff Notifications Channel")
+ .setDescription(`You must choose a channel in this server`)
+ .setStatus("Danger")
+ .setEmoji("CHANNEL.TEXT.DELETE")
+ ]});
+ }
+ let confirmation = await new confirmationMessage(interaction)
+ .setEmoji("CHANNEL.TEXT.EDIT")
+ .setTitle("Staff Notifications Channel")
+ .setDescription(
+ `This will be the channel all notifications, updates, user reports etc. will be sent to.\n\n` +
+ `Are you sure you want to set the staff notifications channel to <#${channel.id}>?`
+ )
+ .setColor("Warning")
+ .setInverted(true)
+ .send(true)
+ if (confirmation.success) {
+ try {
+ await client.database.write(interaction.guild.id, {"logging.staff.channel": channel.id})
+ } catch (e) {
+ return interaction.editReply({embeds: [new generateEmojiEmbed()
+ .setTitle("Staff Notifications Channel")
+ .setDescription(`Something went wrong and the staff notifications channel could not be set`)
+ .setStatus("Danger")
+ .setEmoji("CHANNEL.TEXT.DELETE")
+ ], components: []});
+ }
+ } else {
+ return interaction.editReply({embeds: [new generateEmojiEmbed()
+ .setTitle("Staff Notifications Channel")
+ .setDescription(`No changes were made`)
+ .setStatus("Success")
+ .setEmoji("CHANNEL.TEXT.CREATE")
+ ], components: []});
+ }
+ }
+ let clicks = 0;
+ let data = await client.database.read(interaction.guild.id);
+ let channel = data.logging.staff.channel;
+ while (true) {
+ await interaction.editReply({embeds: [new generateEmojiEmbed()
+ .setTitle("Staff Notifications channel")
+ .setDescription(channel ? `Your staff notifications channel is currently set to <#${channel}>` : "This server does not have a staff notifications channel")
+ .setStatus("Success")
+ .setEmoji("CHANNEL.TEXT.CREATE")
+ ], components: [new MessageActionRow().addComponents([new MessageButton()
+ .setCustomId("clear")
+ .setLabel(clicks ? "Click again to confirm" : "Reset channel")
+ .setEmoji(getEmojiByName(clicks ? "TICKETS.ISSUE" : "CONTROL.CROSS", "id"))
+ .setStyle("DANGER")
+ .setDisabled(!channel)
+ ])]});
+ let i;
+ try {
+ i = await m.awaitMessageComponent({time: 600000});
+ } catch(e) { break }
+ i.deferUpdate()
+ if (i.component.customId == "clear") {
+ clicks += 1;
+ if (clicks == 2) {
+ clicks = 0;
+ await client.database.write(interaction.guild.id, {}, ["logging.staff.channel"])
+ channel = undefined;
+ }
+ } else {
+ break
+ }
+ }
+ await interaction.editReply({embeds: [new generateEmojiEmbed()
+ .setTitle("Staff Notifications channel")
+ .setDescription(channel ? `Your staff notifications channel is currently set to <#${channel}>` : "This server does not have a staff notifications channel")
+ .setStatus("Success")
+ .setEmoji("CHANNEL.TEXT.CREATE")
+ .setFooter({text: "Message closed"})
+ ], components: [new MessageActionRow().addComponents([new MessageButton()
+ .setCustomId("clear")
+ .setLabel("Clear")
+ .setEmoji(getEmojiByName("CONTROL.CROSS", "id"))
+ .setStyle("SECONDARY")
+ .setDisabled(true)
+ ])]});
+}
+
+const check = (interaction: CommandInteraction, defaultCheck: WrappedCheck) => {
+ let member = (interaction.member as Discord.GuildMember)
+ if (!member.permissions.has("MANAGE_GUILD")) throw "You must have the `manage_server` permission to use this command"
+ return true;
+}
+
+export { command };
+export { callback };
+export { check };
diff --git a/src/commands/settings/tickets.ts b/src/commands/settings/tickets.ts
index 64dc980..aac271e 100644
--- a/src/commands/settings/tickets.ts
+++ b/src/commands/settings/tickets.ts
@@ -1,24 +1,410 @@
-import { CommandInteraction } from "discord.js";
-import { SlashCommandSubcommandBuilder } from "@discordjs/builders";
+import getEmojiByName from "../../utils/getEmojiByName.js";
+import generateEmojiEmbed from "../../utils/generateEmojiEmbed.js";
+import confirmationMessage from "../../utils/confirmationMessage.js";
+import Discord, { CommandInteraction, MessageActionRow, MessageButton, MessageSelectMenu, TextInputComponent } from "discord.js";
+import { SelectMenuOption, SlashCommandSubcommandBuilder } from "@discordjs/builders";
import { WrappedCheck } from "jshaiku";
import { ChannelType } from 'discord-api-types';
+import client from "../../utils/client.js";
+import { toHexInteger, toHexArray, tickets as ticketTypes } from "../../utils/calculate.js";
+import { capitalize } from '../../utils/generateKeyValueList.js';
+import { modalInteractionCollector } from "../../utils/dualCollector.js";
-const command = (builder: SlashCommandSubcommandBuilder) =>
- builder
+const command = (builder: SlashCommandSubcommandBuilder) => builder
.setName("tickets")
- .setDescription("Shows settings for tickets")
- .addStringOption(option => option.setName("enabled").setDescription("If users should be able to create tickets | Default yes").setRequired(false)
+ .setDescription("Shows settings for tickets | Use no arguments to manage custom types")
+ .addStringOption(option => option.setName("enabled").setDescription("If users should be able to create tickets").setRequired(false)
.addChoices([["Yes", "yes"], ["No", "no"]]))
.addChannelOption(option => option.setName("category").setDescription("The category where tickets are created").addChannelType(ChannelType.GuildCategory).setRequired(false))
- .addNumberOption(option => option.setName("maxtickets").setDescription("The maximum amount of tickets a user can create | Default 5").setRequired(false).setMinValue(1))
- .addRoleOption(option => option.setName("supportping").setDescription("The role pinged when a ticket is created").setRequired(false))
+ .addNumberOption(option => option.setName("maxticketsperuser").setDescription("The maximum amount of tickets a user can create | Default 5").setRequired(false).setMinValue(1))
+ .addRoleOption(option => option.setName("supportrole").setDescription("This role will have view access to all tickets and will be pinged when a ticket is created").setRequired(false))
-const callback = (interaction: CommandInteraction) => {
- interaction.reply("This command is not yet finished [settings/tickets]");
+const callback = async (interaction: CommandInteraction): Promise<any> => {
+ let m;
+ m = await interaction.reply({
+ embeds: [new generateEmojiEmbed()
+ .setTitle("Loading")
+ .setStatus("Danger")
+ .setEmoji("NUCLEUS.LOADING")
+ ], ephemeral: true, fetchReply: true
+ });
+ let options = {
+ enabled: interaction.options.getString("enabled") as string | boolean,
+ category: interaction.options.getChannel("category"),
+ maxtickets: interaction.options.getNumber("maxticketsperuser"),
+ supportping: interaction.options.getRole("supportrole")
+ }
+ if (options.enabled !== null || options.category || options.maxtickets || options.supportping) {
+ options.enabled = options.enabled === "yes" ? true : false;
+ if (options.category) {
+ let channel
+ try {
+ channel = interaction.guild.channels.cache.get(options.category.id)
+ } catch {
+ return await interaction.editReply({
+ embeds: [new generateEmojiEmbed()
+ .setEmoji("CHANNEL.TEXT.DELETE")
+ .setTitle("Tickets > Category")
+ .setDescription("The channel you provided is not a valid category")
+ .setStatus("Danger")
+ ]
+ })
+ }
+ channel = channel as Discord.CategoryChannel
+ if (channel.guild.id != interaction.guild.id) return interaction.editReply({
+ embeds: [new generateEmojiEmbed()
+ .setTitle("Tickets > Category")
+ .setDescription(`You must choose a category in this server`)
+ .setStatus("Danger")
+ .setEmoji("CHANNEL.TEXT.DELETE")
+ ]
+ });
+ }
+ if (options.maxtickets) {
+ if (options.maxtickets < 1) return interaction.editReply({
+ embeds: [new generateEmojiEmbed()
+ .setTitle("Tickets > Max Tickets")
+ .setDescription(`You must choose a number greater than 0`)
+ .setStatus("Danger")
+ .setEmoji("CHANNEL.TEXT.DELETE")
+ ]
+ });
+ }
+ let role
+ if (options.supportping) {
+ try {
+ role = interaction.guild.roles.cache.get(options.supportping.id)
+ } catch {
+ return await interaction.editReply({
+ embeds: [new generateEmojiEmbed()
+ .setEmoji("GUILD.ROLE.DELETE")
+ .setTitle("Tickets > Support Ping")
+ .setDescription("The role you provided is not a valid role")
+ .setStatus("Danger")
+ ]
+ })
+ }
+ role = role as Discord.Role
+ if (role.guild.id != interaction.guild.id) return interaction.editReply({
+ embeds: [new generateEmojiEmbed()
+ .setTitle("Tickets > Support Ping")
+ .setDescription(`You must choose a role in this server`)
+ .setStatus("Danger")
+ .setEmoji("GUILD.ROLE.DELETE")
+ ]
+ });
+ }
+
+ let confirmation = await new confirmationMessage(interaction)
+ .setEmoji("GUILD.TICKET.ARCHIVED")
+ .setTitle("Tickets")
+ .setDescription(
+ (options.category ? `**Category:** ${options.category.name}\n` : "") +
+ (options.maxtickets ? `**Max Tickets:** ${options.maxtickets}\n` : "") +
+ (options.supportping ? `**Support Ping:** ${options.supportping.name}\n` : "") +
+ (options.enabled !== null ? `**Enabled:** ${options.enabled ? `${getEmojiByName("CONTROL.TICK")} Yes` : `${getEmojiByName("CONTROL.CROSS")} No`
+ }\n` : "") +
+ `\nAre you sure you want to apply these settings?`
+ )
+ .setColor("Warning")
+ .setInverted(true)
+ .send(true)
+ if (confirmation.success) {
+ let toUpdate = {}
+ if (options.enabled !== null) toUpdate["tickets.enabled"] = options.enabled
+ if (options.category) toUpdate["tickets.category"] = options.category.id
+ if (options.maxtickets) toUpdate["tickets.maxTickets"] = options.maxtickets
+ if (options.supportping) toUpdate["tickets.supportRole"] = options.supportping.id
+ try {
+ await client.database.write(interaction.guild.id, toUpdate)
+ } catch (e) {
+ return interaction.editReply({
+ embeds: [new generateEmojiEmbed()
+ .setTitle("Tickets")
+ .setDescription(`Something went wrong and the staff notifications channel could not be set`)
+ .setStatus("Danger")
+ .setEmoji("GUILD.TICKET.DELETE")
+ ], components: []
+ });
+ }
+ } else {
+ return interaction.editReply({
+ embeds: [new generateEmojiEmbed()
+ .setTitle("Tickets")
+ .setDescription(`No changes were made`)
+ .setStatus("Success")
+ .setEmoji("GUILD.TICKET.OPEN")
+ ], components: []
+ });
+ }
+ }
+ let data = await client.database.read(interaction.guild.id);
+ data.tickets.customTypes = data.tickets.customTypes.filter((v, i, a) => a.indexOf(v) === i)
+ let lastClicked = "";
+ let embed;
+ data = {
+ enabled: data.tickets.enabled,
+ category: data.tickets.category,
+ maxTickets: data.tickets.maxTickets,
+ supportRole: data.tickets.supportRole,
+ useCustom: data.tickets.useCustom,
+ types: data.tickets.types,
+ customTypes: data.tickets.customTypes
+ }
+ while (true) {
+ embed = new generateEmojiEmbed()
+ .setTitle("Tickets")
+ .setDescription(
+ `${data.enabled ? "" : getEmojiByName("TICKETS.REPORT")} **Enabled:** ${data.enabled ? `${getEmojiByName("CONTROL.TICK")} Yes` : `${getEmojiByName("CONTROL.CROSS")} No`}\n` +
+ `${data.category ? "" : getEmojiByName("TICKETS.REPORT")} **Category:** ${data.category ? `<#${data.category}>` : "*None set*"}\n` +
+ `**Max Tickets:** ${data.maxTickets ? data.maxTickets : "*No limit*"}\n` +
+ `**Support Ping:** ${data.supportRole ? `<@&${data.supportRole}>` : "*None set*"}\n\n` +
+ ((data.useCustom && data.customTypes === null) ? `${getEmojiByName("TICKETS.REPORT")} ` : "") +
+ `${data.useCustom ? "Custom" : "Default"} types in use` + "\n\n" +
+ `${getEmojiByName("TICKETS.REPORT")} *Indicates a setting stopping tickets from being used*`
+ )
+ .setStatus("Success")
+ .setEmoji("GUILD.TICKET.OPEN")
+ m = await interaction.editReply({
+ embeds: [embed], components: [new MessageActionRow().addComponents([
+ new MessageButton()
+ .setLabel("Tickets " + (data.enabled ? "enabled" : "disabled"))
+ .setEmoji(getEmojiByName("CONTROL." + (data.enabled ? "TICK" : "CROSS"), "id"))
+ .setStyle(data.enabled ? "SUCCESS" : "DANGER")
+ .setCustomId("enabled"),
+ new MessageButton()
+ .setLabel(lastClicked == "cat" ? "Click again to confirm" : "Clear category")
+ .setEmoji(getEmojiByName("CONTROL.CROSS", "id"))
+ .setStyle("DANGER")
+ .setCustomId("clearCategory")
+ .setDisabled(data.category == null),
+ new MessageButton()
+ .setLabel(lastClicked == "max" ? "Click again to confirm" : "Reset max tickets")
+ .setEmoji(getEmojiByName("CONTROL.CROSS", "id"))
+ .setStyle("DANGER")
+ .setCustomId("clearMaxTickets")
+ .setDisabled(data.maxTickets == 5),
+ new MessageButton()
+ .setLabel(lastClicked == "sup" ? "Click again to confirm" : "Clear support ping")
+ .setEmoji(getEmojiByName("CONTROL.CROSS", "id"))
+ .setStyle("DANGER")
+ .setCustomId("clearSupportPing")
+ .setDisabled(data.supportRole == null),
+ ]), new MessageActionRow().addComponents([
+ new MessageButton()
+ .setLabel("Manage types")
+ .setEmoji(getEmojiByName("TICKETS.OTHER", "id"))
+ .setStyle("SECONDARY")
+ .setCustomId("manageTypes"),
+ ])]
+ });
+ let i;
+ try {
+ i = await m.awaitMessageComponent({ time: 600000 });
+ } catch (e) { break }
+ i.deferUpdate()
+ if (i.component.customId == "clearCategory") {
+ if (lastClicked == "cat") {
+ lastClicked = "";
+ await client.database.write(interaction.guild.id, {}, ["tickets.category"])
+ data.category = undefined;
+ } else lastClicked = "cat";
+ } else if (i.component.customId == "clearMaxTickets") {
+ if (lastClicked == "max") {
+ lastClicked = "";
+ await client.database.write(interaction.guild.id, {}, ["tickets.maxTickets"])
+ data.maxTickets = 5;
+ } else lastClicked = "max";
+ } else if (i.component.customId == "clearSupportPing") {
+ if (lastClicked == "sup") {
+ lastClicked = "";
+ await client.database.write(interaction.guild.id, {}, ["tickets.supportRole"])
+ data.supportRole = undefined;
+ } else lastClicked = "sup";
+ } else if (i.component.customId == "enabled") {
+ await client.database.write(interaction.guild.id, { "tickets.enabled": !data.enabled })
+ data.enabled = !data.enabled;
+ } else if (i.component.customId == "manageTypes") {
+ data = await manageTypes(interaction, data, m);
+ } else {
+ break
+ }
+ }
+ await interaction.editReply({ embeds: [embed.setFooter({ text: "Message closed" })], components: [] });
}
+async function manageTypes(interaction, data, m) {
+ while (true) {
+ if (data.useCustom) {
+ let customTypes = data.customTypes;
+ interaction.editReply({
+ embeds: [new generateEmojiEmbed()
+ .setTitle("Tickets > Types")
+ .setDescription(
+ "**Custom types enabled**\n\n" +
+ "**Types in use:**\n" + ((customTypes !== null) ?
+ (customTypes.map((t) => `> ${t}`).join("\n")) :
+ "*None set*"
+ ) + "\n\n" + (customTypes === null ?
+ `${getEmojiByName("TICKETS.REPORT")} Having no types will disable tickets. Please add at least 1 type or use default types` : ""
+ )
+ )
+ .setStatus("Success")
+ .setEmoji("GUILD.TICKET.OPEN")
+ ], components: (customTypes ? [
+ new MessageActionRow().addComponents([new Discord.MessageSelectMenu()
+ .setCustomId("removeTypes")
+ .setPlaceholder("Select types to remove")
+ .setMaxValues(customTypes.length)
+ .setMinValues(1)
+ .addOptions(customTypes.map((t) => new SelectMenuOption().setLabel(t).setValue(t)))
+ ])
+ ] : []).concat([
+ new MessageActionRow().addComponents([
+ new MessageButton()
+ .setLabel("Back")
+ .setEmoji(getEmojiByName("CONTROL.LEFT", "id"))
+ .setStyle("PRIMARY")
+ .setCustomId("back"),
+ new MessageButton()
+ .setLabel("Add new type")
+ .setEmoji(getEmojiByName("TICKETS.SUGGESTION", "id"))
+ .setStyle("PRIMARY")
+ .setCustomId("addType")
+ .setDisabled(customTypes !== null && customTypes.length >= 25),
+ new MessageButton()
+ .setLabel("Switch to default types")
+ .setStyle("SECONDARY")
+ .setCustomId("switchToDefault"),
+ ])
+ ])
+ });
+ } else {
+ let inUse = toHexArray(data.types, ticketTypes)
+ let options = [];
+ ticketTypes.forEach(type => {
+ options.push(new SelectMenuOption({
+ label: capitalize(type),
+ value: type,
+ emoji: interaction.client.emojis.cache.get(getEmojiByName(`TICKETS.${type.toUpperCase()}`, "id")),
+ default: inUse.includes(type)
+ }))
+ })
+ let selectPane = new MessageActionRow().addComponents([
+ new Discord.MessageSelectMenu()
+ .addOptions(options)
+ .setCustomId("types")
+ .setMaxValues(ticketTypes.length)
+ .setMinValues(1)
+ .setPlaceholder("Select types to use")
+ ])
+ interaction.editReply({
+ embeds: [new generateEmojiEmbed()
+ .setTitle("Tickets > Types")
+ .setDescription(
+ "**Default types enabled**\n\n" +
+ "**Types in use:**\n" +
+ (inUse.map((t) => `> ${getEmojiByName("TICKETS." + t.toUpperCase())} ${capitalize(t)}`).join("\n"))
+ )
+ .setStatus("Success")
+ .setEmoji("GUILD.TICKET.OPEN")
+ ], components: [
+ selectPane,
+ new MessageActionRow().addComponents([
+ new MessageButton()
+ .setLabel("Back")
+ .setEmoji(getEmojiByName("CONTROL.LEFT", "id"))
+ .setStyle("PRIMARY")
+ .setCustomId("back"),
+ new MessageButton()
+ .setLabel("Switch to custom types")
+ .setStyle("SECONDARY")
+ .setCustomId("switchToCustom"),
+ ])
+ ]
+ });
+ }
+ let i;
+ try {
+ i = await m.awaitMessageComponent({ time: 600000 });
+ } catch (e) { break }
+ if (i.component.customId == "types") {
+ i.deferUpdate()
+ let types = toHexInteger(i.values, ticketTypes);
+ await client.database.write(interaction.guild.id, { "tickets.types": types })
+ data.types = types;
+ } else if (i.component.customId == "removeTypes") {
+ i.deferUpdate()
+ let types = i.values
+ let customTypes = data.customTypes;
+ if (customTypes) {
+ customTypes = customTypes.filter((t) => !types.includes(t));
+ customTypes = customTypes.length > 0 ? customTypes : null;
+ await client.database.write(interaction.guild.id, { "tickets.customTypes": customTypes })
+ data.customTypes = customTypes;
+ }
+ } else if (i.component.customId == "addType") {
+ await i.showModal(new Discord.Modal().setCustomId("modal").setTitle("Enter a name for the new type").addComponents(
+ // @ts-ignore
+ new MessageActionRow().addComponents(new TextInputComponent()
+ .setCustomId("type")
+ .setLabel("Name")
+ .setMaxLength(100)
+ .setMinLength(1)
+ .setPlaceholder("E.g. \"Server Idea\"")
+ .setRequired(true)
+ .setStyle("SHORT")
+ )
+ ))
+ await interaction.editReply({
+ embeds: [new generateEmojiEmbed()
+ .setTitle("Tickets > Types")
+ .setDescription("Modal opened. If you can't see it, click back and try again.")
+ .setStatus("Success")
+ .setEmoji("GUILD.TICKET.OPEN")
+ ], components: [new MessageActionRow().addComponents([new MessageButton()
+ .setLabel("Back")
+ .setEmoji(getEmojiByName("CONTROL.LEFT", "id"))
+ .setStyle("PRIMARY")
+ .setCustomId("back")
+ ])]
+ });
+ let out
+ try {
+ out = await modalInteractionCollector(m, (m) => m.channel.id == interaction.channel.id, (m) => m.customId == "addType")
+ } catch (e) { continue }
+ if (out.fields) {
+ let toAdd = out.fields.getTextInputValue("type");
+ if (!toAdd) { continue }
+ try {
+ await client.database.append(interaction.guild.id, "tickets.customTypes", toAdd)
+ } catch { continue }
+ data.customTypes = data.customTypes || [];
+ if (!data.customTypes.includes(toAdd)) {
+ data.customTypes.push(toAdd);
+ }
+ } else { continue }
+ } else if (i.component.customId == "switchToDefault") {
+ i.deferUpdate()
+ await client.database.write(interaction.guild.id, { "tickets.useCustom": false }, [])
+ data.useCustom = false;
+ } else if (i.component.customId == "switchToCustom") {
+ i.deferUpdate()
+ await client.database.write(interaction.guild.id, { "tickets.useCustom": true }, [])
+ data.useCustom = true;
+ } else {
+ i.deferUpdate()
+ break
+ }
+ }
+ return data
+}
+
+
const check = (interaction: CommandInteraction, defaultCheck: WrappedCheck) => {
- return interaction.memberPermissions.has("MANAGE_GUILD");
+ let member = (interaction.member as Discord.GuildMember)
+ if (!member.permissions.has("MANAGE_GUILD")) throw "You must have the `manage_server` permission to use this command"
+ return true;
}
export { command };
diff --git a/src/commands/settings/verify/role.ts b/src/commands/settings/verify/role.ts
index c4de7af..dc1d4d9 100644
--- a/src/commands/settings/verify/role.ts
+++ b/src/commands/settings/verify/role.ts
@@ -1,20 +1,126 @@
-import { CommandInteraction } from "discord.js";
+import Discord, { CommandInteraction, MessageActionRow, MessageButton } from "discord.js";
+import generateEmojiEmbed from "../../../utils/generateEmojiEmbed.js";
+import confirmationMessage from "../../../utils/confirmationMessage.js";
+import getEmojiByName from "../../../utils/getEmojiByName.js";
import { SlashCommandSubcommandBuilder } from "@discordjs/builders";
import { WrappedCheck } from "jshaiku";
+import client from "../../../utils/client.js";
const command = (builder: SlashCommandSubcommandBuilder) =>
builder
.setName("role")
- .setDescription("Sets the role given after verifying")
+ .setDescription("Sets or shows the role given to users after using /verify")
+ .addRoleOption(option => option.setName("role").setDescription("The role to give after verifying"))
-const callback = (interaction: CommandInteraction) => {
- interaction.reply("This command is not yet finished [settings/verify/role]");
+const callback = async (interaction: CommandInteraction): Promise<any> => {
+ let m;
+ m = await interaction.reply({embeds: [new generateEmojiEmbed()
+ .setTitle("Loading")
+ .setStatus("Danger")
+ .setEmoji("NUCLEUS.LOADING")
+ ], ephemeral: true, fetchReply: true});
+ if (interaction.options.getRole("role")) {
+ let role
+ try {
+ role = interaction.options.getRole("role")
+ } catch {
+ return await interaction.editReply({embeds: [new generateEmojiEmbed()
+ .setEmoji("GUILD.ROLES.DELETE")
+ .setTitle("Verify Role")
+ .setDescription("The role you provided is not a valid role")
+ .setStatus("Danger")
+ ]})
+ }
+ role = role as Discord.Role
+ if (role.guild.id != interaction.guild.id) {
+ return interaction.editReply({embeds: [new generateEmojiEmbed()
+ .setTitle("Verify Role")
+ .setDescription(`You must choose a role in this server`)
+ .setStatus("Danger")
+ .setEmoji("GUILD.ROLES.DELETE")
+ ]});
+ }
+ let confirmation = await new confirmationMessage(interaction)
+ .setEmoji("GUILD.ROLES.EDIT")
+ .setTitle("Verify Role")
+ .setDescription(`Are you sure you want to set the verify role to <@&${role.id}>?`)
+ .setColor("Warning")
+ .setInverted(true)
+ .send(true)
+ if (confirmation.success) {
+ try {
+ await client.database.write(interaction.guild.id, {"verify.role": role.id, "verify.enabled": true});
+ } catch (e) {
+ console.log(e)
+ return interaction.editReply({embeds: [new generateEmojiEmbed()
+ .setTitle("Verify Role")
+ .setDescription(`Something went wrong while setting the verify role`)
+ .setStatus("Danger")
+ .setEmoji("GUILD.ROLES.DELETE")
+ ], components: []});
+ }
+ } else {
+ return interaction.editReply({embeds: [new generateEmojiEmbed()
+ .setTitle("Verify Role")
+ .setDescription(`No changes were made`)
+ .setStatus("Success")
+ .setEmoji("GUILD.ROLES.CREATE")
+ ], components: []});
+ }
+ }
+ let clicks = 0;
+ let data = await client.database.read(interaction.guild.id);
+ let role = data.verify.role;
+ while (true) {
+ await interaction.editReply({embeds: [new generateEmojiEmbed()
+ .setTitle("Verify Role")
+ .setDescription(role ? `Your verify role is currently set to <@&${role}>` : `You have not set a verify role`)
+ .setStatus("Success")
+ .setEmoji("GUILD.ROLES.CREATE")
+ ], components: [new MessageActionRow().addComponents([new MessageButton()
+ .setCustomId("clear")
+ .setLabel(clicks ? "Click again to confirm" : "Reset role")
+ .setEmoji(getEmojiByName(clicks ? "TICKETS.ISSUE" : "CONTROL.CROSS", "id"))
+ .setStyle("DANGER")
+ .setDisabled(!role)
+ ])]});
+ let i;
+ try {
+ i = await m.awaitMessageComponent({time: 600000});
+ } catch(e) { break }
+ i.deferUpdate()
+ if (i.component.customId == "clear") {
+ clicks += 1;
+ if (clicks == 2) {
+ clicks = 0;
+ await client.database.write(interaction.guild.id, {}, ["verify.role", "verify.enabled"])
+ role = undefined;
+ }
+ } else {
+ break
+ }
+ }
+ await interaction.editReply({embeds: [new generateEmojiEmbed()
+ .setTitle("Verify Role")
+ .setDescription(role ? `Your verify role is currently set to <@&${role}}>` : `You have not set a verify role`)
+ .setStatus("Success")
+ .setEmoji("GUILD.ROLE.CREATE")
+ .setFooter({text: "Message closed"})
+ ], components: [new MessageActionRow().addComponents([new MessageButton()
+ .setCustomId("clear")
+ .setLabel("Clear")
+ .setEmoji(getEmojiByName("CONTROL.CROSS", "id"))
+ .setStyle("SECONDARY")
+ .setDisabled(true)
+ ])]});
}
const check = (interaction: CommandInteraction, defaultCheck: WrappedCheck) => {
+ let member = (interaction.member as Discord.GuildMember)
+ if (!member.permissions.has("MANAGE_GUILD")) throw "You must have the `manage_server` permission to use this command"
return true;
}
export { command };
export { callback };
-export { check };
\ No newline at end of file
+export { check };
diff --git a/src/commands/tag.ts b/src/commands/tag.ts
index a5fcfc1..8d6d8c9 100644
--- a/src/commands/tag.ts
+++ b/src/commands/tag.ts
@@ -1,12 +1,14 @@
import { CommandInteraction } from "discord.js";
import { SlashCommandBuilder } from "@discordjs/builders";
import { WrappedCheck } from "jshaiku";
+import { callback as statsChannelAdd } from '../automations/statsChannelAdd.js';
const command = new SlashCommandBuilder()
.setName("tag")
.setDescription("Get and manage the servers tags")
const callback = (interaction: CommandInteraction) => {
+ try { statsChannelAdd(interaction.client, interaction.member); } catch {} // TODO: REMOVE THIS FOR PRODUCTION
interaction.reply("This command is not yet finished [tag]");
}
diff --git a/src/commands/tags/_meta.ts b/src/commands/tags/_meta.ts
new file mode 100644
index 0000000..8c07682
--- /dev/null
+++ b/src/commands/tags/_meta.ts
@@ -0,0 +1,4 @@
+const name = "tags";
+const description = "manage server tags";
+
+export { name, description };
\ No newline at end of file
diff --git a/src/commands/tags/create.ts b/src/commands/tags/create.ts
new file mode 100644
index 0000000..e53f94f
--- /dev/null
+++ b/src/commands/tags/create.ts
@@ -0,0 +1,87 @@
+import Discord, { CommandInteraction } from "discord.js";
+import { SlashCommandSubcommandBuilder } from "@discordjs/builders";
+import { WrappedCheck } from "jshaiku";
+import generateEmojiEmbed from "../../utils/generateEmojiEmbed.js";
+import confirmationMessage from "../../utils/confirmationMessage.js";
+import keyValueList from "../../utils/generateKeyValueList.js";
+import client from "../../utils/client.js";
+
+const command = (builder: SlashCommandSubcommandBuilder) =>
+ builder
+ .setName("create")
+ .setDescription("Creates a tag")
+ .addStringOption(o => o.setName("name").setRequired(true).setDescription("The name of the tag"))
+ .addStringOption(o => o.setName("value").setRequired(true).setDescription("The value of the tag, shown after running /tag name"))
+
+const callback = async (interaction: CommandInteraction): Promise<any> => {
+ let name = interaction.options.getString("name");
+ let value = interaction.options.getString("value");
+ if (name.length > 100) return await interaction.reply({embeds: [new generateEmojiEmbed()
+ .setTitle("Tag Create")
+ .setDescription("Tag names cannot be longer than 100 characters")
+ .setStatus("Danger")
+ .setEmoji("PUNISH.NICKNAME.RED")
+ ], ephemeral: true});
+ if (value.length > 1000) return await interaction.reply({embeds: [new generateEmojiEmbed()
+ .setTitle("Tag Create")
+ .setDescription("Tag values cannot be longer than 1000 characters")
+ .setStatus("Danger")
+ .setEmoji("PUNISH.NICKNAME.RED")
+ ], ephemeral: true});
+ let data = await client.database.read(interaction.guild.id);
+ if (data.tags.length >= 100) return await interaction.reply({embeds: [new generateEmojiEmbed()
+ .setTitle("Tag Create")
+ .setDescription("You cannot have more than 100 tags")
+ .setStatus("Danger")
+ .setEmoji("PUNISH.NICKNAME.RED")
+ ], ephemeral: true});
+ if (data.tags[name]) return await interaction.reply({embeds: [new generateEmojiEmbed()
+ .setTitle("Tag Create")
+ .setDescription("That tag already exists")
+ .setStatus("Danger")
+ .setEmoji("PUNISH.NICKNAME.RED")
+ ], ephemeral: true});
+ let confirmation = await new confirmationMessage(interaction)
+ .setEmoji("PUNISH.NICKNAME.YELLOW")
+ .setTitle("Tag create")
+ .setDescription(keyValueList({
+ "name": `${name}`,
+ "value": `\n> ${value}`
+ })
+ + `\nAre you sure you want to create this tag?`)
+ .setColor("Warning")
+ .setInverted(true)
+ .send()
+ if (!confirmation) return await interaction.editReply({embeds: [new generateEmojiEmbed()
+ .setTitle("Tag Create")
+ .setDescription("No changes were made")
+ .setStatus("Success")
+ .setEmoji("PUNISH.NICKNAME.GREEN")
+ ]});
+ try {
+ await client.database.write(interaction.guild.id, {[`tags.${name}`]: value});
+ } catch (e) {
+ return await interaction.editReply({embeds: [new generateEmojiEmbed()
+ .setTitle("Tag Create")
+ .setDescription("Something went wrong and the tag was not created")
+ .setStatus("Danger")
+ .setEmoji("PUNISH.NICKNAME.RED")
+ ], components: []});
+ }
+ return await interaction.editReply({embeds: [new generateEmojiEmbed()
+ .setTitle("Tag Create")
+ .setDescription("Tag created")
+ .setStatus("Success")
+ .setEmoji("PUNISH.NICKNAME.GREEN")
+ ], components: []});
+}
+
+const check = (interaction: CommandInteraction, defaultCheck: WrappedCheck) => {
+ let member = (interaction.member as Discord.GuildMember)
+ if (!member.permissions.has("MANAGE_MESSAGES")) throw "You must have the `manage_messages` permission to use this command"
+ return true;
+}
+
+export { command };
+export { callback };
+export { check };
\ No newline at end of file
diff --git a/src/commands/tags/delete.ts b/src/commands/tags/delete.ts
new file mode 100644
index 0000000..ff54ee5
--- /dev/null
+++ b/src/commands/tags/delete.ts
@@ -0,0 +1,69 @@
+import Discord, { CommandInteraction } from "discord.js";
+import { SlashCommandSubcommandBuilder } from "@discordjs/builders";
+import { WrappedCheck } from "jshaiku";
+import generateEmojiEmbed from "../../utils/generateEmojiEmbed.js";
+import confirmationMessage from "../../utils/confirmationMessage.js";
+import keyValueList from "../../utils/generateKeyValueList.js";
+import client from "../../utils/client.js";
+
+const command = (builder: SlashCommandSubcommandBuilder) =>
+ builder
+ .setName("delete")
+ .setDescription("Deletes a tag")
+ .addStringOption(o => o.setName("name").setRequired(true).setDescription("The name of the tag"))
+
+const callback = async (interaction: CommandInteraction): Promise<any> => {
+ let name = interaction.options.getString("name");
+ let data = await client.database.read(interaction.guild.id);
+ if (!data.tags[name]) return await interaction.reply({embeds: [new generateEmojiEmbed()
+ .setTitle("Tags")
+ .setDescription("That tag does not exist")
+ .setStatus("Danger")
+ .setEmoji("PUNISH.NICKNAME.RED")
+ ], ephemeral: true});
+ let confirmation = await new confirmationMessage(interaction)
+ .setEmoji("PUNISH.NICKNAME.YELLOW")
+ .setTitle("Tag Delete")
+ .setDescription(keyValueList({
+ "name": `${name}`,
+ "value": `\n> ${data.tags[name]}`
+ })
+ + `\nAre you sure you want to delete this tag?`)
+ .setColor("Warning")
+ .setInverted(true)
+ .send()
+ if (!confirmation) return await interaction.editReply({embeds: [new generateEmojiEmbed()
+ .setTitle("Tag Delete")
+ .setDescription("No changes were made")
+ .setStatus("Success")
+ .setEmoji("PUNISH.NICKNAME.GREEN")
+ ]});
+ try {
+ data = await client.database.read(interaction.guild.id);
+ delete data.tags[name];
+ await client.database.write(interaction.guild.id, {tags: data});
+ } catch (e) {
+ return await interaction.editReply({embeds: [new generateEmojiEmbed()
+ .setTitle("Tag Delete")
+ .setDescription("Something went wrong and the tag was not deleted")
+ .setStatus("Danger")
+ .setEmoji("PUNISH.NICKNAME.RED")
+ ], components: []});
+ }
+ return await interaction.editReply({embeds: [new generateEmojiEmbed()
+ .setTitle("Tag Delete")
+ .setDescription("Tag deleted")
+ .setStatus("Success")
+ .setEmoji("PUNISH.NICKNAME.GREEN")
+ ], components: []});
+}
+
+const check = (interaction: CommandInteraction, defaultCheck: WrappedCheck) => {
+ let member = (interaction.member as Discord.GuildMember)
+ if (!member.permissions.has("MANAGE_MESSAGES")) throw "You must have the `manage_messages` permission to use this command"
+ return true;
+}
+
+export { command };
+export { callback };
+export { check };
\ No newline at end of file
diff --git a/src/commands/tags/edit.ts b/src/commands/tags/edit.ts
new file mode 100644
index 0000000..3cf73e5
--- /dev/null
+++ b/src/commands/tags/edit.ts
@@ -0,0 +1,102 @@
+import Discord, { CommandInteraction } from "discord.js";
+import { SlashCommandSubcommandBuilder } from "@discordjs/builders";
+import { WrappedCheck } from "jshaiku";
+import generateEmojiEmbed from "../../utils/generateEmojiEmbed.js";
+import confirmationMessage from "../../utils/confirmationMessage.js";
+import keyValueList from "../../utils/generateKeyValueList.js";
+import client from "../../utils/client.js";
+
+const command = (builder: SlashCommandSubcommandBuilder) =>
+ builder
+ .setName("edit")
+ .setDescription("Edits or renames a tag")
+ .addStringOption(o => o.setName("name").setRequired(true).setDescription("The tag to edit"))
+ .addStringOption(o => o.setName("value").setRequired(false).setDescription("The new value of the tag / Rename"))
+ .addStringOption(o => o.setName("newname").setRequired(false).setDescription("The new name of the tag / Edit"))
+
+const callback = async (interaction: CommandInteraction): Promise<any> => {
+ let name = interaction.options.getString("name");
+ let value = interaction.options.getString("value") || "";
+ let newname = interaction.options.getString("newname") || "";
+ if (!newname && !value) return await interaction.reply({embeds: [new generateEmojiEmbed()
+ .setTitle("Tag Edit")
+ .setDescription("You must specify a value or a new name")
+ .setStatus("Danger")
+ .setEmoji("PUNISH.NICKNAME.RED")
+ ], ephemeral: true});
+ if (newname.length > 100) return await interaction.reply({embeds: [new generateEmojiEmbed()
+ .setTitle("Tag Edit")
+ .setDescription("Tag names cannot be longer than 100 characters")
+ .setStatus("Danger")
+ .setEmoji("PUNISH.NICKNAME.RED")
+ ], ephemeral: true});
+ if (value.length > 2000) return await interaction.reply({embeds: [new generateEmojiEmbed()
+ .setTitle("Tag Edit")
+ .setDescription("Tag values cannot be longer than 2000 characters")
+ .setStatus("Danger")
+ .setEmoji("PUNISH.NICKNAME.RED")
+ ], ephemeral: true});
+ let data = await client.database.read(interaction.guild.id);
+ if (!data.tags[name]) return await interaction.reply({embeds: [new generateEmojiEmbed()
+ .setTitle("Tag Edit")
+ .setDescription("That tag does not exist")
+ .setStatus("Danger")
+ .setEmoji("PUNISH.NICKNAME.RED")
+ ], ephemeral: true});
+ if (newname && newname !== name && data.tags[newname]) return await interaction.reply({embeds: [new generateEmojiEmbed()
+ .setTitle("Tag Edit")
+ .setDescription("A tag with that name already exists")
+ .setStatus("Danger")
+ .setEmoji("PUNISH.NICKNAME.RED")
+ ], ephemeral: true});
+ let confirmation = await new confirmationMessage(interaction)
+ .setEmoji("PUNISH.NICKNAME.YELLOW")
+ .setTitle("Tag Edit")
+ .setDescription(keyValueList({
+ "name": `${name}` + (newname ? ` -> ${newname}` : ""),
+ "value": `\n> ${value ? value : data.tags[name]}`
+ })
+ + `\nAre you sure you want to edit this tag?`)
+ .setColor("Warning")
+ .setInverted(true)
+ .send()
+ if (!confirmation) return await interaction.editReply({embeds: [new generateEmojiEmbed()
+ .setTitle("Tag Edit")
+ .setDescription("No changes were made")
+ .setStatus("Success")
+ .setEmoji("PUNISH.NICKNAME.GREEN")
+ ]});
+ try {
+ let toSet = {};
+ let toUnset = []
+ if (value) toSet[`tags.${name}`] = value;
+ if (newname) {
+ toUnset.push(`tags.${name}`);
+ toSet[`tags.${newname}`] = data.tags[name];
+ }
+ await client.database.write(interaction.guild.id, toSet, toUnset);
+ } catch (e) {
+ return await interaction.editReply({embeds: [new generateEmojiEmbed()
+ .setTitle("Tag Edit")
+ .setDescription("Something went wrong and the tag was not edited")
+ .setStatus("Danger")
+ .setEmoji("PUNISH.NICKNAME.RED")
+ ], components: []});
+ }
+ return await interaction.editReply({embeds: [new generateEmojiEmbed()
+ .setTitle("Tags")
+ .setDescription("Tag edited successfully")
+ .setStatus("Success")
+ .setEmoji("PUNISH.NICKNAME.GREEN")
+ ], components: []});
+}
+
+const check = (interaction: CommandInteraction, defaultCheck: WrappedCheck) => {
+ let member = (interaction.member as Discord.GuildMember)
+ if (!member.permissions.has("MANAGE_MESSAGES")) throw "You must have the `manage_messages` permission to use this command"
+ return true;
+}
+
+export { command };
+export { callback };
+export { check };
\ No newline at end of file
diff --git a/src/commands/tags/list.ts b/src/commands/tags/list.ts
new file mode 100644
index 0000000..bf234d5
--- /dev/null
+++ b/src/commands/tags/list.ts
@@ -0,0 +1,150 @@
+import Discord, { CommandInteraction, MessageActionRow, MessageButton } from "discord.js";
+import { SlashCommandSubcommandBuilder } from "@discordjs/builders";
+import { WrappedCheck } from "jshaiku";
+import generateEmojiEmbed from "../../utils/generateEmojiEmbed.js";
+import keyValueList from "../../utils/generateKeyValueList.js";
+import client from "../../utils/client.js";
+import { SelectMenuOption } from '@discordjs/builders';
+import getEmojiByName from "../../utils/getEmojiByName.js";
+import createPageIndicator from "../../utils/createPageIndicator.js";
+
+
+class Embed {
+ embed: Discord.MessageEmbed;
+ title: string;
+ description: string = "";
+ pageId: number = 0;
+ setEmbed(embed: Discord.MessageEmbed) { this.embed = embed; return this; }
+ setTitle(title: string) { this.title = title; return this; }
+ setDescription(description: string) { this.description = description; return this; }
+ setPageId(pageId: number) { this.pageId = pageId; return this; }
+}
+
+const command = (builder: SlashCommandSubcommandBuilder) =>
+ builder
+ .setName("list")
+ .setDescription("Lists all tags in the server")
+
+const callback = async (interaction: CommandInteraction) => {
+ let data = await client.database.read(interaction.guild.id);
+ let tags = data.getKey("tags");
+ console.log(tags)
+ let strings = []
+ if (data === {}) strings = ["*No tags exist*"]
+ else {
+ let string = ""
+ for (let tag in tags) {
+ let proposed = `**${tag}:** ${tags[tag]}\n`
+ if (string.length + proposed.length > 2000) {
+ strings.push(string.slice(0, -1))
+ string = ""
+ }
+ console.log(string)
+ string += proposed
+ }
+ strings.push(string.slice(0, -1))
+ }
+
+ let pages = []
+ for (let string of strings) {
+ pages.push(new Embed()
+ .setEmbed(new generateEmojiEmbed()
+ .setTitle("Tags")
+ .setDescription(string)
+ .setEmoji("PUNISH.NICKNAME.GREEN")
+ .setStatus("Success")
+ ).setTitle(`Page ${pages.length + 1}`).setPageId(pages.length))
+ }
+ let m;
+ m = await interaction.reply({
+ embeds: [
+ new generateEmojiEmbed()
+ .setTitle("Welcome")
+ .setDescription(`One moment...`)
+ .setStatus("Danger")
+ .setEmoji("NUCLEUS.LOADING")
+ ], fetchReply: true, ephemeral: true
+ });
+ let page = 0;
+ let selectPaneOpen = false;
+ while (true) {
+ let selectPane = []
+
+ if (selectPaneOpen) {
+ let options = [];
+ pages.forEach(embed => {
+ options.push(new SelectMenuOption({
+ label: embed.title,
+ value: embed.pageId.toString(),
+ description: embed.description || "",
+ }))
+ })
+ selectPane = [new MessageActionRow().addComponents([
+ new Discord.MessageSelectMenu()
+ .addOptions(options)
+ .setCustomId("page")
+ .setMaxValues(1)
+ .setPlaceholder("Choose a page...")
+ ])]
+ }
+ let em = new Discord.MessageEmbed(pages[page].embed)
+ em.setDescription(em.description + "\n\n" + createPageIndicator(pages.length, page));
+ await interaction.editReply({
+ embeds: [em],
+ components: selectPane.concat([new MessageActionRow().addComponents([
+ new MessageButton().setCustomId("left").setEmoji(getEmojiByName("CONTROL.LEFT", "id")).setStyle("SECONDARY").setDisabled(page === 0),
+ new MessageButton().setCustomId("select").setEmoji(getEmojiByName("CONTROL.MENU", "id")).setStyle(selectPaneOpen ? "PRIMARY" : "SECONDARY").setDisabled(false),
+ new MessageButton().setCustomId("right").setEmoji(getEmojiByName("CONTROL.RIGHT", "id")).setStyle("SECONDARY").setDisabled(page === pages.length - 1),
+ new MessageButton().setCustomId("close").setEmoji(getEmojiByName("CONTROL.CROSS", "id")).setStyle("DANGER")
+ ])])
+ });
+ let i
+ try {
+ i = await m.awaitMessageComponent({time: 600000 });
+ } catch (e) { break }
+ i.deferUpdate()
+ if (i.component.customId == "left") {
+ if (page > 0) page--;
+ selectPaneOpen = false;
+ } else if (i.component.customId == "right") {
+ if (page < pages.length - 1) page++;
+ selectPaneOpen = false;
+ } else if (i.component.customId == "select") {
+ selectPaneOpen = !selectPaneOpen;
+ } else if (i.component.customId == "page") {
+ page = parseInt(i.values[0]);
+ selectPaneOpen = false;
+ } else {
+ let em = new Discord.MessageEmbed(pages[page].embed)
+ em.setDescription(em.description + "\n\n" + createPageIndicator(pages.length, page) + " | Message closed");
+ await interaction.editReply({
+ embeds: [em], components: [new MessageActionRow().addComponents([
+ new MessageButton().setCustomId("left").setEmoji(getEmojiByName("CONTROL.LEFT", "id")).setStyle("SECONDARY").setDisabled(true),
+ new MessageButton().setCustomId("select").setEmoji(getEmojiByName("CONTROL.MENU", "id")).setStyle(selectPaneOpen ? "PRIMARY" : "SECONDARY").setDisabled(true),
+ new MessageButton().setCustomId("right").setEmoji(getEmojiByName("CONTROL.RIGHT", "id")).setStyle("SECONDARY").setDisabled(true),
+ new MessageButton().setCustomId("close").setEmoji(getEmojiByName("CONTROL.CROSS", "id")).setStyle("DANGER").setDisabled(true)
+ ])]
+ })
+ return;
+ }
+ }
+ let em = new Discord.MessageEmbed(pages[page])
+ em.setDescription(em.description + "\n\n" + createPageIndicator(pages.length, page) + " | Message timed out");
+ await interaction.editReply({
+ embeds: [em],
+ components: [new MessageActionRow().addComponents([
+ new MessageButton().setCustomId("left").setEmoji(getEmojiByName("CONTROL.LEFT", "id")).setStyle("SECONDARY").setDisabled(true),
+ new MessageButton().setCustomId("select").setEmoji(getEmojiByName("CONTROL.MENU", "id")).setStyle("SECONDARY").setDisabled(true),
+ new MessageButton().setCustomId("right").setEmoji(getEmojiByName("CONTROL.RIGHT", "id")).setStyle("SECONDARY").setDisabled(true),
+ new MessageButton().setCustomId("close").setEmoji(getEmojiByName("CONTROL.CROSS", "id")).setStyle("DANGER").setDisabled(true)
+ ])]
+ });
+}
+
+const check = (interaction: CommandInteraction, defaultCheck: WrappedCheck) => {
+ return true;
+}
+
+export { command };
+export { callback };
+export { check };
\ No newline at end of file
diff --git a/src/commands/user/track.ts b/src/commands/user/track.ts
index be32f41..f96f718 100644
--- a/src/commands/user/track.ts
+++ b/src/commands/user/track.ts
@@ -3,9 +3,8 @@
import { WrappedCheck } from "jshaiku";
import generateEmojiEmbed from "../../utils/generateEmojiEmbed.js";
import getEmojiByName from "../../utils/getEmojiByName.js";
-import generateKeyValueList from "../../utils/generateKeyValueList.js";
-import readConfig from "../../utils/readConfig.js";
import addPlural from "../../utils/plurals.js";
+import client from "../../utils/client.js";
const command = (builder: SlashCommandSubcommandBuilder) =>
builder
@@ -24,10 +23,10 @@
const callback = async (interaction: CommandInteraction) => {
// @ts-ignore
- const { renderUser } = interaction.client.logger
+ const { renderUser } = interaction.client.logger;
const member = interaction.options.getMember("user") as GuildMember;
const guild = interaction.guild;
- let config = await readConfig(guild.id);
+ let config = await client.database.read(guild.id);
await interaction.reply({embeds: [new generateEmojiEmbed()
.setEmoji("NUCLEUS.LOADING")
.setTitle("Loading")
@@ -161,14 +160,19 @@
}
}
-const check = (interaction: CommandInteraction, defaultCheck: WrappedCheck) => {
+const check = async (interaction: CommandInteraction, defaultCheck: WrappedCheck) => {
let member = (interaction.member as GuildMember)
// Allow the owner to promote anyone
if (member.id == interaction.guild.ownerId) return true
+ // Check if the user can manage any of the tracks
+ // @ts-ignore
+ let tracks = (await interaction.client.database.get(interaction.guild.id)).tracks
+ let managed = false
+ tracks.forEach(element => { if (element.track.manageableBy.some(role => member.roles.cache.has(role))) managed = true });
// Check if the user has manage_roles permission
- if (! member.permissions.has("MANAGE_ROLES")) throw "You do not have the `manage_roles` permission";
+ if (!managed && ! member.permissions.has("MANAGE_ROLES")) throw "You do not have the `manage_roles` permission";
// Allow track
- return true // TODO: allow if the member has manage perms
+ return true;
}
export { command };
diff --git a/src/config/default.json b/src/config/default.json
index 129bfe9..3b0882f 100644
--- a/src/config/default.json
+++ b/src/config/default.json
@@ -57,14 +57,18 @@
"logs": {
"enabled": true,
"channel": null,
- "toLog": "3fffff"
+ "toLog": "3fffff",
+ "ignore": {
+ "users": [],
+ "roles": [],
+ "channels": []
+ }
},
"staff": {
"channel": null
}
},
"verify": {
- "enabled": false,
"role": null
},
"tickets": {
@@ -72,6 +76,7 @@
"category": null,
"types": "3f",
"customTypes": null,
+ "useCustom": false,
"supportRole": null,
"maxTickets": 5
},
diff --git a/src/events/channelCreate.ts b/src/events/channelCreate.ts
index 883efd9..ec788f7 100644
--- a/src/events/channelCreate.ts
+++ b/src/events/channelCreate.ts
@@ -1,5 +1,3 @@
-import { Interaction } from "discord.js";
-
export const event = 'channelCreate'
export async function callback(client, channel) {
diff --git a/src/index.ts b/src/index.ts
index 2616f40..ca14cdb 100644
--- a/src/index.ts
+++ b/src/index.ts
@@ -18,5 +18,4 @@
client.memory = new Memory()
client.database = await new Database(config.mongoUrl).connect()
-
await client.login();
\ No newline at end of file
diff --git a/src/utils/calculate.ts b/src/utils/calculate.ts
index 26c231c..8a297b9 100644
--- a/src/utils/calculate.ts
+++ b/src/utils/calculate.ts
@@ -1,13 +1,13 @@
const logs = [
"channelUpdate",
- "channelPinsUpdate",
+ "channelPinsUpdate", // TODO
"emojiUpdate",
- "stickerUpdate",
+ "stickerUpdate", // TODO
"guildUpdate",
"guildMemberUpdate",
"guildMemberPunish",
- "guildEventUpdate",
- "guildEventMemberUpdate",
+ "guildEventUpdate", // TODO
+ "guildEventMemberUpdate", // TODO
"guildRoleUpdate",
"guildInviteUpdate",
"messageUpdate",
@@ -16,11 +16,11 @@
"messageReactionUpdate",
"messagePing",
"messageMassPing",
- "messageAnnounce",
+ "messageAnnounce", // TODO
"stageUpdate",
"threadUpdate",
- "voiceStateUpdate",
- "webhookUpdate"
+ "voiceStateUpdate", // TODO
+ "webhookUpdate" // TODO
]
const tickets = [
diff --git a/src/utils/database.ts b/src/utils/database.ts
index 53ccb97..4e37652 100644
--- a/src/utils/database.ts
+++ b/src/utils/database.ts
@@ -1,8 +1,10 @@
import { Collection, Db, MongoClient } from 'mongodb';
+import structuredClone from '@ungap/structured-clone';
export const Entry = data => {
data = data ?? {};
+ data.getKey = key => data[key]
return {
get(target, prop, receiver) {
let dataToReturn = data[prop]
@@ -38,11 +40,42 @@
async read(guild: string) {
let entry = await this.guilds.findOne({ id: guild });
- return new Proxy(this.defaultData, Entry(entry)) as unknown as GuildConfig
+ return new Proxy(structuredClone(this.defaultData), Entry(entry)) as unknown as GuildConfig
}
- async write(guild: string, config: GuildConfig) {
- await this.guilds.updateOne({ id: guild }, { $set: config }, { upsert: true });
+ async write(guild: string, set: object = {}, unset: string[] = []) {
+ let uo = {}
+ for (let key of unset) {
+ uo[key] = "";
+ }
+ await this.guilds.updateOne({ id: guild }, {
+ $unset: uo,
+ $set: set
+ }, { upsert: true });
+ }
+
+ async append(guild: string, key: string, value: any) {
+ if (Array.isArray(value)) {
+ await this.guilds.updateOne({ id: guild }, {
+ $addToSet: { [key]: { $each: value } }
+ }, { upsert: true });
+ } else {
+ await this.guilds.updateOne({ id: guild }, {
+ $addToSet: { [key]: value }
+ }, { upsert: true });
+ }
+ }
+
+ async remove(guild: string, key: string, value: any) {
+ if (Array.isArray(value)) {
+ await this.guilds.updateOne({ id: guild }, {
+ $pullAll: { [key]: value }
+ }, { upsert: true });
+ } else {
+ await this.guilds.updateOne({ id: guild }, {
+ $pullAll: { [key]: [value] }
+ }, { upsert: true });
+ }
}
}
@@ -94,64 +127,65 @@
enabled: boolean,
verificationRequired: {
message: boolean,
- role: string
+ role: string | null
},
- welcomeRole: string,
- channel: string,
- message: string
+ welcomeRole: string | null,
+ channel: string | null,
+ message: string | null,
}
stats: {
enabled: boolean,
- channel: string,
- text: string
+ channel: string | null,
+ text: string | null,
}[]
logging: {
logs: {
enabled: boolean,
- channel: string,
- toLog: string
+ channel: string | null,
+ toLog: string | null,
},
staff: {
- channel: string
+ channel: string | null,
}
}
verify: {
enabled: boolean,
- role: string
+ role: string | null,
}
tickets: {
enabled: boolean,
- category: string,
- types: string,
+ category: string | null,
+ types: string | null,
customTypes: string[],
- supportRole: string,
+ useCustom: boolean,
+ supportRole: string | null,
maxTickets: number
}
moderation: {
mute: {
timeout: boolean,
- role: string,
- text: string,
- link: string
+ role: string | null,
+ text: string | null,
+ link: string | null
},
kick: {
- text: string,
- link: string
+ text: string | null,
+ link: string | null
},
ban: {
- text: string,
- link: string
+ text: string | null,
+ link: string | null
},
softban: {
- text: string,
- link: string
+ text: string | null,
+ link: string | null
},
warn: {
- text: string,
- link: string
+ text: string | null,
+ link: string | null
},
role: {
- role: string
+ role: string | null,
}
}
tracks: {
diff --git a/src/utils/dualCollector.ts b/src/utils/dualCollector.ts
new file mode 100644
index 0000000..ae63757
--- /dev/null
+++ b/src/utils/dualCollector.ts
@@ -0,0 +1,49 @@
+import Discord from 'discord.js';
+import client from './client.js';
+import generateEmojiEmbed from "./generateEmojiEmbed.js";
+
+export default async function (m, interactionFilter, messageFilter) {
+ let out;
+ try {
+ out = await new Promise((resolve, reject) => {
+ let mes, int;
+ mes = m.createMessageComponentCollector({filter: (m) => interactionFilter(m), time: 600000})
+ .on("collect", (m) => { resolve(m); })
+ int = m.channel.createMessageCollector({filter: (m) => messageFilter(m), time: 600000})
+ .then("collect", (m) => { try {m.delete();} catch {}; resolve(m); })
+ mes.on("end", () => { int.stop(); })
+ int.on("end", () => { mes.stop(); })
+ })
+ } catch(e) {
+ console.log(e)
+ return null;
+ }
+
+ return out;
+}
+
+export async function modalInteractionCollector(m, modalFilter, interactionFilter) {
+ let out;
+ try {
+ out = await new Promise((resolve, reject) => {
+ let mod, int;
+ int = m.createMessageComponentCollector({filter: (m) => interactionFilter(m), time: 600000})
+ .on("collect", (m) => { resolve(m); })
+ mod = new Discord.InteractionCollector(
+ client, {
+ filter: (m) => modalFilter(m),
+ time: 600000
+ })
+ .on("collect", async (m) => {
+ int.stop();
+ (m as Discord.ModalSubmitInteraction).deferUpdate()
+ resolve((m as Discord.ModalSubmitInteraction)); })
+ int.on("end", () => { mod.stop(); })
+ mod.on("end", () => { int.stop(); })
+ })
+ } catch(e) {
+ console.log(e)
+ return null;
+ }
+ return out;
+}
\ No newline at end of file
diff --git a/src/utils/generateConfig.ts b/src/utils/generateConfig.ts
deleted file mode 100644
index 39b28b0..0000000
--- a/src/utils/generateConfig.ts
+++ /dev/null
@@ -1,92 +0,0 @@
-import * as fs from 'fs';
-
-function writeLogConfig(guild, logs) {
- if( !fs.existsSync(`./data/guilds/${guild.id}/config.json`) ) {
- fs.rmSync(`./data/guilds/${guild.id}/config.json`);
- }
- if( !fs.existsSync(`./data/guilds/${guild.id}/pins.json`) ) {
- let pins = guild.channels.cache.filter(c => c.type === "GUILD_TEXT").map(
- c => c.messages.fetchPinned().then(m => m.map(m => m.id))
- );
- fs.writeFileSync(`./data/guilds/${guild.id}/pins.json`, JSON.stringify(pins));
- }
- if( !fs.existsSync(`./data/guilds/${guild.id}/logs.json`) ) {
- fs.writeFileSync(`./data/guilds/${guild.id}/logs.json`, JSON.stringify([]));
- } else if( logs ) {
- fs.rmSync(`./data/guilds/${guild.id}/logs.json`);
- fs.writeFileSync(`./data/guilds/${guild.id}/logs.json`, JSON.stringify([]));
- }
- fs.writeFileSync(`./data/guilds/${guild.id}/config.json`, JSON.stringify({
- metadata: {
- premium: false
- },
- logs: {
- enabled: true,
- logChannel: guild.systemChannelId,
- toLog: "8be71",
- toIgnore: {
- bots: false,
- channels: [],
- members: [],
- roles: []
- }
- },
- userVerification: {
- enabled: false,
- roleID: null,
- customMessage: null
- },
- modmail: {
- enabled: false,
- categoryId: null,
- namingScheme: "rsm-{user}-{discriminator}",
- },
- welcome: {
- enabled: false,
- channelId: null,
- message: null,
- messageType: "embed",
- },
- filters: {
- images: {
- NSFW: true,
- size: true
- },
- malware: true,
- wordFilter: {
- enabled: true,
- words: {
- strict: [],
- loose: []
- },
- allowed: {
- users: [],
- roles: [],
- channels: []
- }
- },
- invite: {
- enabled: true,
- allowed: {
- users: [],
- channels: [],
- roles: []
- }
- },
- pings: {
- mass: 5,
- everyone: true,
- roles: true,
- allowed: {
- roles: [],
- rolesToMention: [],
- users: [],
- channels: []
- }
- }
- },
- tags: {}
- }));
-}
-
-export default writeLogConfig;
\ No newline at end of file
diff --git a/src/utils/log.ts b/src/utils/log.ts
index 238b6f4..19eb2b6 100644
--- a/src/utils/log.ts
+++ b/src/utils/log.ts
@@ -1,10 +1,10 @@
import * as fs from 'fs';
import * as Discord from 'discord.js';
import getEmojiByName from './getEmojiByName.js';
-import readConfig from './readConfig.js';
import { toHexArray } from './calculate.js';
import { promisify } from 'util';
import generateKeyValueList from './generateKeyValueList.js';
+import client from './client.js';
const wait = promisify(setTimeout);
@@ -52,8 +52,8 @@
return auditLog;
}
- async log(log: any, client): Promise<void> {
- let config = await readConfig(log.hidden.guild);
+ async log(log: any): Promise<void> {
+ let config = await client.database.read(log.hidden.guild);
if (!config.logging.logs.enabled) return;
if (!(log.meta.calculateType == true)) {
if(!toHexArray(config.logging.logs.toLog).includes(log.meta.calculateType)) return console.log('Not logging this type of event');
diff --git a/src/utils/memory.ts b/src/utils/memory.ts
index 0cbf955..7e21fa9 100644
--- a/src/utils/memory.ts
+++ b/src/utils/memory.ts
@@ -1,22 +1,31 @@
-import readConfig from "./readConfig.js";
+import client from "./client.js";
class Memory {
memory: {};
constructor() {
this.memory = {};
+
+ setInterval(() => {
+ for (let guild in this.memory) {
+ if (this.memory[guild].updated + 15 * 60 * 1000 < Date.now()) {
+ delete this.memory[guild];
+ }
+ }
+ }, 1000 * 60 * 30)
}
async readGuildInfo(guild: string): Promise<object> {
if (!this.memory[guild]) {
- let guildData = await readConfig(guild);
+ let guildData = await client.database.read(guild);
this.memory[guild] = {
+ lastUpdated: Date.now(),
filters: guildData.filters,
logging: guildData.logging,
tickets: guildData.tickets,
- }; // TODO: REMOVE GUILD FROM MEMORY WHEN THESE UPDATE
- } // TODO: Add a "lastAccessed" prop, delete after 15 minutes
+ };
+ };
return this.memory[guild];
}
}
-export default Memory;
\ No newline at end of file
+export default Memory;
diff --git a/src/utils/readConfig.ts b/src/utils/readConfig.ts
deleted file mode 100644
index b363fc0..0000000
--- a/src/utils/readConfig.ts
+++ /dev/null
@@ -1,5 +0,0 @@
-import client from './client.js';
-
-export default async function readConfig(guild: string): Promise<any> {
- return await client.database.read(guild);
-}
diff --git a/src/utils/singleNotify.ts b/src/utils/singleNotify.ts
index 4e9e6fe..a983478 100644
--- a/src/utils/singleNotify.ts
+++ b/src/utils/singleNotify.ts
@@ -1,4 +1,4 @@
-import readConfig from "./readConfig.js";
+import client from './client.js';
import generateEmojiEmbed from "./generateEmojiEmbed.js";
let severities = {
@@ -7,17 +7,18 @@
"Info": "Success"
}
-export default async function(client, type: string, guild: string, message: string, severity: string) {
- let config = await readConfig(guild);
- if (config.singleEventNotifications[type]) return;
- // TODO: Set config.singleEventNotifications[type] to true
- let channel = await client.channels.fetch(config.logging.staff);
- if (!channel) return;
+export default async function(type: string, guild: string, message: string, severity: string) {
+ let data = await client.database.read(guild);
+ if (data.singleEventNotifications[type]) return;
+ data.singleEventNotifications[type] = true;
+ client.database.write(guild, data);
try {
+ let channel = await client.channels.fetch(data.logging.staff.channel);
+ if (!channel) return;
await channel.send({embeds: [new generateEmojiEmbed()
.setTitle(`${severity} notification`)
.setDescription(message)
- .setColor(severities[severity])
+ .setStatus(severities[severity])
.setEmoji("CONTROL.BLOCKCROSS")
]})
} catch (err) {
diff --git a/tsconfig.json b/tsconfig.json
index cbbd2ee..591467f 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -9,6 +9,7 @@
"declarationMap": true,
"resolveJsonModule": true,
"moduleResolution": "node",
+ "skipLibCheck": true
},
"include": ["src/**/*"],
"exclude": []