import express from "express"; import { createServer as createViteServer } from "vite"; import * as wppconnect from '@wppconnect-team/wppconnect'; import path from "path"; import { fileURLToPath } from 'url'; const __filename = fileURLToPath(import.meta.url); const __dirname = path.dirname(__filename); let wppClient = null; let currentStatus = 'DISCONNECTED'; let qrCodeBase64 = ''; let logs = []; function addLog(msg) { const timestamp = new Date().toLocaleTimeString(); logs.push(`[${timestamp}] ${msg}`); if (logs.length > 100) logs.shift(); console.log(`[WPPConnect] ${msg}`); } // Middleware to check passkey function checkPasskey(req, res, next) { const passkey = process.env.PASSKEY; if (!passkey) { return next(); } const providedPasskey = req.headers['x-passkey'] || req.headers['authorization'] || req.query.passkey; if (providedPasskey === passkey || providedPasskey === `Bearer ${passkey}`) { return next(); } res.status(401).json({ error: 'Unauthorized: Invalid passkey' }); } async function startServer() { const app = express(); const PORT = process.env.PORT || 7860; app.use(express.json()); app.use(express.urlencoded({ extended: true })); // Health check endpoint (unprotected) app.get("/health", (req, res) => { res.status(200).send("OK"); }); // API Documentation endpoint app.get("/api-docs", (req, res) => { const docs = ` WPPConnect API Documentation

WPPConnect API Documentation

All API requests require authentication via the x-passkey header, Authorization: Bearer <passkey>, or ?passkey=... query parameter.

Base URL: https://auxteam-plandex-backup.hf.space

POST /api/send-to-group-name

Find a group by its name and send a message, poll, or link.

Body: { 
  "groupName": "Team Alpha", 
  "message": "Hello Team!",
  "date": "2023-10-27", (optional, will be prepended to message)
  "links": "https://example.com", (optional, will be appended to message)
  "poll": { (optional)
    "name": "Lunch Choice?", 
    "options": ["Pizza", "Burgers"] 
  } 
}

POST /api/send-by-link

Join a group via link and send a message/poll. Useful for automated triggers.

Body: { 
  "link": "https://chat.whatsapp.com/...", 
  "message": "Optional text message",
  "poll": { 
    "name": "Poll Name", 
    "options": ["Opt1", "Opt2"] 
  } 
}

GET /api/status

Get connection status and QR code.

POST /api/send

Standard send endpoint.

Body: { "phone": "ID", "message": "Text", "isGroup": true/false }
`; res.send(docs); }); // Login endpoint app.post('/api/login', (req, res) => { const { passkey } = req.body; const envPasskey = process.env.PASSKEY; if (!envPasskey || passkey === envPasskey) { res.json({ success: true }); } else { res.status(401).json({ success: false, error: 'Invalid passkey' }); } }); // Protect all other API routes app.use('/api', (req, res, next) => { if (req.path === '/login') return next(); checkPasskey(req, res, next); }); // API Routes app.post('/api/start', async (req, res) => { if (currentStatus === 'INITIALIZING' || currentStatus === 'CONNECTED') { return res.json({ success: true, status: currentStatus }); } currentStatus = 'INITIALIZING'; qrCodeBase64 = ''; addLog('Starting WPPConnect session...'); res.json({ success: true }); try { wppClient = await wppconnect.create({ session: 'gradio-session', catchQR: (base64Qr) => { currentStatus = 'QR_CODE'; qrCodeBase64 = base64Qr; }, statusFind: (statusSession) => { if (statusSession === 'isLogged' || statusSession === 'inChat') { currentStatus = 'CONNECTED'; qrCodeBase64 = ''; } }, headless: true, puppeteerOptions: { executablePath: process.env.PUPPETEER_EXECUTABLE_PATH || null, args: ['--no-sandbox', '--disable-setuid-sandbox'] } }); currentStatus = 'CONNECTED'; addLog('WPPConnect client is ready.'); } catch (error) { currentStatus = 'ERROR'; addLog(`Error: ${error.message}`); } }); app.get('/api/status', (req, res) => { res.json({ status: currentStatus, qrCode: qrCodeBase64, logs }); }); app.get('/api/groups', async (req, res) => { if (!wppClient || currentStatus !== 'CONNECTED') return res.status(400).json({ error: 'Not connected' }); try { const groups = await wppClient.getAllGroups(); res.json({ success: true, groups }); } catch (error) { res.status(500).json({ error: error.message }); } }); app.post('/api/send', async (req, res) => { if (!wppClient || currentStatus !== 'CONNECTED') return res.status(400).json({ error: 'Not connected' }); const { phone, message, isGroup } = req.body; try { let recipient = phone; if (!phone.includes('@')) recipient = isGroup ? `${phone}@g.us` : `${phone}@c.us`; const result = await wppClient.sendText(recipient, message); res.json({ success: true, result }); } catch (error) { res.status(500).json({ error: error.message }); } }); app.post('/api/send-to-group-name', async (req, res) => { if (!wppClient || currentStatus !== 'CONNECTED') return res.status(400).json({ error: 'Not connected' }); const { groupName, message, poll, date, links } = req.body; try { const groups = await wppClient.getAllGroups(); const group = groups.find(g => g.name === groupName || g.contact?.name === groupName); if (!group) return res.status(404).json({ error: 'Group not found' }); const groupId = group.id._serialized; let finalMessage = message || ''; if (date) finalMessage = `[${date}]\n${finalMessage}`; if (links) finalMessage = `${finalMessage}\n\n${links}`; let result; if (poll) { result = await wppClient.sendPollMessage(groupId, poll.name, poll.options, { selectableCount: 1 }); } else { result = await wppClient.sendText(groupId, finalMessage); } res.json({ success: true, result }); } catch (error) { res.status(500).json({ error: error.message }); } }); app.post('/api/send-by-link', async (req, res) => { if (!wppClient || currentStatus !== 'CONNECTED') return res.status(400).json({ error: 'Not connected' }); const { link, message, poll } = req.body; try { let inviteCode = link.match(/chat\.whatsapp\.com\/([^?]+)/)?.[1] || link; const groupInfo = await wppClient.joinGroup(inviteCode); const groupId = typeof groupInfo === 'string' ? groupInfo : groupInfo.id; let result; if (poll) { result = await wppClient.sendPollMessage(groupId, poll.name, poll.options, { selectableCount: 1 }); } else { result = await wppClient.sendText(groupId, message); } res.json({ success: true, groupId, result }); } catch (error) { res.status(500).json({ error: error.message }); } }); if (process.env.NODE_ENV !== "production") { const vite = await createViteServer({ server: { middlewareMode: true }, appType: "spa" }); app.use(vite.middlewares); } else { const distPath = path.join(__dirname, 'dist'); app.use(express.static(distPath)); app.get('*', (req, res) => res.sendFile(path.join(distPath, 'index.html'))); } app.listen(PORT, "0.0.0.0", () => console.log(`Server running on port ${PORT}`)); } startServer();