import express from 'express'; import * as wppconnect from './index'; import { Resolver } from 'dns'; import fs from 'fs'; import path from 'path'; const app = express(); const port = process.env.NODE_PORT || 3000; let whatsappClient: wppconnect.Whatsapp | null = null; let lastQR: { ascii: string, base64: string } | null = null; let statusMsg: string = 'Disconnected'; let appLogs: string[] = []; let isReady = false; let isInitializing = false; const log = (msg: string) => { const entry = `${new Date().toISOString()} - ${msg}`; console.log(entry); appLogs.push(entry); if (appLogs.length > 500) appLogs.shift(); }; app.use(express.json()); app.get('/health', (req, res) => { res.json({ status: 'UP', connected: !!whatsappClient, ready: isReady, whatsappStatus: statusMsg, hasQR: !!lastQR, logs: appLogs }); }); app.get('/qr-data', (req, res) => { if (lastQR) res.json(lastQR); else res.status(404).json({ error: 'No QR' }); }); app.get('/screenshot', async (req, res) => { if (whatsappClient && whatsappClient.page && !whatsappClient.page.isClosed()) { try { const screenshot = await whatsappClient.page.screenshot({ encoding: 'base64' }); const img = Buffer.from(screenshot as string, 'base64'); res.writeHead(200, { 'Content-Type': 'image/png', 'Content-Length': img.length }); res.end(img); } catch (e: any) { res.status(500).json({ error: e.message }); } } else { res.status(404).json({ error: 'Browser not active' }); } }); app.post('/init', (req, res) => { if (isInitializing) return res.json({ success: false, message: 'Already initializing' }); startWPP(); res.json({ success: true }); }); app.post('/clear-session', (req, res) => { log('Manual session clear'); try { const tokensDir = path.join(process.cwd(), 'tokens'); if (fs.existsSync(tokensDir)) fs.rmSync(tokensDir, { recursive: true, force: true }); whatsappClient = null; isReady = false; lastQR = null; statusMsg = 'Cleared'; res.json({ success: true }); } catch (e: any) { res.status(500).json({ error: e.message }); } }); app.post('/send-poll', async (req, res) => { const { telnumber, name, choices } = req.body; if (!whatsappClient || !isReady) return res.status(503).json({ error: 'WhatsApp not ready' }); try { const result = await whatsappClient.sendPollMessage(`${telnumber}@c.us`, name, choices); res.json({ success: true, result }); } catch (e: any) { res.status(500).json({ error: e.message }); } }); async function resolveMany(hosts: string[]): Promise { const resolver = new Resolver(); resolver.setServers(['8.8.8.8', '1.1.1.1']); const rules: string[] = []; for (const host of hosts) { try { const addrs = await new Promise((resolve, reject) => { resolver.resolve4(host, (err, addresses) => err ? reject(err) : resolve(addresses)); }); if (addrs.length > 0) { rules.push(`MAP ${host} ${addrs[0]}`); } } catch (e) {} } return rules; } async function startWPP() { if (isInitializing) return; isInitializing = true; statusMsg = 'Initializing...'; log('Starting initialization...'); const dnsRules = await resolveMany([ 'web.whatsapp.com', 'static.whatsapp.net', 'pps.whatsapp.net', 'mms.whatsapp.net' ]); const hostRules = dnsRules.join(','); if (hostRules) log(`Host Rules: ${hostRules}`); try { whatsappClient = await wppconnect.create({ session: 'hf-session', catchQR: (base64, ascii) => { lastQR = { base64, ascii }; statusMsg = 'Waiting for scan'; log('QR code updated'); }, statusFind: (status) => { statusMsg = status; log('Status: ' + status); if (status === 'inChat') { isReady = true; lastQR = null; } }, headless: true, useChrome: false, puppeteerOptions: { executablePath: '/usr/bin/chromium', args: [ '--no-sandbox', '--disable-setuid-sandbox', '--disable-dev-shm-usage', '--disable-gpu', '--disable-web-security', hostRules ? `--host-resolver-rules=${hostRules}` : '' ].filter(Boolean), }, autoClose: 0, updatesLog: false, waitForLogin: false, }); if (whatsappClient.page) { whatsappClient.page.on('console', msg => { const text = msg.text(); if (!text.includes('TypeError: window.WAPI') && !text.includes('WAPI is not defined')) { log(`Browser: ${text}`); } }); } log('Client Object Created'); } catch (e: any) { log('Init Error: ' + e.message); statusMsg = 'Error: ' + e.message; } finally { isInitializing = false; } } app.listen(port, () => { log(`Node Backend on port ${port}`); setTimeout(startWPP, 5000); });