Yato uses Discord.js events for bot lifecycle and gcommands events for command-related functionality. This guide shows you how to add custom event handlers.
Discord.js events
The Discord.js client emits events for various Discord activities. These are handled directly on the client instance.
Available in Yato
Currently, Yato implements the ready event in src/index.js:9:
const Discord = require ( 'discord.js' );
const client = new Discord . Client ({
allowedMentions: { parse: [ 'users' , 'roles' ] }
});
client . on ( 'ready' , async () => {
console . log ( `➤ Logged in as ${ client . user . tag } ( ${ client . user . id } )` );
// MongoDB connection
await mongoose . connect ( process . env . MONGO_URI , {
useNewUrlParser: true ,
useUnifiedTopology: true
});
// Initialize gcommands
const GCommandsClient = new GCommands ( client , { /* ... */ });
// Set status rotation
setInterval (() => {
const status = statuses [ Math . floor ( Math . random () * statuses . length )];
client . user . setPresence ({
activity: { name: status , type: 'LISTENING' },
status: 'idle'
});
}, 15000 );
});
Adding new Discord events
You can add event handlers directly in src/index.js or create separate event files.
In index.js
Separate files
Add event handlers directly after the client creation: const client = new Discord . Client ({
allowedMentions: { parse: [ 'users' , 'roles' ] }
});
// Add new event handler
client . on ( 'guildMemberAdd' , ( member ) => {
console . log ( ` ${ member . user . tag } joined ${ member . guild . name } ` );
// Send welcome message
const welcomeChannel = member . guild . channels . cache
. find ( ch => ch . name === 'welcome' );
if ( welcomeChannel ) {
welcomeChannel . send ( `Welcome ${ member } !` );
}
});
client . on ( 'ready' , async () => {
// Existing ready logic...
});
Create an events directory structure: mkdir src/events
touch src/events/guildMemberAdd.js
touch src/events/messageDelete.js
Define event handlers in separate files: src/events/guildMemberAdd.js
const { MessageEmbed } = require ( 'discord.js' );
const colors = require ( '../config/colors.json' );
module . exports = {
name: 'guildMemberAdd' ,
once: false ,
execute ( member ) {
const welcomeChannel = member . guild . channels . cache
. find ( ch => ch . name === 'welcome' );
if ( ! welcomeChannel ) return ;
const embed = new MessageEmbed ()
. setColor ( colors . default )
. setTitle ( 'Welcome!' )
. setDescription ( `Welcome to ${ member . guild . name } , ${ member } !` )
. setThumbnail ( member . user . displayAvatarURL ({ dynamic: true }))
. setTimestamp ();
welcomeChannel . send ( embed );
}
};
Load event files in src/index.js: const fs = require ( 'fs' );
const path = require ( 'path' );
// Load event files
const eventFiles = fs . readdirSync ( './src/events' )
. filter ( file => file . endsWith ( '.js' ));
for ( const file of eventFiles ) {
const event = require ( `./events/ ${ file } ` );
if ( event . once ) {
client . once ( event . name , ( ... args ) => event . execute ( ... args ));
} else {
client . on ( event . name , ( ... args ) => event . execute ( ... args ));
}
}
Common Discord events
Here are commonly used Discord.js events you can implement:
Fired when a user joins a server. client . on ( 'guildMemberAdd' , ( member ) => {
// member is a GuildMember object
console . log ( ` ${ member . user . tag } joined` );
});
Fired when a user leaves or is kicked/banned. client . on ( 'guildMemberRemove' , ( member ) => {
console . log ( ` ${ member . user . tag } left` );
});
Fired when a message is deleted. client . on ( 'messageDelete' , ( message ) => {
if ( message . partial ) return ; // Ignore cached messages
console . log ( `Message deleted: ${ message . content } ` );
});
Fired when a message is edited. client . on ( 'messageUpdate' , ( oldMessage , newMessage ) => {
if ( oldMessage . content === newMessage . content ) return ;
console . log ( `Message edited from " ${ oldMessage . content } " to " ${ newMessage . content } "` );
});
Fired when the bot joins a new server. client . on ( 'guildCreate' , ( guild ) => {
console . log ( `Joined new guild: ${ guild . name } ` );
});
Fired when the client encounters an error. client . on ( 'error' , ( error ) => {
console . error ( 'Client error:' , error );
});
gcommands events
The gcommands framework provides its own events for command handling. These are implemented in src/index.js:27:
const GCommandsClient = new GCommands ( client , { /* config */ });
GCommandsClient . on ( 'log' , ( log ) => {
console . log ( log );
});
GCommandsClient . on ( 'debug' , ( debug ) => {
console . log ( debug );
});
Available gcommands events
log General logging information from the framework.
debug Debug information for troubleshooting.
commandError Fired when a command throws an error.
cooldown Fired when a user is on cooldown.
Error handling
Add custom error handling for commands:
const { MessageEmbed } = require ( 'discord.js' );
const colors = require ( './config/colors.json' );
GCommandsClient . on ( 'commandError' , ( ctx , error ) => {
console . error ( `Command error in ${ ctx . command . name } :` , error );
const embed = new MessageEmbed ()
. setColor ( colors . red )
. setTitle ( 'Command Error' )
. setDescription ( 'An error occurred while executing this command.' )
. addField ( 'Error' , error . message )
. setTimestamp ();
ctx . respond ({ content: embed , ephemeral: true });
});
Cooldown messages
Customize cooldown responses:
GCommandsClient . on ( 'cooldown' , ( ctx , timeLeft ) => {
const embed = new MessageEmbed ()
. setColor ( colors . red )
. setDescription ( `Please wait ${ Math . ceil ( timeLeft / 1000 ) } seconds before using this command again.` );
ctx . respond ({ content: embed , ephemeral: true });
});
Example: Logging system
Here’s a complete logging system implementation:
Create the log channel finder
module . exports = {
// ... existing utilities
getLogChannel ( guild ) {
return guild . channels . cache . find ( ch =>
ch . name === 'yato-logs' || ch . name === 'logs'
);
}
};
Create event handlers
src/events/messageDelete.js
const { MessageEmbed } = require ( 'discord.js' );
const colors = require ( '../config/colors.json' );
const utils = require ( '../structures/utils' );
module . exports = {
name: 'messageDelete' ,
execute ( message ) {
if ( message . author . bot ) return ;
if ( message . partial ) return ;
const logChannel = utils . getLogChannel ( message . guild );
if ( ! logChannel ) return ;
const embed = new MessageEmbed ()
. setColor ( colors . red )
. setAuthor ( message . author . tag , message . author . displayAvatarURL ())
. setDescription ( `Message deleted in ${ message . channel } ` )
. addField ( 'Content' , message . content || 'No content' )
. setTimestamp ();
logChannel . send ( embed );
}
};
Load events in index.js
const fs = require ( 'fs' );
// After client creation
const eventFiles = fs . readdirSync ( './src/events' )
. filter ( file => file . endsWith ( '.js' ));
for ( const file of eventFiles ) {
const event = require ( `./events/ ${ file } ` );
client . on ( event . name , ( ... args ) => event . execute ( ... args , client ));
}
Best practices
Check for bots : Many events should ignore bot users to prevent loops
Handle partials : Check for partial data in events like messageDelete
Error handling : Wrap event handlers in try-catch blocks
Rate limits : Be careful with events that fire frequently (like messageCreate)
Permissions : Check channel permissions before sending log messages
Event handler template
Use this template for new event handlers:
const { MessageEmbed } = require ( 'discord.js' );
const colors = require ( '../config/colors.json' );
module . exports = {
name: 'eventName' ,
once: false , // Set to true for one-time events like 'ready'
async execute ( ... args ) {
try {
// Your event logic here
} catch ( error ) {
console . error ( `Error in ${ this . name } event:` , error );
}
}
};
Discord.js v12 has limited support for some newer Discord features. Consider upgrading to v14+ for full feature support.