// Discord-Client: Commands laden, registrieren und Interactions verarbeiten import { Client, Collection, Events, GatewayIntentBits, Partials, REST, Routes } from 'discord.js'; import { config } from '../config.js'; import { archiveDevlogMessage, removeDevlog } from './devlog-archive.js'; import * as ping from './commands/ping.js'; import * as devlogBackfill from './commands/devlog-backfill.js'; // Alle Commands hier eintragen — jedes Modul exportiert { data, execute } const commandModules = [ping, devlogBackfill]; export async function startBot() { const client = new Client({ intents: [ GatewayIntentBits.Guilds, // Für das Devlog-Archiv: Nachrichten im Devlog-Kanal mitlesen // (erfordert aktivierten "Message Content Intent" im Developer Portal!) GatewayIntentBits.GuildMessages, GatewayIntentBits.MessageContent, ], // Partials, damit MessageDelete auch für ungecachte (ältere) Nachrichten feuert partials: [Partials.Message], }); // Commands in Collection ablegen für schnellen Zugriff im Interaction-Handler client.commands = new Collection(); for (const command of commandModules) { client.commands.set(command.data.name, command); } client.once(Events.ClientReady, async (readyClient) => { console.log(`[bot] Eingeloggt als ${readyClient.user.tag}`); await registerCommands(); }); // Live-Archivierung: neue Devlogs (Webhook-Posts im Devlog-Kanal) sofort sichern client.on(Events.MessageCreate, async (message) => { if (message.channelId !== config.devlogChannelId) return; try { if (await archiveDevlogMessage(message)) { console.log(`[devlog] Neues Devlog archiviert (${message.id})`); } } catch (error) { console.error('[devlog] Archivierung fehlgeschlagen:', error); } }); // In Discord gelöscht = im Archiv gelöscht (inkl. lokaler Bilder) client.on(Events.MessageDelete, async (message) => { if (message.channelId !== config.devlogChannelId) return; try { if (await removeDevlog(message.id)) { console.log(`[devlog] Archiv-Eintrag entfernt (Discord-Nachricht ${message.id} gelöscht)`); } } catch (error) { console.error('[devlog] Archiv-Löschung fehlgeschlagen:', error); } }); client.on(Events.InteractionCreate, async (interaction) => { if (!interaction.isChatInputCommand()) return; const command = client.commands.get(interaction.commandName); if (!command) return; try { await command.execute(interaction); } catch (error) { console.error(`[bot] Fehler bei /${interaction.commandName}:`, error); const reply = { content: '❌ Da ist etwas schiefgelaufen.', ephemeral: true }; if (interaction.replied || interaction.deferred) { await interaction.followUp(reply).catch(() => {}); } else { await interaction.reply(reply).catch(() => {}); } } }); await client.login(config.discordToken); return client; } /** Slash-Commands bei Discord registrieren (Guild = sofort sichtbar, global = bis zu 1h Delay) */ async function registerCommands() { const rest = new REST().setToken(config.discordToken); const body = commandModules.map((c) => c.data.toJSON()); const route = config.discordGuildId ? Routes.applicationGuildCommands(config.discordClientId, config.discordGuildId) : Routes.applicationCommands(config.discordClientId); await rest.put(route, { body }); console.log( `[bot] ${body.length} Slash-Command(s) registriert (${config.discordGuildId ? 'Guild' : 'global'})` ); }