import { readdir } from "node:fs/promises"; import { join } from "node:path"; import type { Event } from "@shared/lib/types"; import type { LoadResult } from "./types"; import type { Client } from "../BotClient"; /** * Handles loading events from the file system */ export class EventLoader { private client: Client; constructor(client: Client) { this.client = client; } /** * Load events from a directory recursively */ async loadFromDirectory(dir: string, reload: boolean = false): Promise { const result: LoadResult = { loaded: 0, skipped: 0, errors: [] }; await this.scanDirectory(dir, reload, result); return result; } /** * Recursively scan directory for event files */ private async scanDirectory(dir: string, reload: boolean, result: LoadResult): Promise { try { const files = await readdir(dir, { withFileTypes: true }); for (const file of files) { const filePath = join(dir, file.name); if (file.isDirectory()) { await this.scanDirectory(filePath, reload, result); continue; } if (!file.name.endsWith('.ts') && !file.name.endsWith('.js')) continue; await this.loadEventFile(filePath, reload, result); } } catch (error) { console.error(`Error reading directory ${dir}:`, error); result.errors.push({ file: dir, error }); } } /** * Load a single event file */ private async loadEventFile(filePath: string, reload: boolean, result: LoadResult): Promise { try { const importPath = reload ? `${filePath}?t=${Date.now()}` : filePath; const eventModule = await import(importPath); const event = eventModule.default; if (this.isValidEvent(event)) { if (event.once) { this.client.once(event.name, (...args) => event.execute(...args)); } else { this.client.on(event.name, (...args) => event.execute(...args)); } console.log(`Loaded event: ${event.name}`); result.loaded++; } else { console.warn(`Skipping invalid event in ${filePath}`); result.skipped++; } } catch (error) { console.error(`Failed to load event from ${filePath}:`, error); result.errors.push({ file: filePath, error }); } } /** * Type guard to validate event structure */ private isValidEvent(event: any): event is Event { return event && typeof event === 'object' && 'name' in event && 'execute' in event; } }