UNPKG

commandbot

Version:

A framework that helps you create your own Discord bot easier.

221 lines (220 loc) 8.59 kB
import { Client, Intents } from "discord.js"; import { EventEmitter } from "events"; import * as http from "http"; import { CommandManager } from "./CommandManager.js"; import { CommandNotFound, OperationSuccess, PermissionsError } from "../errors.js"; import { SystemMessageManager } from "./SystemMessage.js"; import { applicationState } from "../state.js"; /** * Application instance * @class * @extends {EventEmitter} */ export class Bot extends EventEmitter { /** * Bot name * @type {string} * @public * @readonly */ name; /** * Discord.js {@link Client} instance * @type {Client} * @public * @readonly */ client; /** * Instance command manager * @type {CommandManager} * @public * @readonly */ commands; /** * Discord Bot token * @type {string} * @public * @readonly */ token; /** * Discord API application ID * @type {string} * @public * @readonly */ applicationId; /** * {@link SystemMessageManager} storing messages' configuration * @type {SystemMessageManager} * @public * @readonly */ messages; /** * Main bot constructor * @constructor * @param {InitOptions} options - instance properties ({@link InitOptions}) */ constructor({ name, token, applicationId, globalPrefix, argumentSeparator, commandSeparator, clientOptions, help }) { super(); this.name = name; this.client = new Client(clientOptions ?? { intents: [ Intents.FLAGS.GUILDS, Intents.FLAGS.GUILD_BANS, Intents.FLAGS.GUILD_EMOJIS_AND_STICKERS, Intents.FLAGS.GUILD_INTEGRATIONS, Intents.FLAGS.GUILD_INVITES, Intents.FLAGS.GUILD_MEMBERS, Intents.FLAGS.GUILD_MESSAGES, Intents.FLAGS.GUILD_MESSAGE_REACTIONS, Intents.FLAGS.GUILD_MESSAGE_TYPING, Intents.FLAGS.GUILD_PRESENCES, Intents.FLAGS.GUILD_VOICE_STATES, Intents.FLAGS.GUILD_WEBHOOKS, Intents.FLAGS.DIRECT_MESSAGES, Intents.FLAGS.DIRECT_MESSAGE_REACTIONS, Intents.FLAGS.DIRECT_MESSAGE_TYPING, ], }); this.messages = new SystemMessageManager(this); this.commands = new CommandManager(this, help ?? { enabled: true, title: "Help", description: "List of all available commands", bottomText: "List of all available commands", ephemeral: "INTERACTIONS", }, globalPrefix, argumentSeparator, commandSeparator); this.token = token; this.applicationId = applicationId; } /** * Starts your Discord bot * @param {?number} [port] - if specified, the app will create a http server that will be listening on the specified port (useful when hosting your bot on platforms like Heroku) * @param {?boolean} [register=true] - if *true* or *undefined*, the bot will register all interactions in the Discord API * @returns {Promise<boolean>} whether this operation has been completed successfully * @public * @async */ async start(port, register) { try { if (applicationState.running) { throw new Error("This bot is already running"); } if (applicationState.dev) { console.warn(`[⚠️ WARNING] You are using an unstable version of the CommandBot package. It is not recommended to use this version in production.`); } console.log(`\nBot name: ${this.name}`); console.log(`Global prefix: ${this.commands.prefix.globalPrefix || "/ (only slash commands)"} \n`); if (this.token === "") { throw new ReferenceError('No token specified. Please pass your Discord application token as an argument to the "start" method or in the constructor'); } if (port) { process.stdout.write(`Creating http server on port ${port}... `); http.createServer().listen(port); console.log("✔"); } applicationState.running = true; process.stdout.write("Connecting to Discord... "); this.client.login(this.token); this.client.on("ready", async () => { if (register === undefined || register === true) { console.log("✔"); process.stdout.write(`Registering commands... `); await this.commands.register(); console.log("✔"); } else { console.log("✔\n"); } this.emit("READY"); }); this.client.on("messageCreate", async (m) => { if (m.author.bot) return; let inputData = null; try { inputData = this.commands.fetch(m); if (inputData) { this.emit("COMMAND", m, inputData); await inputData.command.start(inputData); } else { this.emit("MESSAGE", m); } } catch (e) { if (e instanceof PermissionsError) { this.emit("ERROR", e); await this.messages.send("PERMISSION", { user: m.member ?? undefined, command: inputData?.command, }, m); } else if (e instanceof OperationSuccess) { await this.messages.send("SUCCESS", { command: e.command }, m); } else if (e instanceof CommandNotFound) { await this.messages.send("NOT_FOUND", { phrase: e.query, user: m.member ?? undefined }, m); } else { this.emit("ERROR", e); await this.messages.send("ERROR", { command: inputData?.command, user: m.member ?? undefined, error: e, }, m); } return; } }); this.client.on("interactionCreate", async (i) => { let inputData = null; try { inputData = this.commands.fetch(i); if (inputData) { this.emit("COMMAND", i, inputData); await inputData.command.start(inputData); } } catch (e) { if (e instanceof PermissionsError) { await this.messages.send("PERMISSION", { user: i.member ?? undefined, command: inputData?.command, }, i); this.emit("ERROR", e); } else if (e instanceof OperationSuccess) { await this.messages.send("SUCCESS", { command: e.command }, i); } else if (e instanceof CommandNotFound) { await this.messages.send("NOT_FOUND", { user: i.user, phrase: e.query }, i); } else { await this.messages.send("ERROR", { command: inputData?.command, user: i.member ?? undefined, error: e, }, i); this.emit("ERROR", e); } return; } }); this.client.on("error", (e) => { this.emit("ERROR", e); }); return true; } catch (e) { console.log("❌"); console.error(`[❌ ERROR] ${e}`); return false; } } } export default Bot;