Command & Event Handling
Relevant source files
The following files were used as context for generating this wiki page:
Introduction
The Command and Event Handling system is the core of Amina's interactivity, responsible for processing all incoming interactions from Discord. This includes slash commands, buttons, select menus, and modals. The architecture is designed to be modular and scalable, dynamically loading command and event files at startup.
The system's entry point is the interactionCreate event, which acts as a central router. It inspects the type and customId of each interaction and delegates it to the appropriate handler module. This allows for a clean separation of concerns, where each command, component, and feature has its own dedicated logic file.
System Architecture
The overall architecture follows a clear, event-driven flow from the BotClient to specific handlers. At startup, the BotClient loads all event listeners and command definitions from the filesystem. When a user interacts with the bot, Discord fires an interactionCreate event, which is caught by the main listener. This listener then routes the interaction to the correct handler based on its type and properties.
The following diagram illustrates the high-level data flow for handling interactions.
BotClient Initialization
The BotClient class is the heart of the application, extending Discord.js's Client. During its initialization, it is responsible for loading all commands, context menus, and event listeners.
Sources: src/structures/BotClient.ts
Event Loading
The loadEvents method recursively reads all .js and .ts files from the specified events directory. For each file, it uses the filename as the event name (e.g., interactionCreate.ts becomes the interactionCreate event). It then binds the exported function from the file as a listener for that event.
Sources: src/structures/BotClient.ts:153-185
Command Loading
The loadCommands method is responsible for discovering and registering all slash commands. It recursively reads the commands directory, validates each command object against a predefined structure, and stores it in the client.slashCommands collection if it's enabled.
Key steps in the loadCommand method include:
- Category Check: Skips the command if its category is disabled in the configuration.
- Slash Command Check: Only processes commands where
slashCommand.enabledistrue. - Global Flag: If
config.INTERACTIONS.GLOBALisfalse, it will only load developer or test-guild-only commands, skipping global ones. - Registration: Valid commands are added to the
client.slashCommandscollection, keyed by their name.
Sources: src/structures/BotClient.ts:194-250
The interactionCreate Event Router
The src/events/interactions/interactionCreate.ts file is the primary entry point for all user interactions. It functions as a sophisticated router, determining the interaction type and delegating it to the correct handler.
The router uses a series of if statements to check the interaction type:
isAutocomplete()isChatInputCommand()isContextMenuCommand()isButton()isModalSubmit()isStringSelectMenu()isChannelSelectMenu(),isUserSelectMenu(),isRoleSelectMenu()
This routing logic is visualized below.
Component Interaction Routing
For component interactions (buttons, modals, select menus), the router relies on a customId naming convention to delegate tasks. customIds are prefixed with a category and type, such as ticket:btn:, dev:menu:, or profile:modal:. The interactionCreate handler parses these prefixes to import and call the correct handler function dynamically.
For example, a button with customId dev:btn:back will be routed to the handleDevBackButton function within the dev handler module.
Sources: src/events/interactions/interactionCreate.ts:80-350, src/handlers/dev/main-hub.ts:98-101
Command Structure
All commands in the application must conform to the CommandData interface defined in types/commands.d.ts. This standardized structure ensures that the command handler can process any command reliably.
Sources: types/commands.d.ts, src/commands/utility/help.ts:17-45, src/commands/bot/bot.ts:19-71
CommandData Interface
The CommandData interface defines the properties of a command object.
Sources: types/commands.d.ts:29-60
The key properties of the CommandData interface are detailed in the table below.
| Property | Type | Description |
|---|---|---|
name | string | The name of the command. Must be unique. |
description | string | A brief explanation of what the command does. |
category | CommandCategory | The category the command belongs to (e.g., 'UTILITY', 'MODERATION'). |
botPermissions | PermissionResolvable[] | Permissions the bot requires to execute the command. |
userPermissions | PermissionResolvable[] | Permissions the user requires to execute the command. |
slashCommand | InteractionInfo | Configuration for the slash command, including enabled, ephemeral, and options. |
devOnly | boolean | If true, the command can only be used by developers. |
testGuildOnly | boolean | If true, the command is restricted to the test guild. |
interactionRun | function | The main execution function for the command. It receives the ChatInputCommandInteraction object. |
Sources: types/commands.d.ts:29-60, src/commands/bot/bot.ts:19-71
Command Execution Flow
When a user executes a slash command, a sequence of events is triggered, leading to the execution of the command's interactionRun function.
The sequence diagram below shows the typical flow for a slash command.
The commandHandler (invoked from interactionCreate.ts) is responsible for:
- Retrieving the command object from the
client.slashCommandscollection using the command name. - Performing necessary validations, such as checking user and bot permissions, developer-only status, and command cooldowns.
- If all validations pass, it calls the
interactionRunmethod from the command's file, passing the interaction object. - Handling any errors that occur during command execution and sending an appropriate reply to the user.
Conclusion
Amina's Command and Event Handling system is a robust and well-structured architecture that effectively decouples interaction routing from business logic. The use of a central interactionCreate router, dynamic loading of handlers via BotClient, and a standardized CommandData structure makes the system easy to maintain and extend. The conventional use of customId prefixes for component routing further enhances modularity, allowing developers to add complex, multi-step interactions without cluttering the main event listener.