import { Client, GatewayIntentBits } from "discord.js"; import fetch from "node-fetch"; const DISCORD_TOKEN = process.env.DISCORD_TOKEN; const N8N_WEBHOOK = process.env.N8N_WEBHOOK; if (!DISCORD_TOKEN) { console.error("❌ DISCORD_TOKEN is missing. Set the env var DISCORD_TOKEN."); process.exit(1); } if (!N8N_WEBHOOK) { console.error("❌ N8N_WEBHOOK is missing. Set the env var N8N_WEBHOOK."); process.exit(1); } const client = new Client({ intents: [ GatewayIntentBits.Guilds, GatewayIntentBits.GuildMessages, GatewayIntentBits.MessageContent ] }); client.once("ready", () => { console.log(`✅ Ready! Logged in as ${client.user.tag}`); }); client.on("messageCreate", async (message) => { try { if (message.author.bot) return; console.log(`📩 Message from ${message.author.tag} in ${message.guild ? message.guild.name : "DM"}: ${message.content}`); // envoi vers n8n const res = await fetch(N8N_WEBHOOK, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ text: message.content, user: message.author.username }) }); const rawText = await res.text(); // récup brut console.log("↩️ n8n response raw:", rawText); let data; try { // cas 1 : réponse directement en JSON data = JSON.parse(rawText); } catch { // cas 2 : n8n a renvoyé du texte avec JSON dedans const jsonMatch = rawText.match(/```json([\s\S]*?)```/i) || rawText.match(/{[\s\S]*}/); if (jsonMatch) { try { data = JSON.parse(jsonMatch[1] || jsonMatch[0]); } catch (e) { console.warn("⚠️ Impossible de parser le JSON extrait :", e); } } } // fallback si rien de parsé if (!data) { data = { reply: rawText.trim() }; // au moins répondre avec le texte brut } // nettoyer le champ reply si présent if (data.reply) { data.reply = data.reply .replace(/```[\s\S]*?```/g, "") // supprime blocs de code .replace(/\\n/g, "\n") // normalise retours ligne .trim(); } // === Envoi de la réponse === if (data.reply) { await message.reply(data.reply); } else { await message.reply("⚠️ Sire, je n’ai point reçu de réponse de l’oracle n8n !"); } // === Si action clear_channel demandée === if (data.action === "clear_channel" && data.channel_id && Array.isArray(data.messages_to_delete)) { const channel = await client.channels.fetch(data.channel_id); if (channel && channel.isTextBased()) { for (const msgId of data.messages_to_delete) { try { const msg = await channel.messages.fetch(msgId); if (msg) await msg.delete(); } catch (err) { console.error(`❌ Failed to delete message ${msgId}:`, err); } } console.log(`✅ Deleted ${data.messages_to_delete.length} messages in ${channel.id}`); } } } catch (err) { console.error("🔴 Error in message handler:", err); await message.reply("⚠️ Sire, une erreur est survenue lors de ma consultation de n8n !"); } }); process.on("unhandledRejection", (r) => { console.error("UnhandledRejection:", r); }); process.on("uncaughtException", (err) => { console.error("UncaughtException:", err); process.exit(1); }); client.login(DISCORD_TOKEN).catch(err => { console.error("Failed to login to Discord:", err); process.exit(1); });