This commit is contained in:
2026-01-29 12:26:13 +01:00
parent ba0f116bc2
commit 6dbcadcaee
79 changed files with 2795 additions and 657 deletions

View File

@@ -0,0 +1,40 @@
/**
* Guild events handlers
*/
import { Events } from "discord.js";
import type { EventHandler } from "../types";
import { guildRepository, userRepository } from "../../database";
import { createLogger } from "../../core/logger";
const logger = createLogger("Events:Guild");
export const guildCreateHandler: EventHandler<"guildCreate"> = {
name: Events.GuildCreate as "guildCreate",
once: false,
execute: async (_client, guild) => {
logger.info(`Joined guild: ${guild.name}`);
await guildRepository.create({
id: guild.id,
name: guild.name,
});
},
};
export const guildMemberAddHandler: EventHandler<"guildMemberAdd"> = {
name: Events.GuildMemberAdd as "guildMemberAdd",
once: false,
execute: async (_client, member) => {
await userRepository.addMembership(member.id, member.guild.id);
logger.debug(`Member joined: ${member.displayName} in ${member.guild.name}`);
},
};
export const guildMemberRemoveHandler: EventHandler<"guildMemberRemove"> = {
name: Events.GuildMemberRemove as "guildMemberRemove",
once: false,
execute: async (_client, member) => {
await userRepository.removeMembership(member.id);
logger.debug(`Member left: ${member.displayName} in ${member.guild.name}`);
},
};

View File

@@ -0,0 +1,8 @@
/**
* Event handler exports
*/
export { readyHandler } from "./ready";
export { messageCreateHandler } from "./message-create";
export { interactionCreateHandler } from "./interaction-create";
export { guildCreateHandler, guildMemberAddHandler, guildMemberRemoveHandler } from "./guild";

View File

@@ -0,0 +1,16 @@
/**
* Interaction Create event handler
*/
import { Events } from "discord.js";
import type { EventHandler } from "../types";
import { handleCommand } from "../../commands";
export const interactionCreateHandler: EventHandler<"interactionCreate"> = {
name: Events.InteractionCreate as "interactionCreate",
once: false,
execute: async (_client, interaction) => {
if (!interaction.isChatInputCommand()) return;
await handleCommand(interaction);
},
};

View File

@@ -0,0 +1,29 @@
/**
* Message Create event handler
*/
import { Events } from "discord.js";
import type { EventHandler } from "../types";
import { createLogger } from "../../core/logger";
import { messageLogger } from "../../features/message-logger";
import { joelResponder } from "../../features/joel";
const logger = createLogger("Events:MessageCreate");
export const messageCreateHandler: EventHandler<"messageCreate"> = {
name: Events.MessageCreate as "messageCreate",
once: false,
execute: async (client, message) => {
// Ignore bot messages
if (message.author.bot) return;
// Only process guild messages
if (!message.inGuild()) return;
// Log message to database
await messageLogger.logMessage(message);
// Handle Joel responses
await joelResponder.handleMessage(client, message);
},
};

View File

@@ -0,0 +1,58 @@
/**
* Client Ready event handler
*/
import { ActivityType, Events } from "discord.js";
import type { EventHandler } from "../types";
import { loadCommands, registerCommands } from "../../commands";
import { guildRepository } from "../../database";
import { createLogger } from "../../core/logger";
const logger = createLogger("Events:Ready");
export const readyHandler: EventHandler<"ready"> = {
name: Events.ClientReady as "ready",
once: true,
execute: async (client) => {
logger.info(`Logged in as ${client.user?.tag}`);
// Set initial activity
client.user?.setActivity({
name: "Joel blir väckt...",
type: ActivityType.Custom,
});
// Load and register commands
const commands = await loadCommands();
for (const command of commands) {
client.commands.set(command.data.name, command);
}
await registerCommands(commands, client.user!.id);
// Sync guilds with database
await syncGuilds(client);
// Update activity to show ready
client.user?.setActivity({
name: "Joel är VAKEN",
type: ActivityType.Custom,
});
logger.info("Bot is ready!");
},
};
async function syncGuilds(client: import("../../core/client").BotClient): Promise<void> {
const discordGuilds = await client.guilds.fetch();
const dbGuilds = await guildRepository.findAll();
const existingIds = new Set(dbGuilds.map((g) => g.id));
const toAdd = discordGuilds
.filter((g) => !existingIds.has(g.id))
.map((g) => ({ id: g.id, name: g.name }));
if (toAdd.length > 0) {
await guildRepository.createMany(toAdd);
logger.info(`Added ${toAdd.length} guilds to database`);
}
}

6
src/events/index.ts Normal file
View File

@@ -0,0 +1,6 @@
/**
* Events module exports
*/
export type { EventHandler } from "./types";
export { registerEvents } from "./register";

43
src/events/register.ts Normal file
View File

@@ -0,0 +1,43 @@
/**
* Event registration
*/
import type { BotClient } from "../core/client";
import { createLogger } from "../core/logger";
import type { AnyEventHandler } from "./types";
import {
readyHandler,
messageCreateHandler,
interactionCreateHandler,
guildCreateHandler,
guildMemberAddHandler,
guildMemberRemoveHandler,
} from "./handlers";
const logger = createLogger("Events:Register");
// All event handlers
const handlers: AnyEventHandler[] = [
readyHandler,
messageCreateHandler,
interactionCreateHandler,
guildCreateHandler,
guildMemberAddHandler,
guildMemberRemoveHandler,
];
/**
* Register all event handlers on the client
*/
export function registerEvents(client: BotClient): void {
for (const handler of handlers) {
if (handler.once) {
client.once(handler.name, (...args) => handler.execute(client, ...args));
} else {
client.on(handler.name, (...args) => handler.execute(client, ...args));
}
logger.debug(`Registered event: ${handler.name}`);
}
logger.info(`Registered ${handlers.length} event handlers`);
}

24
src/events/types.ts Normal file
View File

@@ -0,0 +1,24 @@
/**
* Event types and interfaces
*/
import type { ClientEvents } from "discord.js";
import type { BotClient } from "../core/client";
export interface EventHandler<K extends keyof ClientEvents = keyof ClientEvents> {
/** Event name to listen for */
name: K;
/** Whether to only run once */
once?: boolean;
/** Execute the event handler */
execute: (client: BotClient, ...args: ClientEvents[K]) => Promise<void> | void;
}
// Type-safe event handler that can be stored in an array
export type AnyEventHandler = {
name: keyof ClientEvents;
once?: boolean;
execute: (client: BotClient, ...args: any[]) => Promise<void> | void;
};