Eventos del Bot
🎯 Eventos del Bot
Documentación completa de todos los eventos de Discord que el bot maneja y procesa.
📋 Lista de Eventos
🚀 Eventos de Ciclo de Vida
ready
module.exports = { name: 'ready', once: true, async execute(client) { console.log(`✅ Bot conectado como ${client.user.tag}`);
// Registrar comandos slash await registerCommands(client);
// Inicializar sistemas await initializeSystems(client);
// Logs de inicio Logger.info('Bot iniciado correctamente', { guilds: client.guilds.cache.size, users: client.users.cache.size, commands: client.commands.size }); }};Funcionalidades:
- Registro de comandos slash globales
- Inicialización de base de datos
- Configuración de sistemas por defecto
- Logs de inicio y estadísticas
disconnect
module.exports = { name: 'disconnect', async execute(client) { Logger.warn('Bot desconectado de Discord');
// Backup de emergencia await BackupManager.createBackup();
// Limpiar recursos await cleanup(client); }};👥 Eventos de Servidor
guildCreate
module.exports = { name: 'guildCreate', async execute(guild) { Logger.info(`Agregado a nuevo servidor: ${guild.name} (${guild.id})`);
// Crear configuración por defecto await ConfigManager.getGuildConfig(guild.id);
// Mensaje de bienvenida al servidor const owner = await guild.fetchOwner(); const welcomeEmbed = createWelcomeEmbed(guild);
try { await owner.send({ embeds: [welcomeEmbed] }); } catch (error) { Logger.warn('No se pudo enviar mensaje de bienvenida al propietario'); }
// Estadísticas MetricsCollector.recordGuildJoin(guild); }};Funcionalidades:
- Configuración automática del servidor
- Mensaje de bienvenida al propietario
- Creación de base de datos para el servidor
- Registro de métricas
guildDelete
module.exports = { name: 'guildDelete', async execute(guild) { Logger.info(`Eliminado del servidor: ${guild.name} (${guild.id})`);
// Opcional: Limpiar datos del servidor // await ConfigManager.deleteGuildConfig(guild.id);
MetricsCollector.recordGuildLeave(guild); }};👤 Eventos de Miembros
guildMemberAdd
module.exports = { name: 'guildMemberAdd', async execute(member) { const guildId = member.guild.id; const config = await ConfigManager.getGuildConfig(guildId);
Logger.info(`Nuevo miembro: ${member.user.tag} en ${member.guild.name}`);
// Sistema de bienvenida if (config.welcome.enabled) { await WelcomeHandler.handleNewMember(member); }
// Roles automáticos if (config.autoRoles && config.autoRoles.length > 0) { await RoleManager.assignAutoRoles(member); }
// Logs de auditoría await AuditLogger.logMemberJoin(member);
MetricsCollector.recordMemberJoin(member.guild); }};Funcionalidades:
- Mensajes de bienvenida personalizados
- Asignación de roles automáticos
- Logs de auditoría
- Estadísticas de crecimiento
guildMemberRemove
module.exports = { name: 'guildMemberRemove', async execute(member) { Logger.info(`Miembro salió: ${member.user.tag} de ${member.guild.name}`);
// Mensajes de despedida (si están configurados) const config = await ConfigManager.getGuildConfig(member.guild.id); if (config.farewell && config.farewell.enabled) { await FarewellHandler.handleMemberLeave(member); }
// Limpiar tickets abiertos del usuario await TicketManager.closeUserTickets(member.user.id, member.guild.id);
// Logs de auditoría await AuditLogger.logMemberLeave(member);
MetricsCollector.recordMemberLeave(member.guild); }};💬 Eventos de Mensajes
messageCreate
module.exports = { name: 'messageCreate', async execute(message) { // Ignorar bots if (message.author.bot) return;
// Ignorar DMs if (!message.guild) return;
const guildId = message.guild.id; const userId = message.author.id;
// Sistema de niveles await LevelManager.addXP(userId, guildId, message);
// Auto-moderación const config = await ConfigManager.getGuildConfig(guildId); if (config.moderation.autoMod) { await AutoMod.checkMessage(message); }
// Comandos de texto (legacy - si están habilitados) if (config.textCommands) { await TextCommandHandler.handle(message); }
MetricsCollector.recordMessage(message.guild); }};Funcionalidades:
- Sistema de XP y niveles
- Auto-moderación de contenido
- Procesamiento de comandos de texto
- Métricas de actividad
messageDelete
module.exports = { name: 'messageDelete', async execute(message) { // Ignorar mensajes parciales o de bots if (message.partial || message.author?.bot) return;
// Log de mensaje eliminado await AuditLogger.logMessageDelete(message);
// Verificar si era un panel de roles await RoleManager.checkDeletedPanel(message); }};🎛️ Eventos de Interacciones
interactionCreate
module.exports = { name: 'interactionCreate', async execute(interaction) { const guildId = interaction.guild?.id;
// Rate limiting if (RateLimiter.isLimited(`${interaction.user.id}:${interaction.commandName}`)) { return await interaction.reply({ content: 'Estás usando comandos muy rápido. Espera un momento.', ephemeral: true }); }
try { if (interaction.isChatInputCommand()) { await handleSlashCommand(interaction); } else if (interaction.isButton()) { await handleButtonInteraction(interaction); } else if (interaction.isStringSelectMenu()) { await handleSelectMenuInteraction(interaction); } else if (interaction.isModalSubmit()) { await handleModalSubmit(interaction); } } catch (error) { Logger.error('Error en interacción', { error: error.message, user: interaction.user.tag, command: interaction.commandName || 'unknown' });
await handleInteractionError(interaction, error); } }};🔘 Eventos de Reacciones
messageReactionAdd
module.exports = { name: 'messageReactionAdd', async execute(reaction, user) { // Ignorar reacciones de bots if (user.bot) return;
// Manejar reacciones parciales if (reaction.partial) { try { await reaction.fetch(); } catch (error) { Logger.error('Error al obtener reacción', error); return; } }
const message = reaction.message; if (!message.guild) return;
// Sistema de roles por reacción await RoleManager.handleReactionRoleAdd(reaction, user);
// Otros sistemas que usen reacciones await ReactionHandler.processReaction(reaction, user, 'add'); }};messageReactionRemove
module.exports = { name: 'messageReactionRemove', async execute(reaction, user) { if (user.bot) return;
if (reaction.partial) { try { await reaction.fetch(); } catch (error) { return; } }
// Quitar roles por reacción await RoleManager.handleReactionRoleRemove(reaction, user);
await ReactionHandler.processReaction(reaction, user, 'remove'); }};🎭 Eventos de Roles
guildMemberUpdate
module.exports = { name: 'guildMemberUpdate', async execute(oldMember, newMember) { // Detectar cambios de roles const addedRoles = newMember.roles.cache.filter(role => !oldMember.roles.cache.has(role.id) );
const removedRoles = oldMember.roles.cache.filter(role => !newMember.roles.cache.has(role.id) );
// Log cambios de roles if (addedRoles.size > 0 || removedRoles.size > 0) { await AuditLogger.logRoleChanges(oldMember, newMember, addedRoles, removedRoles); }
// Detectar cambios de nickname if (oldMember.nickname !== newMember.nickname) { await AuditLogger.logNicknameChange(oldMember, newMember); }
// Verificar actualizaciones de permisos await PermissionManager.checkMemberPermissions(newMember); }};🔄 Manejo de Errores
Error Handler Global
module.exports = { name: 'error', async execute(error) { Logger.error('Error del cliente Discord', { message: error.message, stack: error.stack, timestamp: new Date().toISOString() });
// Notificar al owner en errores críticos if (error.code === 'CRITICAL') { await notifyOwner(error); }
MetricsCollector.recordError(error); }};Warning Handler
module.exports = { name: 'warn', async execute(warning) { Logger.warn('Advertencia del cliente Discord', { message: warning, timestamp: new Date().toISOString() }); }};📊 Eventos de Monitoreo
Rate Limit Handler
module.exports = { name: 'rateLimit', async execute(rateLimitData) { Logger.warn('Rate limit alcanzado', { timeout: rateLimitData.timeout, limit: rateLimitData.limit, method: rateLimitData.method, path: rateLimitData.path });
MetricsCollector.recordRateLimit(rateLimitData); }};Debug Events
module.exports = { name: 'debug', async execute(info) { if (process.env.NODE_ENV === 'development') { Logger.debug('Discord.js debug', { info }); } }};🎯 Eventos Personalizados
Custom Event Emitter
const EventEmitter = require('events');
class BotEventEmitter extends EventEmitter { // Eventos personalizados del bot emitLevelUp(userId, guildId, level) { this.emit('levelUp', { userId, guildId, level }); }
emitTicketCreated(ticketData) { this.emit('ticketCreated', ticketData); }
emitConfigChanged(guildId, changes) { this.emit('configChanged', { guildId, changes }); }}
module.exports = new BotEventEmitter();Event Listeners
const botEvents = require('../../utils/eventEmitter');
botEvents.on('levelUp', async ({ userId, guildId, level }) => { Logger.info(`Level up: User ${userId} reached level ${level} in guild ${guildId}`);
// Verificar roles automáticos por nivel await RoleManager.checkLevelRoles(userId, guildId, level);
// Estadísticas MetricsCollector.recordLevelUp(guildId, level);});🔧 Configuración de Eventos
Event Handler
const fs = require('fs');const path = require('path');
function loadEvents(client) { const eventsPath = path.join(__dirname, '..', 'events');
function loadEventFiles(dir) { const files = fs.readdirSync(dir);
for (const file of files) { const filePath = path.join(dir, file); const stat = fs.statSync(filePath);
if (stat.isDirectory()) { loadEventFiles(filePath); } else if (file.endsWith('.js')) { const event = require(filePath);
if (event.once) { client.once(event.name, (...args) => event.execute(...args)); } else { client.on(event.name, (...args) => event.execute(...args)); }
Logger.debug(`Evento cargado: ${event.name}`); } } }
loadEventFiles(eventsPath);}
module.exports = { loadEvents };📈 Métricas de Eventos
Event Statistics
class EventMetrics { static stats = { messageCreate: 0, interactionCreate: 0, guildMemberAdd: 0, guildMemberRemove: 0, ready: 0, errors: 0 };
static record(eventName) { if (this.stats.hasOwnProperty(eventName)) { this.stats[eventName]++; } }
static getStats() { return { ...this.stats }; }
static reset() { Object.keys(this.stats).forEach(key => { this.stats[key] = 0; }); }}Todos los eventos están optimizados para máximo rendimiento y incluyen manejo de errores robusto. Los logs detallados permiten debugging efectivo y monitoreo del comportamiento del bot.