├── config.json ├── src ├── discord │ ├── commands │ │ ├── aCommandFormat │ │ └── uptimeCommand.js │ ├── CommandHandler.js │ ├── events │ │ └── interactionCreate.js │ └── DiscordManager.js ├── Application.js └── Logger.js ├── index.js ├── README.md ├── package.json └── .gitignore /config.json: -------------------------------------------------------------------------------- 1 | { 2 | "discord": { 3 | "token": "TOKEN", 4 | "clientID": "clientID", 5 | "serverID": "serverID" 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /src/discord/commands/aCommandFormat: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | name: '', 3 | description: '', 4 | options: [{ 5 | name: '', 6 | description: '', 7 | type: 3, 8 | required: false 9 | }], 10 | 11 | execute: async (interaction, client) => { 12 | 13 | }, 14 | }; -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | process.on("uncaughtException", function (err) { 2 | console.log(err); 3 | }); 4 | const app = require("./src/Application"); 5 | 6 | app 7 | .register() 8 | .then(() => { 9 | app.connect(); 10 | }) 11 | .catch((err) => { 12 | console.error(err); 13 | }); 14 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # discord-bot-blueprint-v14 2 | Simple blueprint for discord.js bot which has support for slash commands and other events. This bot is an attempt to show the basics of command and event handling in clean code. This can be used as the template for any type of bot, without my permissions. 3 | 4 | -------------------------------------------------------------------------------- /src/Application.js: -------------------------------------------------------------------------------- 1 | const DiscordManager = require("./discord/DiscordManager"); 2 | 3 | class Application { 4 | async register() { 5 | this.discord = new DiscordManager(this); 6 | } 7 | 8 | async connect() { 9 | this.discord.connect(); 10 | } 11 | } 12 | 13 | module.exports = new Application(); 14 | -------------------------------------------------------------------------------- /src/discord/commands/uptimeCommand.js: -------------------------------------------------------------------------------- 1 | const { EmbedBuilder } = require("discord.js"); 2 | 3 | module.exports = { 4 | name: "uptime", 5 | description: "Shows the uptime of the bot.", 6 | 7 | execute: async (interaction, client) => { 8 | const uptimeEmbed = new EmbedBuilder() 9 | .setColor(0x0099ff) 10 | .setTitle("🕐 Uptime!") 11 | // icb to make fancy fortmatting 12 | .setDescription(`${process.uptime()} seconds`) 13 | .setFooter({ 14 | text: `by DuckySoLucky#5181 | /help [command] for more information`, 15 | iconURL: "https://imgur.com/tgwQJTX.png", 16 | }); 17 | 18 | interaction.followUp({ embeds: [uptimeEmbed] }); 19 | }, 20 | }; 21 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "discord-bot-blueprint-v14", 3 | "version": "1.0.'", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "start": "node index.js" 8 | }, 9 | "repository": { 10 | "type": "git", 11 | "url": "git+https://github.com/DuckySoLucky/discord-bot-blueprint-v14.git" 12 | }, 13 | "bugs": { 14 | "url": "https://github.com/DuckySoLucky/discord-bot-blueprint-v14/issues" 15 | }, 16 | "homepage": "https://github.com/DuckySoLucky/discord-bot-blueprint-v14#readme", 17 | "author": "DuckySoLucky", 18 | "license": "MIT", 19 | "dependencies": { 20 | "@discordjs/rest": "^1.3.0", 21 | "chalk": "^4.1.0", 22 | "discord-api-types": "^0.37.14", 23 | "discord.js": "^14.6.0", 24 | "axios": "^0.27.2", 25 | "path": "^0.12.7" 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/discord/CommandHandler.js: -------------------------------------------------------------------------------- 1 | const { Routes } = require('discord-api-types/v9') 2 | const config = require('../../config.json') 3 | const { REST } = require('@discordjs/rest') 4 | const fs = require('fs') 5 | 6 | class CommandHandler { 7 | constructor(discord) { 8 | this.discord = discord 9 | 10 | const commands = [] 11 | const _commandFiles = fs.readdirSync('src/discord/commands').filter(file => file.endsWith('.js')) 12 | 13 | for (const file of _commandFiles) { 14 | const command = require(`./commands/${file}`) 15 | commands.push(command) 16 | } 17 | const rest = new REST({ version: '10' }).setToken(config.discord.token) 18 | 19 | rest.put(Routes.applicationGuildCommands(config.discord.clientID, config.discord.serverID), { body: commands }).catch(console.error) 20 | } 21 | } 22 | 23 | module.exports = CommandHandler -------------------------------------------------------------------------------- /src/discord/events/interactionCreate.js: -------------------------------------------------------------------------------- 1 | const Logger = require("../../Logger"); 2 | 3 | module.exports = { 4 | name: "interactionCreate", 5 | async execute(interaction) { 6 | if (interaction.isChatInputCommand()) { 7 | await interaction.deferReply({ ephemeral: false }).catch(() => {}); 8 | 9 | const command = interaction.client.commands.get(interaction.commandName); 10 | if (!command) return; 11 | 12 | try { 13 | Logger.discordMessage( 14 | `${interaction.user.username} - [${interaction.commandName}]` 15 | ); 16 | 17 | await command.execute(interaction, interaction.client); 18 | } catch (error) { 19 | console.log(error); 20 | await interaction.reply({ 21 | content: "There was an error while executing this command!", 22 | ephemeral: true, 23 | }); 24 | } 25 | } 26 | }, 27 | }; 28 | -------------------------------------------------------------------------------- /src/Logger.js: -------------------------------------------------------------------------------- 1 | const chalk = require("chalk"); 2 | 3 | async function discordMessage(message) { 4 | return console.log( 5 | chalk.bgMagenta.black(`[${await getCurrentTime()}] Discord >`) + 6 | " " + 7 | chalk.magenta(message) 8 | ); 9 | } 10 | 11 | async function logoutMessage(message) { 12 | return console.log( 13 | chalk.bgRedBright.black(`[${await getCurrentTime()}] Discord >`) + 14 | " " + 15 | chalk.redBright(message) 16 | ); 17 | } 18 | 19 | async function successfulMessage(message) { 20 | return console.log( 21 | chalk.bgGreenBright.black(`[${await getCurrentTime()}] Discord >`) + 22 | " " + 23 | chalk.greenBright(message) 24 | ); 25 | } 26 | 27 | async function warnMessage(message) { 28 | return console.log( 29 | chalk.bgYellow.black(`[${await getCurrentTime()}] Warning >`) + 30 | " " + 31 | chalk.yellow(message) 32 | ); 33 | } 34 | 35 | async function errorMessage(message) { 36 | return console.log( 37 | chalk.bgRedBright.black(`[${await getCurrentTime()}] Error >`) + 38 | " " + 39 | chalk.redBright(message) 40 | ); 41 | } 42 | 43 | async function broadcastMessage(message, location) { 44 | return console.log( 45 | chalk.inverse(`[${await getCurrentTime()}] ${location} Broadcast >`) + 46 | " " + 47 | message 48 | ); 49 | } 50 | 51 | async function getCurrentTime() { 52 | return new Date().toLocaleTimeString([], { 53 | hour: "2-digit", 54 | minute: "2-digit", 55 | hour12: false, 56 | }); 57 | } 58 | 59 | module.exports = { 60 | discordMessage, 61 | successfulMessage, 62 | logoutMessage, 63 | warnMessage, 64 | errorMessage, 65 | broadcastMessage, 66 | getCurrentTime, 67 | }; 68 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | lerna-debug.log* 8 | 9 | # Diagnostic reports (https://nodejs.org/api/report.html) 10 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json 11 | 12 | # Runtime data 13 | pids 14 | *.pid 15 | *.seed 16 | *.pid.lock 17 | 18 | # Directory for instrumented libs generated by jscoverage/JSCover 19 | lib-cov 20 | 21 | # Coverage directory used by tools like istanbul 22 | coverage 23 | *.lcov 24 | 25 | # nyc test coverage 26 | .nyc_output 27 | 28 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) 29 | .grunt 30 | 31 | # Bower dependency directory (https://bower.io/) 32 | bower_components 33 | 34 | # node-waf configuration 35 | .lock-wscript 36 | 37 | # Compiled binary addons (https://nodejs.org/api/addons.html) 38 | build/Release 39 | 40 | # Dependency directories 41 | node_modules/ 42 | jspm_packages/ 43 | 44 | # TypeScript v1 declaration files 45 | typings/ 46 | 47 | # TypeScript cache 48 | *.tsbuildinfo 49 | 50 | # Optional npm cache directory 51 | .npm 52 | 53 | # Optional eslint cache 54 | .eslintcache 55 | 56 | # Microbundle cache 57 | .rpt2_cache/ 58 | .rts2_cache_cjs/ 59 | .rts2_cache_es/ 60 | .rts2_cache_umd/ 61 | 62 | # Optional REPL history 63 | .node_repl_history 64 | 65 | # Output of 'npm pack' 66 | *.tgz 67 | 68 | # Yarn Integrity file 69 | .yarn-integrity 70 | 71 | # dotenv environment variables file 72 | .env 73 | .env.test 74 | 75 | # parcel-bundler cache (https://parceljs.org/) 76 | .cache 77 | 78 | # Next.js build output 79 | .next 80 | 81 | # Nuxt.js build / generate output 82 | .nuxt 83 | dist 84 | 85 | # Gatsby files 86 | .cache/ 87 | # Comment in the public line in if your project uses Gatsby and *not* Next.js 88 | # https://nextjs.org/blog/next-9-1#public-directory-support 89 | # public 90 | 91 | # vuepress build output 92 | .vuepress/dist 93 | 94 | # Serverless directories 95 | .serverless/ 96 | 97 | # FuseBox cache 98 | .fusebox/ 99 | 100 | # DynamoDB Local files 101 | .dynamodb/ 102 | 103 | # TernJS port file 104 | .tern-port 105 | -------------------------------------------------------------------------------- /src/discord/DiscordManager.js: -------------------------------------------------------------------------------- 1 | const { Client, Collection, GatewayIntentBits } = require("discord.js"); 2 | const CommandHandler = require("./CommandHandler"); 3 | const config = require("../../config.json"); 4 | const Logger = require("../Logger"); 5 | const path = require("node:path"); 6 | const fs = require("fs"); 7 | const delay = (ms) => new Promise((resolve) => setTimeout(resolve, ms)); 8 | const { kill } = require("node:process"); 9 | 10 | class DiscordManager { 11 | constructor(app) { 12 | this.app = app; 13 | 14 | this.commandHandler = new CommandHandler(this); 15 | } 16 | 17 | async connect() { 18 | try { 19 | global.client = new Client({ 20 | intents: [ 21 | GatewayIntentBits.Guilds, 22 | GatewayIntentBits.GuildMessages, 23 | GatewayIntentBits.MessageContent, 24 | ], 25 | }); 26 | const client = global.client; 27 | 28 | client.login(config.discord.token); 29 | 30 | client.on("ready", () => 31 | Logger.successfulMessage( 32 | "Client ready, logged in as " + client.user.tag 33 | ) 34 | ); 35 | 36 | client.commands = new Collection(); 37 | 38 | for (const file of fs.readdirSync(__dirname + "/commands").filter((file) => file.endsWith(".js"))) { 39 | const command = require(`./commands/${file}`); 40 | client.commands.set(command.name, command); 41 | } 42 | 43 | 44 | for (const file of fs.readdirSync(__dirname + "/events").filter((file) => file.endsWith(".js"))) { 45 | const filePath = path.join(__dirname + "/events", file); 46 | const event = require(filePath); 47 | event.once ? client.once(event.name, (...args) => event.execute(...args)) : client.on(event.name, (...args) => event.execute(...args)); 48 | } 49 | 50 | process.on("SIGINT", () => { 51 | Logger.logoutMessage( 52 | "Client successfuly logged out as " + client.user.tag 53 | ).then(() => { 54 | client.destroy(); 55 | kill(process.pid); 56 | }); 57 | }); 58 | } catch (error) { 59 | Logger.errorMessage(error); 60 | } 61 | } 62 | } 63 | 64 | module.exports = DiscordManager; 65 | --------------------------------------------------------------------------------