diff --git a/index.js b/index.js index 93577dc..e62d585 100644 --- a/index.js +++ b/index.js @@ -1,6 +1,5 @@ -const { default: makeWASocket, useMultiFileAuthState, DisconnectReason, fetchLatestBaileysVersion, proto, generateWAMessageFromContent, generateWAMessageContent ,prepareWAMessageMedia} = require('@fizzxydev/baileys-pro'); +const venom = require('venom-bot'); const express = require('express'); -const { Boom } = require('@hapi/boom'); const qrcode = require('qrcode'); const path = require('path'); const fs = require('fs'); @@ -9,44 +8,42 @@ const app = express(); app.use(express.json()); app.use(express.static('public')); -let sock; +let client; let qrData = null; let isConnected = false; -const initBaileys = async () => { - const { version } = await fetchLatestBaileysVersion(); - const { state, saveCreds } = await useMultiFileAuthState('auth'); - - sock = makeWASocket({ - version, - auth: state, - printQRInTerminal: false, - }); - - sock.ev.on('connection.update', async (update) => { - const { connection, lastDisconnect, qr } = update; - if (qr) { - qrData = await qrcode.toDataURL(qr); - isConnected = false; - } - if (connection === 'close') { - const shouldReconnect = lastDisconnect?.error?.output?.statusCode !== DisconnectReason.loggedOut; - if (shouldReconnect) { - console.log('🔁 Reconnexion...'); - initBaileys(); - } else { - console.log('❌ Déconnecté.'); - } - } else if (connection === 'open') { - console.log('✅ Connecté à WhatsApp'); - isConnected = true; +// Initialisation Venom-bot +const initVenom = async () => { + client = await venom.create({ + session: 'whatsapp-session', + disableSpins: true, + logQR: false, + catchQR: (base64Qrimg) => { + qrcode.toDataURL(base64Qrimg, (err, url) => { + if (err) { + console.error('Erreur QR code:', err); + return; + } + qrData = url; + isConnected = false; + }); } }); - sock.ev.on('creds.update', saveCreds); + client.onStateChange((state) => { + console.log('État de connexion:', state); + isConnected = state === 'CONNECTED'; + + if (state === 'DISCONNECTED') { + console.log('🔁 Tentative de reconnexion...'); + setTimeout(initVenom, 5000); + } + }); }; -initBaileys(); +initVenom(); + +// Routes Express app.use('/static', express.static(path.join(__dirname, 'public'))); app.get('/login', (req, res) => { @@ -59,9 +56,10 @@ app.get('/api/qrcode', (req, res) => { app.post('/sendText', async (req, res) => { const { phone, message } = req.body; - if (!sock || !isConnected) return res.status(400).json({ error: 'Non connecté' }); + if (!client || !isConnected) return res.status(400).json({ error: 'Non connecté' }); + try { - await sock.sendMessage(`${phone}@s.whatsapp.net`, { text: message }); + await client.sendText(`${phone}@c.us`, message); res.json({ success: true }); } catch (e) { res.status(500).json({ error: e.message }); @@ -70,237 +68,100 @@ app.post('/sendText', async (req, res) => { app.post('/sendButtons', async (req, res) => { const { phone } = req.body; - if (!sock || !isConnected) return res.status(400).json({ error: 'Non connecté' }); + if (!client || !isConnected) return res.status(400).json({ error: 'Non connecté' }); try { - const content = { - message: { - interactiveMessage: proto.Message.InteractiveMessage.create({ - body: { text: "Bienvenue sur notre service !" }, - footer: { text: "Choisis une action ci-dessous" }, - header: { - title: "Menu principal", - hasMediaAttachment: false - }, - nativeFlowMessage: { - buttons: [ - { - name: "cta_reply", - buttonParamsJson: JSON.stringify({ - display_text: "📩 Contacter support", - id: "support_action" - }) - }, - { - name: "cta_url", - buttonParamsJson: JSON.stringify({ - display_text: "🌐 Voir notre site", - url: "https://canguidev.fr", - merchant_url: "https://canguidev.fr" - }) - }, - { - name: "cta_call", - buttonParamsJson: JSON.stringify({ - display_text: "📞 Appeler le support", - id: "+33612345678" - }) - } - ] - } - }) - } - }; - - const msg = generateWAMessageFromContent(`${phone}@s.whatsapp.net`, content, {}); - await sock.relayMessage(`${phone}@s.whatsapp.net`, msg.message, { messageId: msg.key.id }); - + const buttons = [ + { body: "📩 Contacter support" }, + { body: "🌐 Voir notre site" }, + { body: "📞 Appeler le support" } + ]; + + await client.sendButtons( + `${phone}@c.us`, + "Bienvenue sur notre service !", + buttons, + "Choisis une action ci-dessous" + ); + res.json({ success: true }); } catch (e) { - console.error('❌ Erreur bouton actif :', e); + console.error('❌ Erreur boutons:', e); res.status(500).json({ error: e.message }); } }); -// Votre route POST + app.post('/sendInteractiveImage', async (req, res) => { - const { phone, caption, title, subtitle, footer } = req.body; - if (!sock || !isConnected) { - return res.status(400).json({ error: 'Non connecté à WhatsApp' }); - } + const { phone, caption, footer } = req.body; + if (!client || !isConnected) return res.status(400).json({ error: 'Non connecté' }); try { const imagePath = path.join(__dirname, 'public', 'logo-merlo-cs-FR.jpg'); const imageBuffer = fs.readFileSync(imagePath); - // Upload the image first - const uploadedImage = await prepareWAMessageMedia( - { image: imageBuffer }, - { upload: sock.waUploadToServer } + await client.sendImage( + `${phone}@c.us`, + imageBuffer, + 'logo.jpg', + caption || 'Description par défaut', + { + footer: footer || 'Pied de page', + buttons: [ + { buttonId: 'id1', buttonText: { displayText: '📄 Voir proposition' }, type: 1 }, + { buttonId: 'id2', buttonText: { displayText: '🔧 Spécifications' }, type: 1 } + ] + } ); - - const interactiveMessage = { - imageMessage: uploadedImage.imageMessage, - caption: caption || 'Description par défaut', - footer: footer || 'Pied de page', - buttons: [ - { - buttonId: 'btn1', - buttonText: { displayText: '📄 Voir proposition' }, - type: 1 // URL button - }, - { - buttonId: 'btn2', - buttonText: { displayText: '🔧 Spécifications' }, - type: 1 // URL button - } - ] - }; - - await sock.sendMessage(`${phone}@s.whatsapp.net`, { - image: imageBuffer, - caption: caption, - footer: footer, - templateButtons: [ - { - index: 1, - urlButton: { - displayText: '📄 Voir proposition', - url: 'https://merlo-ch.com/uploads/proposition/f_p_250505_0000136_00008_EB00001909.pdf' - } - }, - { - index: 2, - urlButton: { - displayText: '🔧 Spécifications', - url: 'https://merlo-ch.com/uploads/proposition/d_p_250505_0000136_00008_EB00001909.pdf' - } - } - ] - }); - - return res.json({ success: true }); + + res.json({ success: true }); } catch (e) { - console.error('❌ Erreur /sendInteractiveImage :', e); - return res.status(500).json({ error: e.message }); + console.error('❌ Erreur image interactive:', e); + res.status(500).json({ error: e.message }); } }); -// app.post('/sendInteractiveImage', async (req, res) => { -// const { phone, caption, title, subtitle, footer } = req.body; -// if (!sock || !isConnected) return res.status(400).json({ error: 'Non connecté' }); - -// try { -// const imagePath = path.join(__dirname, 'public', 'logo-merlo-cs-FR.jpg'); -// const resizedBuffer = fs.readFileSync(imagePath); - -// await sock.sendMessage(`${phone}@s.whatsapp.net`, { -// image: resizedBuffer, -// caption: caption || 'Description par défaut', -// title: title || 'Titre par défaut', -// subtitle: subtitle || 'Sous-titre', -// footer: footer || 'Pied de page', -// media: true, -// interactiveButtons: [ -// { -// name: 'cta_url', -// buttonParamsJson: JSON.stringify({ -// display_text: 'Proposition', -// url: 'https://merlo-ch.com/uploads/proposition/f_p_250505_0000136_00008_EB00001909.pdf' -// }) -// }, -// { -// name: 'cta_url', -// buttonParamsJson: JSON.stringify({ -// display_text: 'Spec machine', -// url: 'https://merlo-ch.com/uploads/proposition/d_p_250505_0000136_00008_EB00001909.pdf' -// }) -// } -// ] -// }); -// res.json({ success: true }); -// } catch (e) { -// console.error('❌ Erreur interactive image :', e); -// res.status(500).json({ error: e.message }); -// } -// }); app.post('/sendProductMessage', async (req, res) => { - // On vérifie sock et isConnected, pas client - if (!sock || !isConnected) { - return res.status(400).json({ error: 'Non connecté à WhatsApp' }); - } + if (!client || !isConnected) return res.status(400).json({ error: 'Non connecté' }); const { phone, productImageUrl, - productImageCount, productTitle, productDescription, - priceAmount1000, - currencyCode, - retailerId, - productUrl, - businessOwnerJid, - caption, - messageTitle, - footer, - interactiveButtons = [], - quoted + price, + productUrl } = req.body; try { - const jid = `${phone}@s.whatsapp.net`; + // Venom-bot n'a pas de méthode native pour les produits + // On simule avec une image et des boutons + const buttons = [ + { buttonId: 'buy', buttonText: { displayText: '🛒 Acheter' }, type: 1 }, + { buttonId: 'details', buttonText: { displayText: 'ℹ️ Détails' }, type: 1 } + ]; - // Build product payload exactly comme avant - const productPayload = { - productImage: { url: productImageUrl }, - productImageCount, - title: productTitle, // ici productTitle - description: productDescription, - priceAmount1000: priceAmount1000 * 1000, // ajustez si besoin - currencyCode, - retailerId, - url: productUrl - }; + const caption = `*${productTitle}*\n\n${productDescription}\n\nPrix: ${price}`; - // Transformer les boutons - const buttons = interactiveButtons.map(btn => { - const params = {}; - if (btn.id) params.id = btn.id; - if (btn.url) params.url = btn.url; - if (btn.display_text) params.display_text = btn.display_text; - return { - name: btn.name, - buttonParamsJson: JSON.stringify(params) - }; - }); - - // **On utilise sock.sendMessage** et non client.sendMessage - await sock.sendMessage( - jid, - { - product: productPayload, - businessOwnerJid, - caption, - title: messageTitle, - footer, - media: true, - interactiveButtons: buttons - }, - quoted ? { quoted } : {} + await client.sendImage( + `${phone}@c.us`, + productImageUrl, + 'product.jpg', + caption, + { buttons } ); - - return res.json({ success: true }); + + res.json({ success: true }); } catch (e) { - console.error('❌ Erreur /sendProductMessage :', e); - return res.status(500).json({ error: e.message }); + console.error('❌ Erreur produit:', e); + res.status(500).json({ error: e.message }); } }); - -// 5) 404 et gestion des erreurs +// Gestion des erreurs app.use((req, res) => res.status(404).json({ error: 'Ressource introuvable' })); app.use((err, req, res, next) => { - console.error('Middleware d’erreur :', err); + console.error('Erreur:', err); res.status(500).json({ error: err.message }); }); -app.listen(3001, () => console.log('🚀 Serveur Baileys démarré sur http://localhost:3001')); + +app.listen(3001, () => console.log('🚀 Serveur Venom démarré sur http://localhost:3001')); \ No newline at end of file diff --git a/package.json b/package.json index 9a7c66b..dc1ab39 100644 --- a/package.json +++ b/package.json @@ -1,17 +1,53 @@ { - "name": "baileys-whatsapp-api", - "version": "1.0.0", - "description": "API WhatsApp avec Baileys Pro", - "main": "index.js", + "name": "whatsapp-api-venom", + "version": "2.0.0", + "description": "API WhatsApp avec Venom-bot - Solution complète de messagerie", + "main": "server.js", "scripts": { - "start": "node index.js" + "start": "node server.js", + "dev": "nodemon server.js", + "test": "jest --coverage", + "lint": "eslint .", + "format": "prettier --write .", + "postinstall": "node node_modules/venom-bot/install-chromium.js" }, "dependencies": { - "@fizzxydev/baileys-pro": "latest", - "@hapi/boom": "^10.0.1", - "axios": "^1.4.0", - "express": "^4.18.4", - "qrcode": "^1.5.1", - "sharp": "^0.33.0" + "venom-bot": "^4.3.7", + "express": "^4.18.2", + "express-rate-limit": "^6.8.1", + "helmet": "^7.1.0", + "morgan": "^1.10.0", + "qrcode": "^1.5.3", + "sharp": "^0.33.2", + "winston": "^3.11.0", + "axios": "^1.6.2" + }, + "devDependencies": { + "eslint": "^8.56.0", + "eslint-config-prettier": "^9.1.0", + "jest": "^29.7.0", + "nodemon": "^3.0.2", + "prettier": "^3.1.1", + "supertest": "^6.3.3" + }, + "engines": { + "node": ">=16.0.0", + "npm": ">=8.0.0" + }, + "keywords": [ + "whatsapp", + "api", + "venom", + "bot", + "messaging", + "automation" + ], + "repository": { + "type": "git", + "url": "https://github.com/votre-utilisateur/whatsapp-api-venom.git" + }, + "license": "MIT", + "bugs": { + "url": "https://github.com/votre-utilisateur/whatsapp-api-venom/issues" } -} +} \ No newline at end of file