├── .gitignore ├── README.md ├── package-lock.json ├── package.json └── src ├── bot.ts ├── classes ├── Bot.ts ├── CommandListener.ts └── Rest.ts ├── commands ├── index.ts └── ping.ts └── interfaces └── Command.ts /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | lerna-debug.log* 8 | .pnpm-debug.log* 9 | 10 | # Diagnostic reports (https://nodejs.org/api/report.html) 11 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json 12 | 13 | # Runtime data 14 | pids 15 | *.pid 16 | *.seed 17 | *.pid.lock 18 | 19 | # Directory for instrumented libs generated by jscoverage/JSCover 20 | lib-cov 21 | 22 | # Coverage directory used by tools like istanbul 23 | coverage 24 | *.lcov 25 | 26 | # nyc test coverage 27 | .nyc_output 28 | 29 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) 30 | .grunt 31 | 32 | # Bower dependency directory (https://bower.io/) 33 | bower_components 34 | 35 | # node-waf configuration 36 | .lock-wscript 37 | 38 | # Compiled binary addons (https://nodejs.org/api/addons.html) 39 | build/Release 40 | 41 | # Dependency directories 42 | node_modules/ 43 | jspm_packages/ 44 | 45 | # Snowpack dependency directory (https://snowpack.dev/) 46 | web_modules/ 47 | 48 | # TypeScript cache 49 | *.tsbuildinfo 50 | 51 | # Optional npm cache directory 52 | .npm 53 | 54 | # Optional eslint cache 55 | .eslintcache 56 | 57 | # Microbundle cache 58 | .rpt2_cache/ 59 | .rts2_cache_cjs/ 60 | .rts2_cache_es/ 61 | .rts2_cache_umd/ 62 | 63 | # Optional REPL history 64 | .node_repl_history 65 | 66 | # Output of 'npm pack' 67 | *.tgz 68 | 69 | # Yarn Integrity file 70 | .yarn-integrity 71 | 72 | # dotenv environment variables file 73 | .env 74 | .env.test 75 | .env.production 76 | 77 | # parcel-bundler cache (https://parceljs.org/) 78 | .cache 79 | .parcel-cache 80 | 81 | # Next.js build output 82 | .next 83 | out 84 | 85 | # Nuxt.js build / generate output 86 | .nuxt 87 | dist 88 | 89 | # Gatsby files 90 | .cache/ 91 | # Comment in the public line in if your project uses Gatsby and not Next.js 92 | # https://nextjs.org/blog/next-9-1#public-directory-support 93 | # public 94 | 95 | # vuepress build output 96 | .vuepress/dist 97 | 98 | # Serverless directories 99 | .serverless/ 100 | 101 | # FuseBox cache 102 | .fusebox/ 103 | 104 | # DynamoDB Local files 105 | .dynamodb/ 106 | 107 | # TernJS port file 108 | .tern-port 109 | 110 | # Stores VSCode versions used for testing VSCode extensions 111 | .vscode-test 112 | 113 | # yarn v2 114 | .yarn/cache 115 | .yarn/unplugged 116 | .yarn/build-state.yml 117 | .yarn/install-state.gz 118 | .pnp.* -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

2 | 3 |

Tutorial Discord Bot

4 |

5 | 6 |
7 |

8 | 9 | Servidor do Discord 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 |

21 | 22 | Este é um projeto gravado em uma série de videos no meu [canal](https://www.youtube.com/gumpflash) do youtube, onde ensino como criar um bot no Discord com [discord.js](https://discord.js.org). 23 | 24 | ### Acompanhe os videos do projeto: 25 | 26 | 1. [Configurando o Projeto](https://youtu.be/5d_SAvD9xuQ) 27 | 2. [Iniciando o Bot](https://youtu.be/IkyveMOEPHg) 28 | 3. [Comandos](https://youtu.be/HBma8LJRm7U) 29 | 4. [Opções de comandos](https://youtu.be/xQzjgyeoEfI) 30 | 31 | ### Instalação e Configuração 32 | 33 | Para baixar e instalar o projeto você precisa ter o [node](https://nodejs.org/en/), npm e git instalado. 34 | 35 | ```bash 36 | # Clone/Baixe o projeto 37 | $ git clone https://github.com/GumpFlash/tutorial-discord-bot.git 38 | 39 | # Entre na pasta baixada 40 | $ cd tutorial-discord-bot 41 | 42 | # Instale as dependências 43 | $ npm install 44 | 45 | # Se já tiver configurado -> Inicia o bot 46 | $ npm start 47 | ``` 48 | 49 | As configurações vão sendo feitas durante os videos, para saber como pegar seu token e iniciar seu bot veja o [1º Video](https://youtu.be/5d_SAvD9xuQ) 50 | -------------------------------------------------------------------------------- /package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "tutorialbot", 3 | "version": "1.0.0", 4 | "lockfileVersion": 2, 5 | "requires": true, 6 | "packages": { 7 | "": { 8 | "name": "tutorialbot", 9 | "version": "1.0.0", 10 | "license": "ISC", 11 | "dependencies": { 12 | "@discordjs/builders": "^0.5.0", 13 | "@discordjs/rest": "^0.1.0-canary.0", 14 | "discord-api-types": "^0.22.0", 15 | "discord.js": "^13.1.0", 16 | "dotenv": "^10.0.0" 17 | } 18 | }, 19 | "node_modules/@discordjs/builders": { 20 | "version": "0.5.0", 21 | "resolved": "https://registry.npmjs.org/@discordjs/builders/-/builders-0.5.0.tgz", 22 | "integrity": "sha512-HP5y4Rqw68o61Qv4qM5tVmDbWi4mdTFftqIOGRo33SNPpLJ1Ga3KEIR2ibKofkmsoQhEpLmopD1AZDs3cKpHuw==", 23 | "dependencies": { 24 | "@sindresorhus/is": "^4.0.1", 25 | "discord-api-types": "^0.22.0", 26 | "ow": "^0.27.0", 27 | "ts-mixer": "^6.0.0", 28 | "tslib": "^2.3.0" 29 | }, 30 | "engines": { 31 | "node": ">=14.0.0", 32 | "npm": ">=7.0.0" 33 | } 34 | }, 35 | "node_modules/@discordjs/collection": { 36 | "version": "0.1.6", 37 | "resolved": "https://registry.npmjs.org/@discordjs/collection/-/collection-0.1.6.tgz", 38 | "integrity": "sha512-utRNxnd9kSS2qhyivo9lMlt5qgAUasH2gb7BEOn6p0efFh24gjGomHzWKMAPn2hEReOPQZCJaRKoURwRotKucQ==" 39 | }, 40 | "node_modules/@discordjs/form-data": { 41 | "version": "3.0.1", 42 | "resolved": "https://registry.npmjs.org/@discordjs/form-data/-/form-data-3.0.1.tgz", 43 | "integrity": "sha512-ZfFsbgEXW71Rw/6EtBdrP5VxBJy4dthyC0tpQKGKmYFImlmmrykO14Za+BiIVduwjte0jXEBlhSKf0MWbFp9Eg==", 44 | "dependencies": { 45 | "asynckit": "^0.4.0", 46 | "combined-stream": "^1.0.8", 47 | "mime-types": "^2.1.12" 48 | }, 49 | "engines": { 50 | "node": ">= 6" 51 | } 52 | }, 53 | "node_modules/@discordjs/rest": { 54 | "version": "0.1.0-canary.0", 55 | "resolved": "https://registry.npmjs.org/@discordjs/rest/-/rest-0.1.0-canary.0.tgz", 56 | "integrity": "sha512-d+s//ISYVV+e0w/926wMEeO7vju+Pn11x1JM4tcmVMCHSDgpi6pnFCNAXF1TEdnDcy7xf9tq5cf2pQkb/7ySTQ==", 57 | "dependencies": { 58 | "@discordjs/collection": "^0.1.6", 59 | "@sapphire/async-queue": "^1.1.4", 60 | "@sapphire/snowflake": "^1.3.5", 61 | "abort-controller": "^3.0.0", 62 | "discord-api-types": "^0.18.1", 63 | "form-data": "^4.0.0", 64 | "node-fetch": "^2.6.1", 65 | "tslib": "^2.3.0" 66 | }, 67 | "engines": { 68 | "node": ">=16.0.0" 69 | } 70 | }, 71 | "node_modules/@discordjs/rest/node_modules/discord-api-types": { 72 | "version": "0.18.1", 73 | "resolved": "https://registry.npmjs.org/discord-api-types/-/discord-api-types-0.18.1.tgz", 74 | "integrity": "sha512-hNC38R9ZF4uaujaZQtQfm5CdQO58uhdkoHQAVvMfIL0LgOSZeW575W8H6upngQOuoxWd8tiRII3LLJm9zuQKYg==", 75 | "deprecated": "No longer supported. Install the latest release (0.20.2)", 76 | "engines": { 77 | "node": ">=12" 78 | } 79 | }, 80 | "node_modules/@sapphire/async-queue": { 81 | "version": "1.1.4", 82 | "resolved": "https://registry.npmjs.org/@sapphire/async-queue/-/async-queue-1.1.4.tgz", 83 | "integrity": "sha512-fFrlF/uWpGOX5djw5Mu2Hnnrunao75WGey0sP0J3jnhmrJ5TAPzHYOmytD5iN/+pMxS+f+u/gezqHa9tPhRHEA==", 84 | "engines": { 85 | "node": ">=14", 86 | "npm": ">=6" 87 | } 88 | }, 89 | "node_modules/@sapphire/snowflake": { 90 | "version": "1.3.6", 91 | "resolved": "https://registry.npmjs.org/@sapphire/snowflake/-/snowflake-1.3.6.tgz", 92 | "integrity": "sha512-QnzuLp+p9D7agynVub/zqlDVriDza9y3STArBhNiNBUgIX8+GL5FpQxstRfw1jDr5jkZUjcuKYAHxjIuXKdJAg==", 93 | "engines": { 94 | "node": ">=12", 95 | "npm": ">=6" 96 | } 97 | }, 98 | "node_modules/@sindresorhus/is": { 99 | "version": "4.0.1", 100 | "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-4.0.1.tgz", 101 | "integrity": "sha512-Qm9hBEBu18wt1PO2flE7LPb30BHMQt1eQgbV76YntdNk73XZGpn3izvGTYxbGgzXKgbCjiia0uxTd3aTNQrY/g==", 102 | "engines": { 103 | "node": ">=10" 104 | }, 105 | "funding": { 106 | "url": "https://github.com/sindresorhus/is?sponsor=1" 107 | } 108 | }, 109 | "node_modules/@types/node": { 110 | "version": "16.6.2", 111 | "resolved": "https://registry.npmjs.org/@types/node/-/node-16.6.2.tgz", 112 | "integrity": "sha512-LSw8TZt12ZudbpHc6EkIyDM3nHVWKYrAvGy6EAJfNfjusbwnThqjqxUKKRwuV3iWYeW/LYMzNgaq3MaLffQ2xA==" 113 | }, 114 | "node_modules/@types/ws": { 115 | "version": "7.4.7", 116 | "resolved": "https://registry.npmjs.org/@types/ws/-/ws-7.4.7.tgz", 117 | "integrity": "sha512-JQbbmxZTZehdc2iszGKs5oC3NFnjeay7mtAWrdt7qNtAVK0g19muApzAy4bm9byz79xa2ZnO/BOBC2R8RC5Lww==", 118 | "dependencies": { 119 | "@types/node": "*" 120 | } 121 | }, 122 | "node_modules/abort-controller": { 123 | "version": "3.0.0", 124 | "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz", 125 | "integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==", 126 | "dependencies": { 127 | "event-target-shim": "^5.0.0" 128 | }, 129 | "engines": { 130 | "node": ">=6.5" 131 | } 132 | }, 133 | "node_modules/asynckit": { 134 | "version": "0.4.0", 135 | "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", 136 | "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=" 137 | }, 138 | "node_modules/callsites": { 139 | "version": "3.1.0", 140 | "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", 141 | "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", 142 | "engines": { 143 | "node": ">=6" 144 | } 145 | }, 146 | "node_modules/combined-stream": { 147 | "version": "1.0.8", 148 | "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", 149 | "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", 150 | "dependencies": { 151 | "delayed-stream": "~1.0.0" 152 | }, 153 | "engines": { 154 | "node": ">= 0.8" 155 | } 156 | }, 157 | "node_modules/delayed-stream": { 158 | "version": "1.0.0", 159 | "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", 160 | "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=", 161 | "engines": { 162 | "node": ">=0.4.0" 163 | } 164 | }, 165 | "node_modules/discord-api-types": { 166 | "version": "0.22.0", 167 | "resolved": "https://registry.npmjs.org/discord-api-types/-/discord-api-types-0.22.0.tgz", 168 | "integrity": "sha512-l8yD/2zRbZItUQpy7ZxBJwaLX/Bs2TGaCthRppk8Sw24LOIWg12t9JEreezPoYD0SQcC2htNNo27kYEpYW/Srg==", 169 | "engines": { 170 | "node": ">=12" 171 | } 172 | }, 173 | "node_modules/discord.js": { 174 | "version": "13.1.0", 175 | "resolved": "https://registry.npmjs.org/discord.js/-/discord.js-13.1.0.tgz", 176 | "integrity": "sha512-gxO4CXKdHpqA+WKG+f5RNnd3srTDj5uFJHgOathksDE90YNq/Qijkd2WlMgTTMS6AJoEnHxI7G9eDQHCuZ+xDA==", 177 | "dependencies": { 178 | "@discordjs/builders": "^0.5.0", 179 | "@discordjs/collection": "^0.2.1", 180 | "@discordjs/form-data": "^3.0.1", 181 | "@sapphire/async-queue": "^1.1.4", 182 | "@types/ws": "^7.4.7", 183 | "discord-api-types": "^0.22.0", 184 | "node-fetch": "^2.6.1", 185 | "ws": "^7.5.1" 186 | }, 187 | "engines": { 188 | "node": ">=16.6.0", 189 | "npm": ">=7.0.0" 190 | } 191 | }, 192 | "node_modules/discord.js/node_modules/@discordjs/collection": { 193 | "version": "0.2.1", 194 | "resolved": "https://registry.npmjs.org/@discordjs/collection/-/collection-0.2.1.tgz", 195 | "integrity": "sha512-vhxqzzM8gkomw0TYRF3tgx7SwElzUlXT/Aa41O7mOcyN6wIJfj5JmDWaO5XGKsGSsNx7F3i5oIlrucCCWV1Nog==", 196 | "engines": { 197 | "node": ">=14.0.0" 198 | } 199 | }, 200 | "node_modules/dot-prop": { 201 | "version": "6.0.1", 202 | "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-6.0.1.tgz", 203 | "integrity": "sha512-tE7ztYzXHIeyvc7N+hR3oi7FIbf/NIjVP9hmAt3yMXzrQ072/fpjGLx2GxNxGxUl5V73MEqYzioOMoVhGMJ5cA==", 204 | "dependencies": { 205 | "is-obj": "^2.0.0" 206 | }, 207 | "engines": { 208 | "node": ">=10" 209 | }, 210 | "funding": { 211 | "url": "https://github.com/sponsors/sindresorhus" 212 | } 213 | }, 214 | "node_modules/dotenv": { 215 | "version": "10.0.0", 216 | "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-10.0.0.tgz", 217 | "integrity": "sha512-rlBi9d8jpv9Sf1klPjNfFAuWDjKLwTIJJ/VxtoTwIR6hnZxcEOQCZg2oIL3MWBYw5GpUDKOEnND7LXTbIpQ03Q==", 218 | "engines": { 219 | "node": ">=10" 220 | } 221 | }, 222 | "node_modules/event-target-shim": { 223 | "version": "5.0.1", 224 | "resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz", 225 | "integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==", 226 | "engines": { 227 | "node": ">=6" 228 | } 229 | }, 230 | "node_modules/form-data": { 231 | "version": "4.0.0", 232 | "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", 233 | "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", 234 | "dependencies": { 235 | "asynckit": "^0.4.0", 236 | "combined-stream": "^1.0.8", 237 | "mime-types": "^2.1.12" 238 | }, 239 | "engines": { 240 | "node": ">= 6" 241 | } 242 | }, 243 | "node_modules/is-obj": { 244 | "version": "2.0.0", 245 | "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-2.0.0.tgz", 246 | "integrity": "sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==", 247 | "engines": { 248 | "node": ">=8" 249 | } 250 | }, 251 | "node_modules/lodash.isequal": { 252 | "version": "4.5.0", 253 | "resolved": "https://registry.npmjs.org/lodash.isequal/-/lodash.isequal-4.5.0.tgz", 254 | "integrity": "sha1-QVxEePK8wwEgwizhDtMib30+GOA=" 255 | }, 256 | "node_modules/mime-db": { 257 | "version": "1.49.0", 258 | "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.49.0.tgz", 259 | "integrity": "sha512-CIc8j9URtOVApSFCQIF+VBkX1RwXp/oMMOrqdyXSBXq5RWNEsRfyj1kiRnQgmNXmHxPoFIxOroKA3zcU9P+nAA==", 260 | "engines": { 261 | "node": ">= 0.6" 262 | } 263 | }, 264 | "node_modules/mime-types": { 265 | "version": "2.1.32", 266 | "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.32.tgz", 267 | "integrity": "sha512-hJGaVS4G4c9TSMYh2n6SQAGrC4RnfU+daP8G7cSCmaqNjiOoUY0VHCMS42pxnQmVF1GWwFhbHWn3RIxCqTmZ9A==", 268 | "dependencies": { 269 | "mime-db": "1.49.0" 270 | }, 271 | "engines": { 272 | "node": ">= 0.6" 273 | } 274 | }, 275 | "node_modules/node-fetch": { 276 | "version": "2.6.1", 277 | "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.1.tgz", 278 | "integrity": "sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw==", 279 | "engines": { 280 | "node": "4.x || >=6.0.0" 281 | } 282 | }, 283 | "node_modules/ow": { 284 | "version": "0.27.0", 285 | "resolved": "https://registry.npmjs.org/ow/-/ow-0.27.0.tgz", 286 | "integrity": "sha512-SGnrGUbhn4VaUGdU0EJLMwZWSupPmF46hnTRII7aCLCrqixTAC5eKo8kI4/XXf1eaaI8YEVT+3FeGNJI9himAQ==", 287 | "dependencies": { 288 | "@sindresorhus/is": "^4.0.1", 289 | "callsites": "^3.1.0", 290 | "dot-prop": "^6.0.1", 291 | "lodash.isequal": "^4.5.0", 292 | "type-fest": "^1.2.1", 293 | "vali-date": "^1.0.0" 294 | }, 295 | "engines": { 296 | "node": ">=12" 297 | }, 298 | "funding": { 299 | "url": "https://github.com/sponsors/sindresorhus" 300 | } 301 | }, 302 | "node_modules/ts-mixer": { 303 | "version": "6.0.0", 304 | "resolved": "https://registry.npmjs.org/ts-mixer/-/ts-mixer-6.0.0.tgz", 305 | "integrity": "sha512-nXIb1fvdY5CBSrDIblLn73NW0qRDk5yJ0Sk1qPBF560OdJfQp9jhl+0tzcY09OZ9U+6GpeoI9RjwoIKFIoB9MQ==" 306 | }, 307 | "node_modules/tslib": { 308 | "version": "2.3.1", 309 | "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.1.tgz", 310 | "integrity": "sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw==" 311 | }, 312 | "node_modules/type-fest": { 313 | "version": "1.4.0", 314 | "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-1.4.0.tgz", 315 | "integrity": "sha512-yGSza74xk0UG8k+pLh5oeoYirvIiWo5t0/o3zHHAO2tRDiZcxWP7fywNlXhqb6/r6sWvwi+RsyQMWhVLe4BVuA==", 316 | "engines": { 317 | "node": ">=10" 318 | }, 319 | "funding": { 320 | "url": "https://github.com/sponsors/sindresorhus" 321 | } 322 | }, 323 | "node_modules/vali-date": { 324 | "version": "1.0.0", 325 | "resolved": "https://registry.npmjs.org/vali-date/-/vali-date-1.0.0.tgz", 326 | "integrity": "sha1-G5BKWWCfsyjvB4E4Qgk09rhnCaY=", 327 | "engines": { 328 | "node": ">=0.10.0" 329 | } 330 | }, 331 | "node_modules/ws": { 332 | "version": "7.5.3", 333 | "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.3.tgz", 334 | "integrity": "sha512-kQ/dHIzuLrS6Je9+uv81ueZomEwH0qVYstcAQ4/Z93K8zeko9gtAbttJWzoC5ukqXY1PpoouV3+VSOqEAFt5wg==", 335 | "engines": { 336 | "node": ">=8.3.0" 337 | }, 338 | "peerDependencies": { 339 | "bufferutil": "^4.0.1", 340 | "utf-8-validate": "^5.0.2" 341 | }, 342 | "peerDependenciesMeta": { 343 | "bufferutil": { 344 | "optional": true 345 | }, 346 | "utf-8-validate": { 347 | "optional": true 348 | } 349 | } 350 | } 351 | }, 352 | "dependencies": { 353 | "@discordjs/builders": { 354 | "version": "0.5.0", 355 | "resolved": "https://registry.npmjs.org/@discordjs/builders/-/builders-0.5.0.tgz", 356 | "integrity": "sha512-HP5y4Rqw68o61Qv4qM5tVmDbWi4mdTFftqIOGRo33SNPpLJ1Ga3KEIR2ibKofkmsoQhEpLmopD1AZDs3cKpHuw==", 357 | "requires": { 358 | "@sindresorhus/is": "^4.0.1", 359 | "discord-api-types": "^0.22.0", 360 | "ow": "^0.27.0", 361 | "ts-mixer": "^6.0.0", 362 | "tslib": "^2.3.0" 363 | } 364 | }, 365 | "@discordjs/collection": { 366 | "version": "0.1.6", 367 | "resolved": "https://registry.npmjs.org/@discordjs/collection/-/collection-0.1.6.tgz", 368 | "integrity": "sha512-utRNxnd9kSS2qhyivo9lMlt5qgAUasH2gb7BEOn6p0efFh24gjGomHzWKMAPn2hEReOPQZCJaRKoURwRotKucQ==" 369 | }, 370 | "@discordjs/form-data": { 371 | "version": "3.0.1", 372 | "resolved": "https://registry.npmjs.org/@discordjs/form-data/-/form-data-3.0.1.tgz", 373 | "integrity": "sha512-ZfFsbgEXW71Rw/6EtBdrP5VxBJy4dthyC0tpQKGKmYFImlmmrykO14Za+BiIVduwjte0jXEBlhSKf0MWbFp9Eg==", 374 | "requires": { 375 | "asynckit": "^0.4.0", 376 | "combined-stream": "^1.0.8", 377 | "mime-types": "^2.1.12" 378 | } 379 | }, 380 | "@discordjs/rest": { 381 | "version": "0.1.0-canary.0", 382 | "resolved": "https://registry.npmjs.org/@discordjs/rest/-/rest-0.1.0-canary.0.tgz", 383 | "integrity": "sha512-d+s//ISYVV+e0w/926wMEeO7vju+Pn11x1JM4tcmVMCHSDgpi6pnFCNAXF1TEdnDcy7xf9tq5cf2pQkb/7ySTQ==", 384 | "requires": { 385 | "@discordjs/collection": "^0.1.6", 386 | "@sapphire/async-queue": "^1.1.4", 387 | "@sapphire/snowflake": "^1.3.5", 388 | "abort-controller": "^3.0.0", 389 | "discord-api-types": "^0.18.1", 390 | "form-data": "^4.0.0", 391 | "node-fetch": "^2.6.1", 392 | "tslib": "^2.3.0" 393 | }, 394 | "dependencies": { 395 | "discord-api-types": { 396 | "version": "0.18.1", 397 | "resolved": "https://registry.npmjs.org/discord-api-types/-/discord-api-types-0.18.1.tgz", 398 | "integrity": "sha512-hNC38R9ZF4uaujaZQtQfm5CdQO58uhdkoHQAVvMfIL0LgOSZeW575W8H6upngQOuoxWd8tiRII3LLJm9zuQKYg==" 399 | } 400 | } 401 | }, 402 | "@sapphire/async-queue": { 403 | "version": "1.1.4", 404 | "resolved": "https://registry.npmjs.org/@sapphire/async-queue/-/async-queue-1.1.4.tgz", 405 | "integrity": "sha512-fFrlF/uWpGOX5djw5Mu2Hnnrunao75WGey0sP0J3jnhmrJ5TAPzHYOmytD5iN/+pMxS+f+u/gezqHa9tPhRHEA==" 406 | }, 407 | "@sapphire/snowflake": { 408 | "version": "1.3.6", 409 | "resolved": "https://registry.npmjs.org/@sapphire/snowflake/-/snowflake-1.3.6.tgz", 410 | "integrity": "sha512-QnzuLp+p9D7agynVub/zqlDVriDza9y3STArBhNiNBUgIX8+GL5FpQxstRfw1jDr5jkZUjcuKYAHxjIuXKdJAg==" 411 | }, 412 | "@sindresorhus/is": { 413 | "version": "4.0.1", 414 | "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-4.0.1.tgz", 415 | "integrity": "sha512-Qm9hBEBu18wt1PO2flE7LPb30BHMQt1eQgbV76YntdNk73XZGpn3izvGTYxbGgzXKgbCjiia0uxTd3aTNQrY/g==" 416 | }, 417 | "@types/node": { 418 | "version": "16.6.2", 419 | "resolved": "https://registry.npmjs.org/@types/node/-/node-16.6.2.tgz", 420 | "integrity": "sha512-LSw8TZt12ZudbpHc6EkIyDM3nHVWKYrAvGy6EAJfNfjusbwnThqjqxUKKRwuV3iWYeW/LYMzNgaq3MaLffQ2xA==" 421 | }, 422 | "@types/ws": { 423 | "version": "7.4.7", 424 | "resolved": "https://registry.npmjs.org/@types/ws/-/ws-7.4.7.tgz", 425 | "integrity": "sha512-JQbbmxZTZehdc2iszGKs5oC3NFnjeay7mtAWrdt7qNtAVK0g19muApzAy4bm9byz79xa2ZnO/BOBC2R8RC5Lww==", 426 | "requires": { 427 | "@types/node": "*" 428 | } 429 | }, 430 | "abort-controller": { 431 | "version": "3.0.0", 432 | "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz", 433 | "integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==", 434 | "requires": { 435 | "event-target-shim": "^5.0.0" 436 | } 437 | }, 438 | "asynckit": { 439 | "version": "0.4.0", 440 | "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", 441 | "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=" 442 | }, 443 | "callsites": { 444 | "version": "3.1.0", 445 | "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", 446 | "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==" 447 | }, 448 | "combined-stream": { 449 | "version": "1.0.8", 450 | "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", 451 | "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", 452 | "requires": { 453 | "delayed-stream": "~1.0.0" 454 | } 455 | }, 456 | "delayed-stream": { 457 | "version": "1.0.0", 458 | "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", 459 | "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=" 460 | }, 461 | "discord-api-types": { 462 | "version": "0.22.0", 463 | "resolved": "https://registry.npmjs.org/discord-api-types/-/discord-api-types-0.22.0.tgz", 464 | "integrity": "sha512-l8yD/2zRbZItUQpy7ZxBJwaLX/Bs2TGaCthRppk8Sw24LOIWg12t9JEreezPoYD0SQcC2htNNo27kYEpYW/Srg==" 465 | }, 466 | "discord.js": { 467 | "version": "13.1.0", 468 | "resolved": "https://registry.npmjs.org/discord.js/-/discord.js-13.1.0.tgz", 469 | "integrity": "sha512-gxO4CXKdHpqA+WKG+f5RNnd3srTDj5uFJHgOathksDE90YNq/Qijkd2WlMgTTMS6AJoEnHxI7G9eDQHCuZ+xDA==", 470 | "requires": { 471 | "@discordjs/builders": "^0.5.0", 472 | "@discordjs/collection": "^0.2.1", 473 | "@discordjs/form-data": "^3.0.1", 474 | "@sapphire/async-queue": "^1.1.4", 475 | "@types/ws": "^7.4.7", 476 | "discord-api-types": "^0.22.0", 477 | "node-fetch": "^2.6.1", 478 | "ws": "^7.5.1" 479 | }, 480 | "dependencies": { 481 | "@discordjs/collection": { 482 | "version": "0.2.1", 483 | "resolved": "https://registry.npmjs.org/@discordjs/collection/-/collection-0.2.1.tgz", 484 | "integrity": "sha512-vhxqzzM8gkomw0TYRF3tgx7SwElzUlXT/Aa41O7mOcyN6wIJfj5JmDWaO5XGKsGSsNx7F3i5oIlrucCCWV1Nog==" 485 | } 486 | } 487 | }, 488 | "dot-prop": { 489 | "version": "6.0.1", 490 | "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-6.0.1.tgz", 491 | "integrity": "sha512-tE7ztYzXHIeyvc7N+hR3oi7FIbf/NIjVP9hmAt3yMXzrQ072/fpjGLx2GxNxGxUl5V73MEqYzioOMoVhGMJ5cA==", 492 | "requires": { 493 | "is-obj": "^2.0.0" 494 | } 495 | }, 496 | "dotenv": { 497 | "version": "10.0.0", 498 | "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-10.0.0.tgz", 499 | "integrity": "sha512-rlBi9d8jpv9Sf1klPjNfFAuWDjKLwTIJJ/VxtoTwIR6hnZxcEOQCZg2oIL3MWBYw5GpUDKOEnND7LXTbIpQ03Q==" 500 | }, 501 | "event-target-shim": { 502 | "version": "5.0.1", 503 | "resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz", 504 | "integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==" 505 | }, 506 | "form-data": { 507 | "version": "4.0.0", 508 | "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", 509 | "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", 510 | "requires": { 511 | "asynckit": "^0.4.0", 512 | "combined-stream": "^1.0.8", 513 | "mime-types": "^2.1.12" 514 | } 515 | }, 516 | "is-obj": { 517 | "version": "2.0.0", 518 | "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-2.0.0.tgz", 519 | "integrity": "sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==" 520 | }, 521 | "lodash.isequal": { 522 | "version": "4.5.0", 523 | "resolved": "https://registry.npmjs.org/lodash.isequal/-/lodash.isequal-4.5.0.tgz", 524 | "integrity": "sha1-QVxEePK8wwEgwizhDtMib30+GOA=" 525 | }, 526 | "mime-db": { 527 | "version": "1.49.0", 528 | "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.49.0.tgz", 529 | "integrity": "sha512-CIc8j9URtOVApSFCQIF+VBkX1RwXp/oMMOrqdyXSBXq5RWNEsRfyj1kiRnQgmNXmHxPoFIxOroKA3zcU9P+nAA==" 530 | }, 531 | "mime-types": { 532 | "version": "2.1.32", 533 | "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.32.tgz", 534 | "integrity": "sha512-hJGaVS4G4c9TSMYh2n6SQAGrC4RnfU+daP8G7cSCmaqNjiOoUY0VHCMS42pxnQmVF1GWwFhbHWn3RIxCqTmZ9A==", 535 | "requires": { 536 | "mime-db": "1.49.0" 537 | } 538 | }, 539 | "node-fetch": { 540 | "version": "2.6.1", 541 | "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.1.tgz", 542 | "integrity": "sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw==" 543 | }, 544 | "ow": { 545 | "version": "0.27.0", 546 | "resolved": "https://registry.npmjs.org/ow/-/ow-0.27.0.tgz", 547 | "integrity": "sha512-SGnrGUbhn4VaUGdU0EJLMwZWSupPmF46hnTRII7aCLCrqixTAC5eKo8kI4/XXf1eaaI8YEVT+3FeGNJI9himAQ==", 548 | "requires": { 549 | "@sindresorhus/is": "^4.0.1", 550 | "callsites": "^3.1.0", 551 | "dot-prop": "^6.0.1", 552 | "lodash.isequal": "^4.5.0", 553 | "type-fest": "^1.2.1", 554 | "vali-date": "^1.0.0" 555 | } 556 | }, 557 | "ts-mixer": { 558 | "version": "6.0.0", 559 | "resolved": "https://registry.npmjs.org/ts-mixer/-/ts-mixer-6.0.0.tgz", 560 | "integrity": "sha512-nXIb1fvdY5CBSrDIblLn73NW0qRDk5yJ0Sk1qPBF560OdJfQp9jhl+0tzcY09OZ9U+6GpeoI9RjwoIKFIoB9MQ==" 561 | }, 562 | "tslib": { 563 | "version": "2.3.1", 564 | "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.1.tgz", 565 | "integrity": "sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw==" 566 | }, 567 | "type-fest": { 568 | "version": "1.4.0", 569 | "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-1.4.0.tgz", 570 | "integrity": "sha512-yGSza74xk0UG8k+pLh5oeoYirvIiWo5t0/o3zHHAO2tRDiZcxWP7fywNlXhqb6/r6sWvwi+RsyQMWhVLe4BVuA==" 571 | }, 572 | "vali-date": { 573 | "version": "1.0.0", 574 | "resolved": "https://registry.npmjs.org/vali-date/-/vali-date-1.0.0.tgz", 575 | "integrity": "sha1-G5BKWWCfsyjvB4E4Qgk09rhnCaY=" 576 | }, 577 | "ws": { 578 | "version": "7.5.3", 579 | "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.3.tgz", 580 | "integrity": "sha512-kQ/dHIzuLrS6Je9+uv81ueZomEwH0qVYstcAQ4/Z93K8zeko9gtAbttJWzoC5ukqXY1PpoouV3+VSOqEAFt5wg==", 581 | "requires": {} 582 | } 583 | } 584 | } 585 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "tutorialbot", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "src/bot.ts", 6 | "scripts": { 7 | "start": "ts-node-dev .", 8 | "prod": "ts-node .", 9 | "test": "echo \"Error: no test specified\" && exit 1" 10 | }, 11 | "author": "", 12 | "license": "ISC", 13 | "dependencies": { 14 | "@discordjs/builders": "^0.5.0", 15 | "@discordjs/rest": "^0.1.0-canary.0", 16 | "discord-api-types": "^0.22.0", 17 | "discord.js": "^13.1.0", 18 | "dotenv": "^10.0.0" 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/bot.ts: -------------------------------------------------------------------------------- 1 | import Bot from "./classes/Bot"; 2 | import { config } from "dotenv"; 3 | import Rest from "./classes/Rest"; 4 | import Commands from "./commands"; 5 | import CommandListener from "./classes/CommandListener"; 6 | 7 | config(); 8 | 9 | const init = () => { 10 | if (!process.env.TOKEN) { 11 | console.error("O Token não foi encontrado!"); 12 | return; 13 | } 14 | if (!process.env.CLIENT_ID) { 15 | console.error("O ClientId não foi encontrado!"); 16 | return; 17 | } 18 | 19 | const rest = new Rest(process.env.TOKEN, process.env.CLIENT_ID); 20 | rest.registerCommands(Commands); 21 | rest.start(); 22 | const bot = new Bot(process.env.TOKEN); 23 | const commands = new CommandListener(Commands); 24 | bot.start(); 25 | }; 26 | init(); 27 | -------------------------------------------------------------------------------- /src/classes/Bot.ts: -------------------------------------------------------------------------------- 1 | import { Client, Intents } from "discord.js"; 2 | 3 | const intents = [Intents.FLAGS.GUILDS]; 4 | 5 | class Bot { 6 | public static client: Client; 7 | constructor(private token: string) { 8 | Bot.client = new Client({ intents }); 9 | Bot.client.on("ready", () => { 10 | if (Bot.client.user) 11 | console.log(`O bot está funcionando como ${Bot.client.user.tag}!`); 12 | }); 13 | } 14 | start() { 15 | Bot.client.login(this.token); 16 | } 17 | } 18 | 19 | export default Bot; 20 | -------------------------------------------------------------------------------- /src/classes/CommandListener.ts: -------------------------------------------------------------------------------- 1 | import Command from "../interfaces/Command"; 2 | import Bot from "./Bot"; 3 | 4 | class CommandListener { 5 | constructor(private commands: Command[]) { 6 | if (!Bot.client) return; 7 | Bot.client.on("interactionCreate", async (interaction) => { 8 | if (!interaction.isCommand()) return; 9 | 10 | this.commands.forEach((command) => { 11 | if (interaction.commandName === command.name) command.run(interaction); 12 | }); 13 | }); 14 | } 15 | } 16 | 17 | export default CommandListener; 18 | -------------------------------------------------------------------------------- /src/classes/Rest.ts: -------------------------------------------------------------------------------- 1 | import { SlashCommandBuilder } from "@discordjs/builders"; 2 | import { SlashCommandOptionBase } from "@discordjs/builders/dist/interactions/slashCommands/mixins/CommandOptionBase"; 3 | import { REST } from "@discordjs/rest"; 4 | import { Routes } from "discord-api-types/v9"; 5 | import Command, { Option, OptionType } from "../interfaces/Command"; 6 | 7 | class Rest { 8 | private rest: REST; 9 | private commands: Command[] = []; 10 | constructor(private token: string, private clientId: string) { 11 | this.rest = new REST({ version: "9" }).setToken(this.token); 12 | } 13 | registerCommands(commands: Command[]) { 14 | this.commands = commands; 15 | } 16 | start() { 17 | (async () => { 18 | try { 19 | console.log("Recarregando os comandos de barra da aplicação..."); 20 | await this.rest.put(Routes.applicationCommands(this.clientId), { 21 | body: this.commands.map((command) => { 22 | const data = new SlashCommandBuilder() 23 | .setName(command.name.toLowerCase()) 24 | .setDescription(command.description); 25 | const dataWithOptions = this.addFields(data, command.options); 26 | return dataWithOptions.toJSON(); 27 | }), 28 | }); 29 | console.log( 30 | "Os comandos de barra da aplicação foram recarregados com sucesso!" 31 | ); 32 | } catch (error) { 33 | console.error(error); 34 | } 35 | })(); 36 | } 37 | addField(slashOption: T, option: Option) { 38 | return slashOption 39 | .setName(option.name.toLowerCase()) 40 | .setDescription(option.description) 41 | .setRequired(option.required ? true : false); 42 | } 43 | addFields(data: SlashCommandBuilder, options?: Option[]) { 44 | options && 45 | options.forEach((option) => { 46 | switch (option.type) { 47 | case OptionType.Boolean: 48 | data.addBooleanOption((slashOption) => 49 | this.addField(slashOption, option) 50 | ); 51 | break; 52 | case OptionType.Channel: 53 | data.addChannelOption((slashOption) => 54 | this.addField(slashOption, option) 55 | ); 56 | break; 57 | case OptionType.Integer: 58 | data.addIntegerOption((slashOption) => { 59 | const newSlashOption = this.addField(slashOption, option); 60 | 61 | option.choices && 62 | option.choices.forEach((choice) => 63 | newSlashOption.addChoice(choice.name, parseInt(choice.value)) 64 | ); 65 | 66 | return newSlashOption; 67 | }); 68 | break; 69 | case OptionType.Mention: 70 | data.addMentionableOption((slashOption) => 71 | this.addField(slashOption, option) 72 | ); 73 | break; 74 | case OptionType.Role: 75 | data.addRoleOption((slashOption) => 76 | this.addField(slashOption, option) 77 | ); 78 | break; 79 | case OptionType.String: 80 | data.addStringOption((slashOption) => { 81 | const newSlashOption = this.addField(slashOption, option); 82 | 83 | option.choices && 84 | option.choices.forEach((choice) => 85 | newSlashOption.addChoice(choice.name, choice.value) 86 | ); 87 | 88 | return newSlashOption; 89 | }); 90 | break; 91 | case OptionType.User: 92 | data.addUserOption((slashOption) => 93 | this.addField(slashOption, option) 94 | ); 95 | break; 96 | } 97 | }); 98 | return data; 99 | } 100 | } 101 | 102 | export default Rest; 103 | -------------------------------------------------------------------------------- /src/commands/index.ts: -------------------------------------------------------------------------------- 1 | import { ping } from "./ping"; 2 | 3 | export default [ping]; 4 | -------------------------------------------------------------------------------- /src/commands/ping.ts: -------------------------------------------------------------------------------- 1 | import Command, { OptionType } from "../interfaces/Command"; 2 | 3 | export const ping: Command = { 4 | name: "ping", 5 | description: "responde com pong", 6 | options: [ 7 | { 8 | name: "nome", 9 | description: "nome da pessoa que vai receber o pong", 10 | type: OptionType.String, 11 | required: true, 12 | choices: [ 13 | { 14 | name: "Gump", 15 | value: "gump", 16 | }, 17 | { 18 | name: "Discord", 19 | value: "discord", 20 | }, 21 | ], 22 | }, 23 | ], 24 | run: async (interaction) => { 25 | const nome = interaction.options.data[0].value; 26 | 27 | await interaction.reply(`PONG ${nome}`); 28 | }, 29 | }; 30 | -------------------------------------------------------------------------------- /src/interfaces/Command.ts: -------------------------------------------------------------------------------- 1 | import { CommandInteraction } from "discord.js"; 2 | 3 | export interface Option { 4 | name: string; 5 | description: string; 6 | type: OptionType; 7 | required?: boolean; 8 | choices?: { 9 | name: string; 10 | value: string; 11 | }[]; 12 | } 13 | 14 | export enum OptionType { 15 | Boolean, 16 | Channel, 17 | Integer, 18 | Mention, 19 | Role, 20 | String, 21 | User, 22 | } 23 | 24 | export default interface Command { 25 | name: string; 26 | description: string; 27 | options?: Option[]; 28 | run: (interaction: CommandInteraction) => void; 29 | } 30 | --------------------------------------------------------------------------------