forked from syntaxbullet/AuroraBot-discord
refactor(core): centralize interaction error handling and organize routes
This commit is contained in:
@@ -1,11 +1,14 @@
|
||||
import { ButtonInteraction, StringSelectMenuInteraction, ModalSubmitInteraction } from "discord.js";
|
||||
import { ButtonInteraction, StringSelectMenuInteraction, ModalSubmitInteraction, MessageFlags } from "discord.js";
|
||||
import { logger } from "@lib/logger";
|
||||
import { UserError } from "@lib/errors";
|
||||
import { createErrorEmbed } from "@lib/embeds";
|
||||
|
||||
type ComponentInteraction = ButtonInteraction | StringSelectMenuInteraction | ModalSubmitInteraction;
|
||||
|
||||
/**
|
||||
* Handles component interactions (buttons, select menus, modals)
|
||||
* Routes to appropriate handlers based on customId patterns
|
||||
* Provides centralized error handling with UserError differentiation
|
||||
*/
|
||||
export class ComponentInteractionHandler {
|
||||
static async handle(interaction: ComponentInteraction): Promise<void> {
|
||||
@@ -17,12 +20,59 @@ export class ComponentInteractionHandler {
|
||||
const handlerMethod = module[route.method];
|
||||
|
||||
if (typeof handlerMethod === 'function') {
|
||||
await handlerMethod(interaction);
|
||||
return;
|
||||
try {
|
||||
await handlerMethod(interaction);
|
||||
return;
|
||||
} catch (error) {
|
||||
await this.handleError(interaction, error, route.method);
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
logger.error(`Handler method ${route.method} not found in module`);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles errors from interaction handlers
|
||||
* Differentiates between UserError (user-facing) and system errors
|
||||
*/
|
||||
private static async handleError(
|
||||
interaction: ComponentInteraction,
|
||||
error: unknown,
|
||||
handlerName: string
|
||||
): Promise<void> {
|
||||
const isUserError = error instanceof UserError;
|
||||
|
||||
// Determine error message
|
||||
const errorMessage = isUserError
|
||||
? (error as Error).message
|
||||
: 'An unexpected error occurred. Please try again later.';
|
||||
|
||||
// Log system errors (non-user errors) for debugging
|
||||
if (!isUserError) {
|
||||
logger.error(`Error in ${handlerName}:`, error);
|
||||
}
|
||||
|
||||
const errorEmbed = createErrorEmbed(errorMessage);
|
||||
|
||||
try {
|
||||
// Handle different interaction states
|
||||
if (interaction.replied || interaction.deferred) {
|
||||
await interaction.followUp({
|
||||
embeds: [errorEmbed],
|
||||
flags: MessageFlags.Ephemeral
|
||||
});
|
||||
} else {
|
||||
await interaction.reply({
|
||||
embeds: [errorEmbed],
|
||||
flags: MessageFlags.Ephemeral
|
||||
});
|
||||
}
|
||||
} catch (replyError) {
|
||||
// If we can't send a reply, log it
|
||||
logger.error(`Failed to send error response in ${handlerName}:`, replyError);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,11 +19,14 @@ interface InteractionRoute {
|
||||
}
|
||||
|
||||
export const interactionRoutes: InteractionRoute[] = [
|
||||
// --- TRADE MODULE ---
|
||||
{
|
||||
predicate: (i) => i.customId.startsWith("trade_") || i.customId === "amount",
|
||||
handler: () => import("@/modules/trade/trade.interaction"),
|
||||
method: 'handleTradeInteraction'
|
||||
},
|
||||
|
||||
// --- ECONOMY MODULE ---
|
||||
{
|
||||
predicate: (i) => i.isButton() && i.customId.startsWith("shop_buy_"),
|
||||
handler: () => import("@/modules/economy/shop.interaction"),
|
||||
@@ -34,16 +37,22 @@ export const interactionRoutes: InteractionRoute[] = [
|
||||
handler: () => import("@/modules/economy/lootdrop.interaction"),
|
||||
method: 'handleLootdropInteraction'
|
||||
},
|
||||
|
||||
// --- ADMIN MODULE ---
|
||||
{
|
||||
predicate: (i) => i.customId.startsWith("createitem_"),
|
||||
handler: () => import("@/modules/admin/item_wizard"),
|
||||
method: 'handleItemWizardInteraction'
|
||||
},
|
||||
|
||||
// --- USER MODULE ---
|
||||
{
|
||||
predicate: (i) => i.isButton() && i.customId === "enrollment",
|
||||
handler: () => import("@/modules/user/enrollment.interaction"),
|
||||
method: 'handleEnrollmentInteraction'
|
||||
},
|
||||
|
||||
// --- FEEDBACK MODULE ---
|
||||
{
|
||||
predicate: (i) => i.customId.startsWith("feedback_"),
|
||||
handler: () => import("@/modules/feedback/feedback.interaction"),
|
||||
|
||||
Reference in New Issue
Block a user