simplify-cord
Version:
SimplifyCord is an unofficial extension of the 'discord.js' library. Our extension aims to simplify the development of Discord bots, promoting cleaner code and easier maintenance.
317 lines (316 loc) • 14.7 kB
JavaScript
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.bootstrapApp = void 0;
const discord_js_1 = require("discord.js");
const index_1 = __importStar(require("../handlers/commands/index"));
const index_2 = require("../handlers/interactions/index");
const Event_1 = require("./Event");
const url_1 = require("url");
const index_3 = require("../functions/index");
const zod_1 = require("zod");
const path = __importStar(require("path"));
const logger_1 = require("../functions/logger");
const discord_js_2 = require("discord.js");
const chalk_1 = __importDefault(require("chalk"));
const intents_1 = require("../lib/constants/intents");
class bootstrapApp extends discord_js_1.Client {
customOptions;
slashCommands = new discord_js_1.Collection();
slashArray = [];
commands;
constructor(options) {
const intentsValidation = zod_1.z.array(zod_1.z.nativeEnum(discord_js_1.GatewayIntentBits), { invalid_type_error: "Intents list must be a GatewayIntentBits object from discord" });
intentsValidation.parse(options.intents || intents_1.DEFAULT_INTENTS);
const tokenValidation = zod_1.z.string({ required_error: "Token is required", invalid_type_error: "Token must be a string" });
tokenValidation.parse(options.token);
const clientOptions = {
intents: options.intents || intents_1.DEFAULT_INTENTS
};
super(clientOptions);
this.customOptions = options;
this.commands = options.commands;
this.slashCommands = new discord_js_1.Collection();
this.slashArray = [];
this.startListening();
this.loadAutoImportPaths().then(() => {
Event_1.Event.register(this);
this.login(options.token);
});
}
async invokeInteraction(interactionName, interaction, params = {}) {
try {
const handler = index_2.interactionHandlers.get(interactionName);
if (!handler) {
logger_1.Logger.error(`No handler found for interaction: ${interactionName}`);
if (!interaction.replied && !interaction.deferred) {
await interaction.reply({ content: 'Interaction handler not found.', ephemeral: true });
}
return;
}
return await handler.run(this, interaction, params);
}
catch (error) {
logger_1.Logger.error(`Error invoking interaction "${interactionName}"`, error);
if (!interaction.replied && !interaction.deferred) {
await interaction.reply({ content: 'An error occurred while processing this interaction.', ephemeral: true });
}
}
}
async invokeCommand(commandName, interaction) {
const command = this.slashCommands.get(commandName);
if (!command) {
logger_1.Logger.error(`Command "${commandName}" not found!`);
return;
}
try {
await command.run(this, interaction);
}
catch (error) {
logger_1.Logger.error(`Error in command "${commandName}"`, error);
}
}
async reloadCommands() {
try {
this.slashCommands = new discord_js_1.Collection();
this.slashArray = [];
for (const [name, command] of index_1.slashCommandHandlers) {
if (this.slashCommands.has(name)) {
continue;
}
this.slashCommands.set(name, command);
const commandData = {
name: command.name,
description: command.description,
type: command.type,
options: (command.options || []).map(option => ({
...option,
autocomplete: option.autocomplete ?? false
}))
};
this.slashArray.push(commandData);
}
if (this.slashArray.length === 0) {
logger_1.Logger.warn("Warning: No commands to register.");
return;
}
if (this.guilds.cache.size === 0) {
logger_1.Logger.warn("Warning: No guilds found. Commands will be registered when joining a guild.");
return;
}
if (this.commands?.guilds && this.commands.guilds.length > 0) {
for (const guildId of this.commands.guilds) {
const guild = this.guilds.cache.get(guildId);
if (!guild) {
logger_1.Logger.warn(`Guild with ID ${guildId} not found. Make sure the bot is in the guild.`);
continue;
}
try {
await guild.commands.set(this.slashArray);
logger_1.Logger.success(`Commands registered in guild: ${guild.name} (${this.slashArray.length} commands)`);
}
catch (error) {
logger_1.Logger.error(`Failed to register commands in guild ${guild.name}`, error);
}
}
}
else {
try {
await this.application?.commands.set(this.slashArray);
logger_1.Logger.success(`Commands registered globally (${this.slashArray.length} commands)`);
}
catch (error) {
logger_1.Logger.error("Failed to register commands globally", error);
}
}
}
catch (error) {
logger_1.Logger.error("Error reloading commands", error);
}
}
async loadAutoImportPaths() {
const root_path = path.resolve();
const autoImportPath = this.customOptions?.autoImport;
if (autoImportPath) {
for (const importPath of autoImportPath) {
const files = index_3.utils.getRecursiveFiles(`${root_path}/${importPath}`);
if (!files) {
logger_1.Logger.warn(`Auto Import path not found: '${importPath}'`);
logger_1.Logger.info("Make sure to provide a valid path to the components folder");
continue;
}
for (const file of files) {
const isValidFile = file.endsWith('.mjs') || file.endsWith('.js') || file.endsWith(".ts");
if (!isValidFile)
continue;
try {
const componentPath = (0, url_1.pathToFileURL)(file).href;
await import(componentPath);
}
catch (error) {
logger_1.Logger.error(`Failed to import component: ${file}`, error);
}
}
}
}
this.slashCommands = new discord_js_1.Collection();
this.slashArray = [];
for (const [name, command] of index_1.slashCommandHandlers) {
this.slashCommands.set(name, command);
const commandData = {
name: command.name,
description: command.description,
type: command.type,
options: (command.options || []).map(option => ({
...option,
autocomplete: option.autocomplete ?? false
}))
};
this.slashArray.push(commandData);
}
}
startListening() {
this.once(discord_js_1.Events.ClientReady, async (client) => {
console.log();
await this.loadAutoImportPaths();
if (this.customOptions?.loadLogs !== false) {
index_1.default.loadLogs();
Event_1.Event.loadLogs();
logger_1.Logger.separator();
}
logger_1.Logger.info(`${chalk_1.default.green.bold(`discord.js`)} @${chalk_1.default.white.bold(discord_js_2.version)} / ${chalk_1.default.green.bold(`NodeJs`)} @${chalk_1.default.white.bold(process.versions.node)}`);
logger_1.Logger.separator();
logger_1.Logger.ready(`Online as ${logger_1.Logger.highlight(client.user.username)}`);
await this.reloadCommands();
});
this.on(discord_js_1.Events.InteractionCreate, async (interaction) => {
if (interaction.isCommand()) {
const command = this.slashCommands.get(interaction.commandName);
if (!command) {
logger_1.Logger.error(`Command "${interaction.commandName}" not found!`);
logger_1.Logger.info(`Available commands: ${Array.from(this.slashCommands.keys()).join(", ")}`);
if (!interaction.replied && !interaction.deferred) {
await interaction.reply({ content: 'Command not found. Please try again later.', ephemeral: true });
}
return;
}
try {
await command.run(this, interaction);
}
catch (error) {
logger_1.Logger.error(`Error in command "${interaction.commandName}"`, error);
if (!interaction.replied && !interaction.deferred) {
await interaction.reply({ content: 'An error occurred while executing this command.', ephemeral: true });
}
}
}
if (interaction.isButton() || interaction.isAnySelectMenu() || interaction.isModalSubmit()) {
try {
const runInteractionHandler = this.getInteractionCallback(interaction.customId, interaction);
if (!runInteractionHandler) {
logger_1.Logger.error(`No handler found for interaction: ${interaction.customId}`);
if (!interaction.replied && !interaction.deferred) {
await interaction.reply({ content: 'Interaction handler not found.', ephemeral: true });
}
return;
}
await runInteractionHandler();
}
catch (error) {
logger_1.Logger.error(`Error in interaction "${interaction.customId}"`, error);
if (!interaction.replied && !interaction.deferred) {
await interaction.reply({ content: 'An error occurred while processing this interaction.', ephemeral: true });
}
}
}
if (interaction.isAutocomplete()) {
const command = this.slashCommands.get(interaction.commandName);
if (!command) {
return logger_1.Logger.error('Error on interaction autocomplete! Command not found.');
}
if (command.autocomplete) {
try {
await command.autocomplete(interaction);
}
catch (error) {
logger_1.Logger.error('Error in autocomplete interaction', error);
}
}
}
});
this.on(discord_js_1.Events.GuildCreate, async () => {
await this.reloadCommands();
});
}
parsePattern(pattern, customId) {
const patternParts = pattern.split('/');
const customIdParts = customId.split('/');
if (patternParts.length !== customIdParts.length) {
return null;
}
const params = {};
for (let i = 0; i < patternParts.length; i++) {
if (patternParts[i].startsWith(':')) {
const paramName = patternParts[i].slice(1);
params[paramName] = customIdParts[i];
}
else if (patternParts[i] !== customIdParts[i]) {
return null;
}
}
return params;
}
getInteractionCallback(customId, interaction) {
if (interaction.isButton() || interaction.isAnySelectMenu() || interaction.isCommand() || interaction.isModalSubmit()) {
try {
const useOptionInLastParam = customId.includes("(OILP)");
const cleanCustomId = customId.replace("(OILP)", "");
for (const [pattern, handler] of index_2.interactionHandlers.entries()) {
const params = this.parsePattern(pattern, cleanCustomId);
if (params) {
if (interaction.isAnySelectMenu() && useOptionInLastParam && interaction.values.length > 0) {
params.value = interaction.values[0];
}
const callback = handler.run;
if (!callback) {
logger_1.Logger.error(`Callback not found for pattern: ${pattern}`);
return;
}
return callback.bind(null, this, interaction, params);
}
}
logger_1.Logger.warn(`No matching handler found for customId: ${customId}`);
}
catch (error) {
logger_1.Logger.error(`Error processing interaction for customId ${customId}`, error);
}
}
}
}
exports.default = bootstrapApp;
exports.bootstrapApp = bootstrapApp;