require('dotenv').config(); // Fix for Node 18+ IPv6 DNS resolution bug in Docker const dns = require('node:dns'); dns.setDefaultResultOrder('ipv4first'); const { Client, GatewayIntentBits, Partials, } = require('discord.js'); // ── Validate Environment ────────────────────────────────────── const required = ['BOT_TOKEN', 'OWNER_ID']; console.log(' 📋 ENV CHECK:', required.map(k => `${k}=${process.env[k] ? '✅' : '❌'}`).join(' | ')); for (const key of required) { if (!process.env[key] || process.env[key].includes('YOUR_')) { console.error(`❌ Missing or placeholder env var: ${key}`); console.error(' Please fill in your .env file before starting.'); process.exit(1); } } // ── Create Client ───────────────────────────────────────────── const client = new Client({ intents: [ GatewayIntentBits.Guilds, GatewayIntentBits.GuildMembers, GatewayIntentBits.GuildMessages, GatewayIntentBits.GuildMessageReactions, GatewayIntentBits.DirectMessages, GatewayIntentBits.MessageContent, GatewayIntentBits.GuildPresences, ], partials: [ Partials.Message, Partials.Channel, Partials.Reaction, Partials.User, Partials.GuildMember, ], }); // ── Load Event Handlers ─────────────────────────────────────── const events = [ require('./events/ready'), require('./events/messageCreate'), require('./events/messageReactionAdd'), require('./events/messageReactionRemove'), require('./events/guildMemberUpdate'), require('./events/guildMemberAdd'), require('./events/guildMemberRemove'), require('./events/interactionCreate'), ]; for (const event of events) { if (event.once) { client.once(event.name, (...args) => event.execute(client, ...args)); } else { client.on(event.name, (...args) => event.execute(client, ...args)); } } // ── Error Handling ──────────────────────────────────────────── client.on('error', (err) => { console.error('[Client Error]', err); }); process.on('unhandledRejection', (err) => { console.error('[Unhandled Rejection]', err); }); process.on('uncaughtException', (err) => { console.error('[Uncaught Exception]', err); process.exit(1); }); // ── Keep-Alive HTTP Server (for Render / Glitch + UptimeRobot) ─ const http = require('http'); const PORT = process.env.PORT || 3001; http.createServer((req, res) => { res.writeHead(200, { 'Content-Type': 'application/json' }); res.end(JSON.stringify({ status: 'alive', bot: client.user?.tag || 'starting...', uptime: Math.floor(process.uptime()) + 's', })); }).listen(PORT, () => { console.log(` 🌐 Keep-alive server on port ${PORT}`); }); // ── Login ───────────────────────────────────────────────────── const token = process.env.BOT_TOKEN; console.log(` 🔑 Token: ${token ? token.slice(0, 10) + '...' + token.slice(-5) : 'MISSING'}`); async function startBot(retryCount = 0) { if (retryCount > 10) { console.error('❌ MAX RETRIES REACHED. Bot failed to connect.'); process.exit(1); } console.log(` ⏳ Connecting to Discord... (Attempt ${retryCount + 1})`); const loginTimeout = setTimeout(() => { console.error('❌ LOGIN TIMED OUT after 60s — Discord gateway unreachable'); }, 60000); try { await client.login(token); clearTimeout(loginTimeout); console.log(' ✅ Login promise resolved'); } catch (err) { clearTimeout(loginTimeout); console.error(`❌ LOGIN FAILED: ${err.message}`); if (err.message.includes('ENOTFOUND') || err.message.includes('EAI_AGAIN')) { console.log(' 📡 DNS/Network error detected. Retrying in 10s...'); setTimeout(() => startBot(retryCount + 1), 10000); } else { console.error(' ⚠️ Non-network error. Exiting.'); process.exit(1); } } } // Debug logging for network issues client.on('debug', (info) => { if (info.includes('Gateway')) console.log(`[DEBUG] ${info}`); }); startBot();