UNPKG

djshandler-core

Version:

Core command handler framework for Discord.js bots

355 lines (351 loc) 10.8 kB
"use strict"; var __create = Object.create; var __defProp = Object.defineProperty; var __getOwnPropDesc = Object.getOwnPropertyDescriptor; var __getOwnPropNames = Object.getOwnPropertyNames; var __getProtoOf = Object.getPrototypeOf; var __hasOwnProp = Object.prototype.hasOwnProperty; var __export = (target, all) => { for (var name in all) __defProp(target, name, { get: all[name], enumerable: true }); }; var __copyProps = (to, from, except, desc) => { if (from && typeof from === "object" || typeof from === "function") { for (let key of __getOwnPropNames(from)) if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); } return to; }; var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps( // If the importer is in node compatibility mode or this is not an ESM // file that has been converted to a CommonJS file using a Babel- // compatible transform (i.e. "__esModule" has not been set), then set // "default" to the CommonJS "module.exports" for node compatibility. isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target, mod )); var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); // src/index.ts var index_exports = {}; __export(index_exports, { CommandClass: () => CommandClass, CommandHandler: () => DJSHandler, DJSHandler: () => DJSHandler, EventClass: () => EventClass, Execute: () => Execute, Logger: () => Logger, On: () => On, Once: () => Once, ensureDir: () => ensureDir, extractCommand: () => extractCommand, extractEvent: () => extractEvent, fileExists: () => fileExists, formatCommandName: () => formatCommandName, importModule: () => importModule, isValidCommandName: () => isValidCommandName, loadFiles: () => loadFiles, logger: () => logger }); module.exports = __toCommonJS(index_exports); // src/handler.ts var import_discord = require("discord.js"); var DJSHandler = class { constructor(options) { this.options = options; this.commands = new import_discord.Collection(); this.events = new import_discord.Collection(); this.client = new import_discord.Client({ intents: this.options.intents || [ import_discord.GatewayIntentBits.Guilds, import_discord.GatewayIntentBits.GuildMessages, import_discord.GatewayIntentBits.MessageContent ] }); if (this.options.token) { this.rest = new import_discord.REST().setToken(this.options.token); } this.setupDefaultEvents(); } /** * Register a command with the handler */ registerCommand(command) { this.commands.set(command.data.name, command); return this; } /** * Register an event with the handler */ registerEvent(event) { this.events.set(event.name, event); if (event.once) { this.client.once(event.name, (...args) => event.execute(...args)); } else { this.client.on(event.name, (...args) => event.execute(...args)); } return this; } /** * Load all commands from a directory */ async loadCommands(commandsPath) { return this; } /** * Load all events from a directory */ async loadEvents(eventsPath) { return this; } /** * Deploy slash commands to Discord */ async deployCommands(guildId) { if (!this.rest || !this.options.clientId) { throw new Error("REST client not initialized or clientId not provided"); } const commandsData = Array.from(this.commands.values()).map( (command) => command.data.toJSON() ); try { console.log(`Started refreshing ${commandsData.length} application (/) commands.`); const route = guildId ? import_discord.Routes.applicationGuildCommands(this.options.clientId, guildId) : import_discord.Routes.applicationCommands(this.options.clientId); await this.rest.put(route, { body: commandsData }); console.log(`Successfully reloaded ${commandsData.length} application (/) commands.`); } catch (error) { console.error("Error deploying commands:", error); throw error; } } /** * Start the bot */ async start() { if (!this.options.token) { throw new Error("Bot token is required to start the client"); } try { await this.client.login(this.options.token); console.log("Bot started successfully!"); } catch (error) { console.error("Error starting bot:", error); throw error; } } /** * Get the Discord.js client instance */ getClient() { return this.client; } /** * Get registered commands */ getCommands() { return this.commands; } /** * Get registered events */ getEvents() { return this.events; } /** * Setup default event handlers */ setupDefaultEvents() { this.client.on(import_discord.Events.InteractionCreate, async (interaction) => { if (!interaction.isChatInputCommand()) return; const command = this.commands.get(interaction.commandName); if (!command) return; try { await command.execute(interaction); } catch (error) { console.error(`Error executing command ${interaction.commandName}:`, error); const reply = { content: "There was an error while executing this command!", ephemeral: true }; if (interaction.replied || interaction.deferred) { await interaction.followUp(reply); } else { await interaction.reply(reply); } } }); this.client.on(import_discord.Events.ClientReady, () => { console.log(`Ready! Logged in as ${this.client.user?.tag}`); }); } }; // src/decorators.ts var import_reflect_metadata = require("reflect-metadata"); var import_discord2 = require("discord.js"); var COMMAND_METADATA_KEY = Symbol("command"); var EVENT_METADATA_KEY = Symbol("event"); function CommandClass(metadata) { return function(constructor) { Reflect.defineMetadata(COMMAND_METADATA_KEY, metadata, constructor); return constructor; }; } function Execute() { return function(target, propertyKey, descriptor) { Reflect.defineMetadata("execute", true, target, propertyKey); }; } function EventClass(metadata) { return function(constructor) { Reflect.defineMetadata(EVENT_METADATA_KEY, metadata, constructor); return constructor; }; } function On(eventName) { return function(target, propertyKey, descriptor) { Reflect.defineMetadata("eventName", eventName, target, propertyKey); Reflect.defineMetadata("once", false, target, propertyKey); }; } function Once(eventName) { return function(target, propertyKey, descriptor) { Reflect.defineMetadata("eventName", eventName, target, propertyKey); Reflect.defineMetadata("once", true, target, propertyKey); }; } function extractCommand(CommandClass2) { const metadata = Reflect.getMetadata(COMMAND_METADATA_KEY, CommandClass2); if (!metadata) return null; const instance = new CommandClass2(); const prototype = Object.getPrototypeOf(instance); const methods = Object.getOwnPropertyNames(prototype); let executeMethod = null; for (const method of methods) { if (Reflect.getMetadata("execute", prototype, method)) { executeMethod = instance[method].bind(instance); break; } } if (!executeMethod) return null; const commandBuilder = new import_discord2.SlashCommandBuilder().setName(metadata.name).setDescription(metadata.description); return { data: commandBuilder, execute: executeMethod, category: metadata.category, disabled: metadata.disabled, cooldown: metadata.cooldown }; } function extractEvent(EventClass2) { const metadata = Reflect.getMetadata(EVENT_METADATA_KEY, EventClass2); if (!metadata) return null; const instance = new EventClass2(); const prototype = Object.getPrototypeOf(instance); const methods = Object.getOwnPropertyNames(prototype); let executeMethod = null; for (const method of methods) { const eventName = Reflect.getMetadata("eventName", prototype, method); if (eventName) { executeMethod = instance[method].bind(instance); break; } } if (!executeMethod) return null; return { name: metadata.name, once: metadata.once, execute: executeMethod }; } // src/utils.ts var fs = __toESM(require("fs/promises")); var path = __toESM(require("path")); async function loadFiles(dirPath, extension = ".js") { const files = []; try { const items = await fs.readdir(dirPath, { withFileTypes: true }); for (const item of items) { const fullPath = path.join(dirPath, item.name); if (item.isDirectory()) { const subFiles = await loadFiles(fullPath, extension); files.push(...subFiles); } else if (item.isFile() && item.name.endsWith(extension)) { files.push(fullPath); } } } catch (error) { console.warn(`Could not read directory ${dirPath}:`, error); } return files; } async function importModule(filePath) { try { const module2 = await import(filePath); return module2.default || module2; } catch (error) { console.warn(`Could not import module from ${filePath}:`, error); return null; } } async function fileExists(filePath) { try { await fs.access(filePath); return true; } catch { return false; } } async function ensureDir(dirPath) { try { await fs.mkdir(dirPath, { recursive: true }); } catch (error) { console.warn(`Could not create directory ${dirPath}:`, error); } } function formatCommandName(name) { return name.toLowerCase().replace(/[^a-z0-9-_]/g, "-").replace(/-+/g, "-").replace(/^-|-$/g, ""); } function isValidCommandName(name) { return /^[a-z0-9-_]{1,32}$/.test(name); } var Logger = class { constructor(prefix = "DJSHandler") { this.prefix = prefix; } info(message, ...args) { console.log(`[${this.prefix}] ${message}`, ...args); } warn(message, ...args) { console.warn(`[${this.prefix}] ${message}`, ...args); } error(message, ...args) { console.error(`[${this.prefix}] ${message}`, ...args); } debug(message, ...args) { if (process.env.NODE_ENV === "development") { console.debug(`[${this.prefix}] ${message}`, ...args); } } }; var logger = new Logger(); // Annotate the CommonJS export names for ESM import in node: 0 && (module.exports = { CommandClass, CommandHandler, DJSHandler, EventClass, Execute, Logger, On, Once, ensureDir, extractCommand, extractEvent, fileExists, formatCommandName, importModule, isValidCommandName, loadFiles, logger }); //# sourceMappingURL=index.js.map