const express = require('express'); const qrcode = require('qrcode'); const { default: makeWASocket, useMultiFileAuthState, DisconnectReason, fetchLatestBaileysVersion, generateWAMessageFromContent, proto } = require('@whiskeysockets/baileys'); const { Boom } = require('@hapi/boom'); const app = express(); app.use(express.json()); let sock; let qrCodeData = null; let isConnected = false; async function startSock() { const { state, saveCreds } = await useMultiFileAuthState('auth_info'); const { version } = await fetchLatestBaileysVersion(); sock = makeWASocket({ version, auth: state, printQRInTerminal: true }); sock.ev.on('connection.update', async ({ connection, lastDisconnect, qr }) => { if (qr) { qrCodeData = await qrcode.toDataURL(qr); } if (connection === 'close') { const shouldReconnect = (lastDisconnect?.error instanceof Boom) && lastDisconnect.error.output.statusCode !== DisconnectReason.loggedOut; console.log('❌ Déconnecté. Reconnexion :', shouldReconnect); if (shouldReconnect) startSock(); } else if (connection === 'open') { console.log('✅ Connecté à WhatsApp'); isConnected = true; } }); sock.ev.on('creds.update', saveCreds); } startSock(); app.get('/api/qrcode', (req, res) => { res.json({ qr: qrCodeData, connected: isConnected }); }); app.post('/sendText', async (req, res) => { const { phone, message } = req.body; if (!sock || !isConnected) return res.status(400).json({ error: 'Non connecté' }); try { await sock.sendMessage(`${phone}@s.whatsapp.net`, { text: message }); res.json({ success: true }); } catch (e) { res.status(500).json({ error: e.message }); } }); app.post('/sendImage', async (req, res) => { const { phone, imageUrl, caption } = req.body; if (!sock || !isConnected) return res.status(400).json({ error: 'Non connecté' }); try { await sock.sendMessage(`${phone}@s.whatsapp.net`, { image: { url: imageUrl }, caption: caption || '' }); res.json({ success: true }); } catch (e) { res.status(500).json({ error: e.message }); } }); app.post('/sendDocument', async (req, res) => { const { phone, documentUrl, fileName, mimetype } = req.body; if (!sock || !isConnected) return res.status(400).json({ error: 'Non connecté' }); try { await sock.sendMessage(`${phone}@s.whatsapp.net`, { document: { url: documentUrl }, fileName: fileName || 'fichier.pdf', mimetype: mimetype || 'application/pdf' }); res.json({ success: true }); } catch (e) { res.status(500).json({ error: e.message }); } }); app.post('/sendInteractive', async (req, res) => { const { phone } = req.body; if (!sock || !isConnected) return res.status(400).json({ error: 'Non connecté' }); try { const jid = `${phone}@s.whatsapp.net`; const content = { viewOnceMessage: { message: { messageContextInfo: { deviceListMetadata: {}, deviceListMetadataVersion: 2 }, interactiveMessage: proto.Message.InteractiveMessage.create({ body: { text: 'Bienvenue ! Choisissez une action :' }, footer: { text: 'Service WhatsApp' }, nativeFlowMessage: { buttons: [ { name: 'cta_reply', buttonParamsJson: JSON.stringify({ display_text: '✅ Confirmer', id: 'confirm_action' }) }, { name: 'cta_url', buttonParamsJson: JSON.stringify({ display_text: '🌐 Site Web', url: 'https://canguidev.fr' }) } ] } }) } } }; const msg = generateWAMessageFromContent(jid, content, {}); await sock.relayMessage(jid, msg.message, { messageId: msg.key.id }); res.json({ success: true }); } catch (e) { console.error('❌ Erreur interactive :', e); res.status(500).json({ error: e.message }); } }); const PORT = process.env.PORT || 3001; app.listen(PORT, () => { console.log(`🚀 Serveur prêt sur http://localhost:${PORT}`); });