const express = require('express'); const qrcode = require('qrcode'); const path = require('path'); const fs = require('fs'); const NodeCache = require('node-cache'); const { makeWASocket, useMultiFileAuthState, DisconnectReason, fetchLatestBaileysVersion, generateWAMessageFromContent, proto } = require('@whiskeysockets/baileys'); const app = express(); app.use(express.json()); app.use(express.static('public')); let sock; let qrData = null; let isConnected = false; const groupCache = new NodeCache({ stdTTL: 300, useClones: false }); async function getMessageFromStore(key) { return { conversation: "Message temporaire pour retry" }; } const initBaileys = async () => { const { version } = await fetchLatestBaileysVersion(); const { state, saveCreds } = await useMultiFileAuthState('auth'); sock = makeWASocket({ version, auth: state, markOnlineOnConnect: false, getMessage: async (key) => await getMessageFromStore(key), cachedGroupMetadata: async (jid) => groupCache.get(jid) }); sock.ev.on('connection.update', async ({ connection, lastDisconnect, qr }) => { if (qr) { qrData = await qrcode.toDataURL(qr); isConnected = false; } if (connection === 'close') { const shouldReconnect = lastDisconnect?.error?.output?.statusCode !== DisconnectReason.loggedOut; console.log(shouldReconnect ? '🔁 Reconnexion...' : '❌ DĂ©connectĂ©.'); if (shouldReconnect) initBaileys(); } else if (connection === 'open') { console.log('✅ ConnectĂ© Ă  WhatsApp'); isConnected = true; } }); sock.ev.on('creds.update', saveCreds); sock.ev.on('messages.upsert', async ({ messages }) => { const msg = messages[0]; if (!msg.key.fromMe && msg.message?.conversation) { console.log('💬 Message reçu de', msg.key.remoteJid, ':', msg.message.conversation); } }); }; initBaileys(); app.get('/login', (req, res) => { res.sendFile(path.join(__dirname, 'public', 'login.html')); }); app.get('/api/qrcode', (req, res) => { res.json({ qr: qrData, 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('/sendButtons', async (req, res) => { const { phone } = req.body; if (!sock || !isConnected) return res.status(400).json({ error: 'Non connectĂ©' }); const jid = `${phone}@s.whatsapp.net`; const imageUrl = 'https://wa.canguidev.fr/static/logo-merlo-cs-FR.jpg'; const content = { viewOnceMessage: { message: { messageContextInfo: { deviceListMetadata: {}, deviceListMetadataVersion: 2 }, interactiveMessage: proto.Message.InteractiveMessage.create({ header: { hasMediaAttachment: true, imageMessage: { url: imageUrl } }, body: { text: 'Bienvenue !' }, footer: { text: 'Choisissez une action :' }, nativeFlowMessage: { buttons: [ { name: 'cta_reply', buttonParamsJson: JSON.stringify({ display_text: 'RĂ©pondre', id: 'reply_id' }) }, { name: 'cta_url', buttonParamsJson: JSON.stringify({ display_text: 'Site Web', url: 'https://canguidev.fr' }) } ] } }) } } }; try { const msg = generateWAMessageFromContent(jid, content, {}); await sock.relayMessage(jid, msg.message, { messageId: msg.key.id }); res.json({ success: true }); } catch (e) { console.error('❌ Erreur sendButtons :', e); res.status(500).json({ error: e.message }); } }); app.post('/sendInteractiveImage', async (req, res) => { const { phone } = req.body; if (!sock || !isConnected) return res.status(400).json({ error: 'Non connectĂ© Ă  WhatsApp' }); const jid = `${phone}@s.whatsapp.net`; const imageUrl = 'https://wa.canguidev.fr/static/logo-merlo-cs-FR.jpg'; const content = { viewOnceMessage: { message: { messageContextInfo: { deviceListMetadata: {}, deviceListMetadataVersion: 2 }, interactiveMessage: proto.Message.InteractiveMessage.create({ header: { hasMediaAttachment: true, imageMessage: { url: imageUrl } }, body: { text: '📄 Document interactif' }, footer: { text: 'SĂ©lectionne une option :' }, nativeFlowMessage: { buttons: [ { name: 'cta_url', buttonParamsJson: JSON.stringify({ display_text: 'Voir PDF', url: 'https://example.com/doc.pdf' }) } ] } }) } } }; try { 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 image :', e); res.status(500).json({ error: e.message }); } }); app.use((req, res) => res.status(404).json({ error: 'Ressource introuvable' })); app.use((err, req, res, next) => { console.error('❌ Middleware erreur :', err); res.status(500).json({ error: err.message }); }); app.listen(3001, () => console.log('🚀 Serveur Baileys opĂ©rationnel sur http://localhost:3001'));