export function parseEvolutionWebhook(reqBody) { const envelope = Array.isArray(reqBody) ? reqBody[0] : reqBody; const body = envelope?.body ?? envelope ?? {}; const event = body.event; const instance = body.instance; // tenant key const data = body.data; if (!event || !data || !data.key) { return { ok: false, reason: "missing_fields" }; } if (event !== "messages.upsert") { return { ok: false, reason: "not_messages_upsert" }; } const remoteJid = data.key.remoteJid; const fromMe = data.key.fromMe === true; const messageId = data.key.id; // only inbound if (fromMe) return { ok: false, reason: "from_me" }; // ignore groups / broadcasts if (!remoteJid || typeof remoteJid !== "string") return { ok: false, reason: "no_remoteJid" }; if (!remoteJid.endsWith("@s.whatsapp.net")) return { ok: false, reason: "not_direct_chat" }; const messageType = data.messageType; // extract text const msg = data.message || {}; const text = (typeof msg.conversation === "string" && msg.conversation) || (typeof msg.extendedTextMessage?.text === "string" && msg.extendedTextMessage.text) || ""; const cleanText = String(text).trim(); if (!cleanText) return { ok: false, reason: "empty_text" }; // metadata const pushName = data.pushName || null; const ts = data.messageTimestamp ? new Date(Number(data.messageTimestamp) * 1000).toISOString() : null; const source = data.source || null; // e.g. "sim" return { ok: true, tenant_key: instance || null, chat_id: remoteJid, message_id: messageId || null, text: cleanText, from_name: pushName, message_type: messageType || null, ts, source, raw: body, // para log/debug si querés }; }