diff --git a/.env.example b/.env.example index d2bedea..2fe2fcd 100644 --- a/.env.example +++ b/.env.example @@ -12,5 +12,14 @@ MOORE_CLIENT_ID= # This is the test guild id MOORE_GUILD_ID= -# Set to production if you want to deploy command globally -NODE_ENV= \ No newline at end of file +# Set to production if you are running in production +NODE_ENV= + +# This was inserted by `prisma init`: +# Environment variables declared in this file are automatically made available to Prisma. +# See the documentation for more detail: https://pris.ly/d/prisma-schema#accessing-environment-variables-from-the-schema + +# Prisma supports the native connection string format for PostgreSQL, MySQL, SQLite, SQL Server, MongoDB and CockroachDB. +# See the documentation for all the connection string options: https://pris.ly/d/connection-strings + +DATABASE_URL="postgresql://johndoe:randompassword@localhost:5432/mydb?schema=public" \ No newline at end of file diff --git a/.idea/codeStyles/Project.xml b/.idea/codeStyles/Project.xml new file mode 100644 index 0000000..f55fffc --- /dev/null +++ b/.idea/codeStyles/Project.xml @@ -0,0 +1,34 @@ + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/codeStyles/codeStyleConfig.xml b/.idea/codeStyles/codeStyleConfig.xml new file mode 100644 index 0000000..79ee123 --- /dev/null +++ b/.idea/codeStyles/codeStyleConfig.xml @@ -0,0 +1,5 @@ + + + + \ No newline at end of file diff --git a/.idea/prettier.xml b/.idea/prettier.xml new file mode 100644 index 0000000..b0ab31a --- /dev/null +++ b/.idea/prettier.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/package.json b/package.json index 12fdc4b..059699e 100644 --- a/package.json +++ b/package.json @@ -6,9 +6,11 @@ "type": "module", "scripts": { "start": "cd dist && node index", + "start:watch": "cd dist && nodemon --delay 1000ms index", "format": "prettier -w .", "lint": "eslint . --no-error-on-unmatched-pattern", "build": "pnpm run build:files && pnpm run copy:dotfiles", + "dev": "conc --kill-others \"pnpm run build:watch\" \"pnpm run start:watch\"", "build:files": "tsc -p .", "build:watch": "tsc -p . --watch", "copy:dotfiles": "cp .env dist" @@ -24,11 +26,16 @@ "@types/node": "^18.11.3", "@typescript-eslint/eslint-plugin": "^5.40.1", "@typescript-eslint/parser": "^5.40.1", + "axios": "^1.1.3", "discord-api-types": "^0.37.14", "discord.js": "~14.6.0", "discordx": "^11.4.0", "dotenv": "^16.0.3", "eslint": "8.22", + "prisma": "^4.5.0", "typescript": "^4.8.4" + }, + "devDependencies": { + "concurrently": "^7.5.0" } } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index abee2c1..1fbbff8 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -8,11 +8,14 @@ specifiers: '@types/node': ^18.11.3 '@typescript-eslint/eslint-plugin': ^5.40.1 '@typescript-eslint/parser': ^5.40.1 + axios: ^1.1.3 + concurrently: ^7.5.0 discord-api-types: ^0.37.14 discord.js: ~14.6.0 discordx: ^11.4.0 dotenv: ^16.0.3 eslint: '8.22' + prisma: ^4.5.0 typescript: ^4.8.4 dependencies: @@ -23,13 +26,18 @@ dependencies: '@types/node': 18.11.3 '@typescript-eslint/eslint-plugin': 5.40.1_7l7rruczv4daimtr3qpeu6yv5e '@typescript-eslint/parser': 5.40.1_yv3nvntfnealqm77uomj2fi4ki + axios: 1.1.3 discord-api-types: 0.37.14 discord.js: 14.6.0 discordx: 11.4.0_discord.js@14.6.0 dotenv: 16.0.3 eslint: 8.22.0 + prisma: 4.5.0 typescript: 4.8.4 +devDependencies: + concurrently: 7.5.0 + packages: /@discordjs/builders/1.3.0: @@ -170,6 +178,11 @@ packages: fastq: 1.13.0 dev: false + /@prisma/engines/4.5.0: + resolution: {integrity: sha512-4t9ir2SbQQr/wMCNU4YpHWp5hU14J2m3wHUZnGJPpmBF8YtkisxyVyQsKd1e6FyLTaGq8LOLhm6VLYHKqKNm+g==} + requiresBuild: true + dev: false + /@sapphire/async-queue/1.5.0: resolution: {integrity: sha512-JkLdIsP8fPAdh9ZZjrbHWR/+mZj0wvKS5ICibcLrRI1j84UmLMshx5n9QmL8b95d4onJ2xxiyugTgSAX7AalmA==} engines: {node: '>=v14.0.0', npm: '>=7.0.0'} @@ -364,14 +377,12 @@ packages: /ansi-regex/5.0.1: resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} engines: {node: '>=8'} - dev: false /ansi-styles/4.3.0: resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} engines: {node: '>=8'} dependencies: color-convert: 2.0.1 - dev: false /argparse/2.0.1: resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} @@ -382,6 +393,20 @@ packages: engines: {node: '>=8'} dev: false + /asynckit/0.4.0: + resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==} + dev: false + + /axios/1.1.3: + resolution: {integrity: sha512-00tXVRwKx/FZr/IDVFt4C+f9FYairX517WoGCL6dpOntqLkZofjhu43F/Xl44UOpqa+9sLFDrG/XAnFsUYgkDA==} + dependencies: + follow-redirects: 1.15.2 + form-data: 4.0.0 + proxy-from-env: 1.1.0 + transitivePeerDependencies: + - debug + dev: false + /balanced-match/1.0.2: resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} dev: false @@ -424,23 +449,52 @@ packages: dependencies: ansi-styles: 4.3.0 supports-color: 7.2.0 - dev: false + + /cliui/8.0.1: + resolution: {integrity: sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==} + engines: {node: '>=12'} + dependencies: + string-width: 4.2.3 + strip-ansi: 6.0.1 + wrap-ansi: 7.0.0 + dev: true /color-convert/2.0.1: resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} engines: {node: '>=7.0.0'} dependencies: color-name: 1.1.4 - dev: false /color-name/1.1.4: resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} + + /combined-stream/1.0.8: + resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==} + engines: {node: '>= 0.8'} + dependencies: + delayed-stream: 1.0.0 dev: false /concat-map/0.0.1: resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} dev: false + /concurrently/7.5.0: + resolution: {integrity: sha512-5E3mwiS+i2JYBzr5BpXkFxOnleZTMsG+WnE/dCG4/P+oiVXrbmrBwJ2ozn4SxwB2EZDrKR568X+puVohxz3/Mg==} + engines: {node: ^12.20.0 || ^14.13.0 || >=16.0.0} + hasBin: true + dependencies: + chalk: 4.1.2 + date-fns: 2.29.3 + lodash: 4.17.21 + rxjs: 7.5.7 + shell-quote: 1.7.4 + spawn-command: 0.0.2-1 + supports-color: 8.1.1 + tree-kill: 1.2.2 + yargs: 17.6.2 + dev: true + /cross-spawn/7.0.3: resolution: {integrity: sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==} engines: {node: '>= 8'} @@ -450,6 +504,11 @@ packages: which: 2.0.2 dev: false + /date-fns/2.29.3: + resolution: {integrity: sha512-dDCnyH2WnnKusqvZZ6+jA1O51Ibt8ZMRNkDZdyAyK4YfbDwa/cEmuztzG5pk6hqlp9aSBPYcjOlktquahGwGeA==} + engines: {node: '>=0.11'} + dev: true + /debug/4.3.4: resolution: {integrity: sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==} engines: {node: '>=6.0'} @@ -466,6 +525,11 @@ packages: resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==} dev: false + /delayed-stream/1.0.0: + resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==} + engines: {node: '>=0.4.0'} + dev: false + /dir-glob/3.0.1: resolution: {integrity: sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==} engines: {node: '>=8'} @@ -523,6 +587,15 @@ packages: engines: {node: '>=12'} dev: false + /emoji-regex/8.0.0: + resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} + dev: true + + /escalade/3.1.1: + resolution: {integrity: sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==} + engines: {node: '>=6'} + dev: true + /escape-string-regexp/4.0.0: resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==} engines: {node: '>=10'} @@ -722,6 +795,25 @@ packages: resolution: {integrity: sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==} dev: false + /follow-redirects/1.15.2: + resolution: {integrity: sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==} + engines: {node: '>=4.0'} + peerDependencies: + debug: '*' + peerDependenciesMeta: + debug: + optional: true + dev: false + + /form-data/4.0.0: + resolution: {integrity: sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==} + engines: {node: '>= 6'} + dependencies: + asynckit: 0.4.0 + combined-stream: 1.0.8 + mime-types: 2.1.35 + dev: false + /fs.realpath/1.0.0: resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==} dev: false @@ -730,6 +822,11 @@ packages: resolution: {integrity: sha512-dsKNQNdj6xA3T+QlADDA7mOSlX0qiMINjn0cgr+eGHGsbSHzTabcIogz2+p/iqP1Xs6EP/sS2SbqH+brGTbq0g==} dev: false + /get-caller-file/2.0.5: + resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==} + engines: {node: 6.* || 8.* || >= 10.*} + dev: true + /glob-parent/5.1.2: resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} engines: {node: '>= 6'} @@ -792,7 +889,6 @@ packages: /has-flag/4.0.0: resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} engines: {node: '>=8'} - dev: false /ieee754/1.2.1: resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==} @@ -832,6 +928,11 @@ packages: engines: {node: '>=0.10.0'} dev: false + /is-fullwidth-code-point/3.0.0: + resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==} + engines: {node: '>=8'} + dev: true + /is-glob/4.0.3: resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} engines: {node: '>=0.10.0'} @@ -892,7 +993,6 @@ packages: /lodash/4.17.21: resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==} - dev: false /lru-cache/6.0.0: resolution: {integrity: sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==} @@ -914,6 +1014,18 @@ packages: picomatch: 2.3.1 dev: false + /mime-db/1.52.0: + resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==} + engines: {node: '>= 0.6'} + dev: false + + /mime-types/2.1.35: + resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==} + engines: {node: '>= 0.6'} + dependencies: + mime-db: 1.52.0 + dev: false + /minimatch/3.1.2: resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} dependencies: @@ -1009,6 +1121,19 @@ packages: engines: {node: '>= 0.8.0'} dev: false + /prisma/4.5.0: + resolution: {integrity: sha512-9Aeg4qiKlv9Wsjz4NO8k2CzRzlvS3A4FYVJ5+28sBBZ0eEwbiVOE/Jj7v6rZC1tFW2s4GSICQOAyuOjc6WsNew==} + engines: {node: '>=14.17'} + hasBin: true + requiresBuild: true + dependencies: + '@prisma/engines': 4.5.0 + dev: false + + /proxy-from-env/1.1.0: + resolution: {integrity: sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==} + dev: false + /punycode/2.1.1: resolution: {integrity: sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==} engines: {node: '>=6'} @@ -1039,6 +1164,11 @@ packages: engines: {node: '>=8'} dev: false + /require-directory/2.1.1: + resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==} + engines: {node: '>=0.10.0'} + dev: true + /resolve-from/4.0.0: resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==} engines: {node: '>=4'} @@ -1062,6 +1192,12 @@ packages: queue-microtask: 1.2.3 dev: false + /rxjs/7.5.7: + resolution: {integrity: sha512-z9MzKh/UcOqB3i20H6rtrlaE/CgjLOvheWK/9ILrbhROGTweAi1BaFsTT9FbwZi5Trr1qNRs+MXkhmR06awzQA==} + dependencies: + tslib: 2.4.0 + dev: true + /safe-buffer/5.2.1: resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==} dev: false @@ -1086,16 +1222,33 @@ packages: engines: {node: '>=8'} dev: false + /shell-quote/1.7.4: + resolution: {integrity: sha512-8o/QEhSSRb1a5i7TFR0iM4G16Z0vYB2OQVs4G3aAFXjn3T6yEx8AZxy1PgDF7I00LZHYA3WxaSYIf5e5sAX8Rw==} + dev: true + /slash/3.0.0: resolution: {integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==} engines: {node: '>=8'} dev: false + /spawn-command/0.0.2-1: + resolution: {integrity: sha512-n98l9E2RMSJ9ON1AKisHzz7V42VDiBQGY6PB1BwRglz99wpVsSuGzQ+jOi6lFXBGVTCrRpltvjm+/XA+tpeJrg==} + dev: true + /streamsearch/1.1.0: resolution: {integrity: sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==} engines: {node: '>=10.0.0'} dev: false + /string-width/4.2.3: + resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==} + engines: {node: '>=8'} + dependencies: + emoji-regex: 8.0.0 + is-fullwidth-code-point: 3.0.0 + strip-ansi: 6.0.1 + dev: true + /string_decoder/1.3.0: resolution: {integrity: sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==} dependencies: @@ -1107,7 +1260,6 @@ packages: engines: {node: '>=8'} dependencies: ansi-regex: 5.0.1 - dev: false /strip-json-comments/3.1.1: resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} @@ -1127,7 +1279,13 @@ packages: engines: {node: '>=8'} dependencies: has-flag: 4.0.0 - dev: false + + /supports-color/8.1.1: + resolution: {integrity: sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==} + engines: {node: '>=10'} + dependencies: + has-flag: 4.0.0 + dev: true /text-table/0.2.0: resolution: {integrity: sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==} @@ -1148,6 +1306,11 @@ packages: ieee754: 1.2.1 dev: false + /tree-kill/1.2.2: + resolution: {integrity: sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==} + hasBin: true + dev: true + /ts-mixer/6.0.1: resolution: {integrity: sha512-hvE+ZYXuINrx6Ei6D6hz+PTim0Uf++dYbK9FFifLNwQj+RwKquhQpn868yZsCtJYiclZF1u8l6WZxxKi+vv7Rg==} dev: false @@ -1158,7 +1321,6 @@ packages: /tslib/2.4.0: resolution: {integrity: sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==} - dev: false /tsutils/3.21.0_typescript@4.8.4: resolution: {integrity: sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==} @@ -1233,6 +1395,15 @@ packages: engines: {node: '>=0.10.0'} dev: false + /wrap-ansi/7.0.0: + resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==} + engines: {node: '>=10'} + dependencies: + ansi-styles: 4.3.0 + string-width: 4.2.3 + strip-ansi: 6.0.1 + dev: true + /wrappy/1.0.2: resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} dev: false @@ -1250,10 +1421,33 @@ packages: optional: true dev: false + /y18n/5.0.8: + resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==} + engines: {node: '>=10'} + dev: true + /yallist/4.0.0: resolution: {integrity: sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==} dev: false + /yargs-parser/21.1.1: + resolution: {integrity: sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==} + engines: {node: '>=12'} + dev: true + + /yargs/17.6.2: + resolution: {integrity: sha512-1/9UrdHjDZc0eOU0HxOHoS78C69UD3JRMvzlJ7S79S2nTaWRA/whGCTV8o9e/N/1Va9YIV7Q4sOxD8VV4pCWOw==} + engines: {node: '>=12'} + dependencies: + cliui: 8.0.1 + escalade: 3.1.1 + get-caller-file: 2.0.5 + require-directory: 2.1.1 + string-width: 4.2.3 + y18n: 5.0.8 + yargs-parser: 21.1.1 + dev: true + /yocto-queue/0.1.0: resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} engines: {node: '>=10'} diff --git a/prisma/schema.prisma b/prisma/schema.prisma new file mode 100644 index 0000000..d205f42 --- /dev/null +++ b/prisma/schema.prisma @@ -0,0 +1,11 @@ +// This is your Prisma schema file, +// learn more about it in the docs: https://pris.ly/d/prisma-schema + +generator client { + provider = "prisma-client-js" +} + +datasource db { + provider = "postgresql" + url = env("DATABASE_URL") +} diff --git a/src/commands/fun/deepfry.ts b/src/commands/fun/deepfry.ts new file mode 100644 index 0000000..ce9ce9c --- /dev/null +++ b/src/commands/fun/deepfry.ts @@ -0,0 +1,34 @@ +import type { CommandInteraction } from "discord.js"; +import { Discord, Slash, SlashOption } from "discordx"; +import { Category } from "@discordx/utilities"; +import axios from "axios"; +import { ApplicationCommandOptionType, User } from "discord.js"; + +@Discord() +@Category("Fun") +export class DeepfryCommand { + @Slash({ description: "DEEP-FRY selected user", name: "deepfry" }) + async deepfry( + @SlashOption({ + description: "User to deep-fry", + name: "user", + type: ApplicationCommandOptionType.User, + required: true, + }) + user: User, + interaction: CommandInteraction, + ): Promise { + await interaction.deferReply(); + const avatar = user.displayAvatarURL({ size: 512 }); + const { data } = await axios.get(`https://nekobot.xyz/api/imagegen?type=deepfry&image=${avatar}`); + + await interaction.editReply({ + files: [ + { + attachment: data.message, + name: "deepfry.png", + }, + ], + }); + } +} diff --git a/src/commands/fun/magik.ts b/src/commands/fun/magik.ts new file mode 100644 index 0000000..8028387 --- /dev/null +++ b/src/commands/fun/magik.ts @@ -0,0 +1,34 @@ +import type { CommandInteraction } from "discord.js"; +import { ApplicationCommandOptionType, User } from "discord.js"; +import { Discord, Slash, SlashOption } from "discordx"; +import { Category } from "@discordx/utilities"; +import axios from "axios"; + +@Discord() +@Category("Fun") +export class MagikCommand { + @Slash({ description: "Somehow perform ritual to selected user", name: "magik" }) + async magik( + @SlashOption({ + description: "User to perform ritual on", + name: "user", + type: ApplicationCommandOptionType.User, + required: true, + }) + user: User, + interaction: CommandInteraction, + ): Promise { + await interaction.deferReply(); + const avatar = user.displayAvatarURL({ size: 512 }); + const { data } = await axios.get(`https://nekobot.xyz/api/imagegen?type=magik&image=${avatar}&intensity=1`); + + await interaction.editReply({ + files: [ + { + attachment: data.message, + name: "magik.png", + }, + ], + }); + } +} diff --git a/src/commands/fun/meme.ts b/src/commands/fun/meme.ts new file mode 100644 index 0000000..9b92525 --- /dev/null +++ b/src/commands/fun/meme.ts @@ -0,0 +1,59 @@ +import type { CommandInteraction } from "discord.js"; +import { + ActionRowBuilder, + ButtonBuilder, ButtonInteraction, + ButtonStyle, Colors, + EmbedBuilder, +} from "discord.js"; +import { ButtonComponent, Discord, Slash } from "discordx"; +import { Category } from "@discordx/utilities"; +import axios from "axios"; + +@Discord() +@Category("Fun") +export class MemeCommand { + public static buttonRow = new ActionRowBuilder().addComponents( + new ButtonBuilder() + .setLabel("NEXT") + .setCustomId("next") + .setStyle(ButtonStyle.Primary), + ); + + public static async fetchMemes(): Promise { + const { data } = await axios.get("https://meme-api.herokuapp.com/gimme"); + return data; + } + + @ButtonComponent({ id: "next" }) + async handler(interaction: ButtonInteraction): Promise { + await interaction.deferUpdate(); + const data = await MemeCommand.fetchMemes(); + await interaction.editReply({ + embeds: [ + new EmbedBuilder() + .setTitle(data.title) + .setImage(data.url) + .setURL(data.postLink) + .setColor(Colors.Green), + ], + components: [MemeCommand.buttonRow], + }); + } + + @Slash({ description: "Get random memes", name: "meme" }) + async meme( + interaction: CommandInteraction, + ): Promise { + const data = await MemeCommand.fetchMemes(); + await interaction.reply({ + embeds: [ + new EmbedBuilder() + .setTitle(data.title) + .setImage(data.url) + .setURL(data.postLink) + .setColor(Colors.Green), + ], + components: [MemeCommand.buttonRow], + }); + } +} diff --git a/src/commands/misc/help.ts b/src/commands/misc/help.ts index ce806d9..2003e96 100644 --- a/src/commands/misc/help.ts +++ b/src/commands/misc/help.ts @@ -1,9 +1,9 @@ -import { Discord, MetadataStorage, Slash, SlashGroup } from "discordx"; -import { EmbedBuilder, Colors, CommandInteraction } from "discord.js"; +import type { DApplicationCommand } from "discordx"; +import { Discord, MetadataStorage, Slash, SlashGroup, SlashOption } from "discordx"; +import { ApplicationCommandOptionType, Colors, CommandInteraction, EmbedBuilder } from "discord.js"; import { Category, ICategory } from "@discordx/utilities"; import { Pagination } from "@discordx/pagination"; import { bot } from "../../index.js"; -import type { DApplicationCommand } from "discordx"; @Discord() @Category("Miscellaneous") @@ -17,7 +17,11 @@ export class HelpCommand { async all(interaction: CommandInteraction) { const commands = MetadataStorage.instance.applicationCommandSlashesFlat.map( (cmd: DApplicationCommand & ICategory) => { - return { description: cmd.description, name: cmd.name, category: cmd.category }; + return { + description: cmd.description, + name: cmd.group ? `${cmd.group} (${cmd.name})` : cmd.name, + category: cmd.category, + }; }, ); const categories = new Set(commands.map((c) => c.category)); @@ -41,4 +45,50 @@ export class HelpCommand { const pagination = new Pagination(interaction, pages); await pagination.send(); } + + @Slash({ description: "Show info about a specific command" }) + async command( + @SlashOption({ + description: "Command to get info from", + name: "command", + type: ApplicationCommandOptionType.String, + required: true, + }) + command: string, + interaction: CommandInteraction, + ): Promise { + const cmd = MetadataStorage.instance.applicationCommandSlashesFlat.find( + (c: DApplicationCommand & ICategory) => c.name === command, + ) as DApplicationCommand & ICategory; + if (!cmd) { + await interaction.reply({ + content: `Command \`${command}\` not found.`, + ephemeral: true, + }); + return; + } + + const embed = new EmbedBuilder() + .setColor(Colors.Blue) + .setFooter({ + text: "You can send `/help all` to get a list of all commands.", + iconURL: interaction.user.avatarURL()!, + }) + .setThumbnail(bot.user!.displayAvatarURL()) + .setTitle(cmd.name.toUpperCase()) + .addFields({ + name: "Description", + value: cmd.description, + }) + .addFields({ + name: "Category", + value: String(cmd.category), + }) + .addFields({ + name: "Options", + value: cmd.options?.map((o) => `\`${o.name}\` - ${o.description}`).join("\n") || "None", + }); + + await interaction.reply({ embeds: [embed] }); + } } diff --git a/src/index.ts b/src/index.ts index ce6fb3b..347ac24 100644 --- a/src/index.ts +++ b/src/index.ts @@ -5,10 +5,10 @@ import { ActivityType, GatewayIntentBits } from "discord-api-types/v10"; import { debuglog } from "util"; import type { Interaction } from "discord.js"; +export const botLog = debuglog("bot"); const NODE_ENV = process.env.NODE_ENV === "production"; const TOKEN = NODE_ENV ? process.env.MOORE_TOKEN : process.env.MOORE_DEV_TOKEN; const CLIENT_ID = NODE_ENV ? process.env.MOORE_CLIENT_ID : process.env.MOORE_DEV_CLIENT_ID; -const BOT_LOG = debuglog("bot"); export const bot = new Client({ botId: CLIENT_ID, @@ -21,6 +21,14 @@ export const bot = new Client({ }); bot.once("ready", async () => { + // To clear all guild commands, uncomment this line, + // This is useful when moving from guild commands to global commands + // It must only be executed once + // + // await bot.clearApplicationCommands( + // ...bot.guilds.cache.map((g) => g.id) + // ); + await bot.guilds.fetch(); await bot.initApplicationCommands(); @@ -28,7 +36,7 @@ bot.once("ready", async () => { type: ActivityType.Watching, }); - BOT_LOG("Logged in as %s", bot.user?.tag); + botLog("Logged in as %s", bot.user?.tag); }); bot.on("interactionCreate", (interaction: Interaction) => {