/** * Structured logging service – posts embeds to dedicated Discord channels. * Call setClient(client) from the main bot on ready so logs can be posted. */ const { EmbedBuilder } = require('discord.js'); const { CONFIG } = require('../config'); let client = null; function setClient(c) { client = c; } // --- Helpers --- async function sendToChannel(channelId, embed, overrideClient) { const c = overrideClient || client; if (!c || !channelId) return; try { const channel = await c.channels.fetch(channelId); if (channel) await channel.send({ embeds: [embed] }); } catch (_) { // ignore send failures } } // --- logError (backwards-compatible) --- async function logError(context, error, interaction = null, overrideClient = null) { const c = overrideClient || client; if (!c || !CONFIG.DEBUGGING_CHANNEL_ID) return; try { const channel = await c.channels.fetch(CONFIG.DEBUGGING_CHANNEL_ID); const userLine = interaction?.user?.tag ? `User: ${interaction.user.tag}\n` : ''; const commandLine = (interaction?.commandName || interaction?.customId) ? `Command/Button: ${interaction.commandName || interaction.customId}\n` : ''; const stack = (error.stack || error.message || String(error)).slice(0, 1500); await channel.send({ content: `\`[${context}]\` ${error.message || String(error)}\n${userLine}${commandLine}\n\`\`\`${stack}\`\`\`` }); } catch (_) { // ignore send failures } } // --- logWarn --- async function logWarn(context, message, overrideClient = null) { const embed = new EmbedBuilder() .setTitle(`Warning: ${context}`) .setDescription(String(message).slice(0, 4000)) .setColor(0xFFFF00) .setTimestamp(); await sendToChannel(CONFIG.DEBUGGING_CHANNEL_ID, embed, overrideClient); } // --- logEvent (generic – posts to any configured channel) --- async function logEvent(channelConfigKey, embed, overrideClient = null) { const channelId = CONFIG[channelConfigKey]; await sendToChannel(channelId, embed, overrideClient); } // --- logTicketEvent --- async function logTicketEvent(action, fields, interaction = null) { const embed = new EmbedBuilder() .setTitle(action) .setColor(CONFIG.EMBED_COLOR_INFO || 0x1e2124) .addFields(fields.map(f => ({ name: f.name, value: String(f.value).slice(0, 1024), inline: f.inline ?? true }))) .setTimestamp(); if (interaction?.user?.tag) { embed.setFooter({ text: interaction.user.tag }); } await sendToChannel(CONFIG.LOG_CHAN, embed, interaction?.client); } // --- logGmail --- async function logGmail(...args) { return; } // --- logAutomation --- async function logAutomation(...args) { return; } // --- logSecurity --- async function logSecurity(...args) { return; } // --- logIntegrity --- async function logIntegrity(issue, detail, overrideClient = null) { const embed = new EmbedBuilder() .setTitle('Ticket Integrity Issue') .setColor(0xFF0000) .addFields( { name: 'Issue', value: String(issue).slice(0, 256), inline: false }, { name: 'Detail', value: String(detail || 'N/A').slice(0, 1024), inline: false }, { name: 'Timestamp', value: new Date().toISOString(), inline: true } ) .setTimestamp(); await sendToChannel(CONFIG.DEBUGGING_CHANNEL_ID, embed, overrideClient); } // --- logSystem --- async function logSystem(...args) { return; } module.exports = { setClient, logError, logWarn, logEvent, logTicketEvent, logGmail, logAutomation, logSecurity, logIntegrity, logSystem };