n8n-nodes-wuzapi
Version:
n8n community nodes for Wuzapi - WhatsApp Multi-Device REST API
1,066 lines (1,065 loc) • 52 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.WuzapiTrigger = void 0;
class WuzapiTrigger {
constructor() {
this.description = {
displayName: 'Wuzapi Trigger',
name: 'wuzapiTrigger',
icon: 'file:wuzapi.svg',
group: ['trigger'],
version: 1,
subtitle: '={{$parameter["events"].join(", ")}}',
description: 'Receive WhatsApp events from Wuzapi with complete event mapping',
defaults: {
name: 'Wuzapi Trigger',
},
inputs: [],
outputs: ["main" /* NodeConnectionType.Main */],
credentials: [
{
name: 'wuzapiApi',
required: false,
},
],
webhooks: [
{
name: 'default',
httpMethod: 'POST',
responseMode: 'onReceived',
path: 'wuzapi',
},
],
properties: [
{
displayName: 'Events',
name: 'events',
type: 'multiOptions',
default: ['Message'],
options: [
{
name: 'All',
value: 'All',
description: 'Subscribe to all event types',
},
{
name: 'App State',
value: 'AppState',
description: 'Application state changes',
},
{
name: 'App State Sync Complete',
value: 'AppStateSyncComplete',
description: 'App state synchronization completed',
},
{
name: 'Blocklist',
value: 'Blocklist',
description: 'Full blocklist updates',
},
{
name: 'Blocklist Change',
value: 'BlocklistChange',
description: 'Contact block/unblock events',
},
{
name: 'Call Accept',
value: 'CallAccept',
description: 'Call accepted events',
},
{
name: 'Call Offer',
value: 'CallOffer',
description: 'Incoming call notifications',
},
{
name: 'Call Offer Notice',
value: 'CallOfferNotice',
description: 'Call offer notifications',
},
{
name: 'Call Relay Latency',
value: 'CallRelayLatency',
description: 'Call connection latency updates',
},
{
name: 'Call Terminate',
value: 'CallTerminate',
description: 'Call ended events',
},
{
name: 'CAT Refresh Error',
value: 'CATRefreshError',
description: 'Crypto auth token refresh errors',
},
{
name: 'Chat Presence',
value: 'ChatPresence',
description: 'Typing indicators and chat presence',
},
{
name: 'Client Outdated',
value: 'ClientOutdated',
description: 'WhatsApp client version outdated',
},
{
name: 'Connect Failure',
value: 'ConnectFailure',
description: 'Connection attempt failed',
},
{
name: 'Connected',
value: 'Connected',
description: 'WhatsApp connection established',
},
{
name: 'Disconnected',
value: 'Disconnected',
description: 'WhatsApp connection lost',
},
{
name: 'FB Ads Conversion',
value: 'FBAdsConversion',
description: 'Facebook Ads conversion events',
},
{
name: 'FB Message',
value: 'FBMessage',
description: 'Facebook bridge messages',
},
{
name: 'Group Info',
value: 'GroupInfo',
description: 'Group information updates',
},
{
name: 'History Sync',
value: 'HistorySync',
description: 'Message history synchronization',
},
{
name: 'Identity Change',
value: 'IdentityChange',
description: 'Contact security identity changes',
},
{
name: 'Joined Group',
value: 'JoinedGroup',
description: 'Group join notifications',
},
{
name: 'Keep Alive Restored',
value: 'KeepAliveRestored',
description: 'Connection keep-alive restored',
},
{
name: 'Keep Alive Timeout',
value: 'KeepAliveTimeout',
description: 'Connection keep-alive timeout',
},
{
name: 'Logged Out',
value: 'LoggedOut',
description: 'User logged out event',
},
{
name: 'Media Retry',
value: 'MediaRetry',
description: 'Media download retry events',
},
{
name: 'Message',
value: 'Message',
description: 'Incoming messages',
},
{
name: 'Newsletter Join',
value: 'NewsletterJoin',
description: 'Channel join notifications',
},
{
name: 'Newsletter Leave',
value: 'NewsletterLeave',
description: 'Channel leave notifications',
},
{
name: 'Newsletter Live Update',
value: 'NewsletterLiveUpdate',
description: 'Live updates from channels',
},
{
name: 'Newsletter Mute Change',
value: 'NewsletterMuteChange',
description: 'Channel mute status changes',
},
{
name: 'Offline Sync Completed',
value: 'OfflineSyncCompleted',
description: 'Offline message sync completed',
},
{
name: 'Offline Sync Preview',
value: 'OfflineSyncPreview',
description: 'Preview of offline messages to sync',
},
{
name: 'Pair Error',
value: 'PairError',
description: 'Device pairing failed',
},
{
name: 'Pair Success',
value: 'PairSuccess',
description: 'Device pairing successful',
},
{
name: 'Picture',
value: 'Picture',
description: 'Profile picture updates',
},
{
name: 'Presence',
value: 'Presence',
description: 'User online/offline status',
},
{
name: 'Privacy Settings',
value: 'PrivacySettings',
description: 'Privacy settings updates',
},
{
name: 'Push Name Setting',
value: 'PushNameSetting',
description: 'Push notification name changes',
},
{
name: 'QR',
value: 'QR',
description: 'QR code generated for pairing',
},
{
name: 'QR Scanned Without Multidevice',
value: 'QRScannedWithoutMultidevice',
description: 'QR code scanned without multidevice support',
},
{
name: 'Read Receipt',
value: 'ReadReceipt',
description: 'Message read confirmations',
},
{
name: 'Receipt',
value: 'Receipt',
description: 'Message delivery receipts',
},
{
name: 'Stream Error',
value: 'StreamError',
description: 'Connection stream error',
},
{
name: 'Stream Replaced',
value: 'StreamReplaced',
description: 'Connection stream replaced',
},
{
name: 'Temporary Ban',
value: 'TemporaryBan',
description: 'Account temporarily banned',
},
{
name: 'Undecryptable Message',
value: 'UndecryptableMessage',
description: 'Messages that could not be decrypted',
},
{
name: 'User About',
value: 'UserAbout',
description: 'User status/about updates',
},
],
description: 'Events to listen for',
},
{
displayName: 'Filters',
name: 'filters',
type: 'collection',
placeholder: 'Add Filter',
default: {},
options: [
{
displayName: 'From Phone (Sender)',
name: 'fromPhone',
type: 'string',
default: '',
placeholder: 'e.g. 5521971532700@s.whatsapp.net',
description: 'Only process messages from this phone number (full JID format)',
},
{
displayName: 'Chat ID',
name: 'chatId',
type: 'string',
default: '',
placeholder: 'e.g. 120363312246943103@g.us or 5521971532700@s.whatsapp.net',
description: 'Only process messages from this specific chat (group or direct)',
},
{
displayName: 'Message Type',
name: 'messageType',
type: 'options',
default: '',
options: [
{
name: 'All Types',
value: '',
},
{
name: 'Text',
value: 'text',
},
{
name: 'URL/Link Preview',
value: 'url',
},
{
name: 'Facebook Ads',
value: 'ads',
},
{
name: 'Audio',
value: 'audio',
},
{
name: 'Voice Note (PTT)',
value: 'ptt',
},
{
name: 'Image',
value: 'image',
},
{
name: 'Video',
value: 'video',
},
{
name: 'Document',
value: 'document',
},
{
name: 'Sticker',
value: 'sticker',
},
{
name: 'Location',
value: 'location',
},
{
name: 'Contact',
value: 'contact',
},
{
name: 'Contacts Array',
value: 'contacts',
},
{
name: 'Buttons',
value: 'buttons',
},
{
name: 'List',
value: 'list',
},
{
name: 'Template',
value: 'template',
},
{
name: 'Interactive Response',
value: 'interactiveResponse',
},
{
name: 'Interactive',
value: 'interactive',
},
{
name: 'Poll',
value: 'poll',
},
{
name: 'Event',
value: 'event',
},
{
name: 'Product',
value: 'product',
},
{
name: 'Order',
value: 'order',
},
{
name: 'Unknown/Other',
value: 'unknown',
},
],
description: 'Only process specific message types based on content',
},
{
displayName: 'Contains Text',
name: 'containsText',
type: 'string',
default: '',
placeholder: 'e.g. hello',
description: 'Only process messages containing this text (case insensitive)',
},
{
displayName: 'Is Group',
name: 'isGroup',
type: 'options',
default: 'any',
options: [
{
name: 'Any',
value: 'any',
description: 'Process all messages',
},
{
name: 'Groups Only',
value: 'true',
description: 'Only process group messages',
},
{
name: 'Direct Only',
value: 'false',
description: 'Only process direct messages',
},
],
description: 'Filter by message source (based on IsGroup field)',
},
{
displayName: 'Is From Me',
name: 'isFromMe',
type: 'options',
default: 'any',
options: [
{
name: 'Any',
value: 'any',
description: 'Process all messages',
},
{
name: 'From Me Only',
value: 'true',
description: 'Only process messages I sent',
},
{
name: 'From Others Only',
value: 'false',
description: 'Only process messages from others',
},
],
description: 'Filter by message sender (based on IsFromMe field)',
},
{
displayName: 'Token Filter',
name: 'tokenFilter',
type: 'string',
typeOptions: {
password: true,
},
default: '',
placeholder: 'e.g. setupautomatizado',
description: 'Only process events from this specific token',
},
],
},
{
displayName: 'Options',
name: 'options',
type: 'collection',
placeholder: 'Add Option',
default: {},
options: [
{
displayName: 'Include Raw Data',
name: 'includeRawData',
type: 'boolean',
default: false,
description: 'Whether to include the complete raw webhook data for debugging',
},
{
displayName: 'Simplify Output',
name: 'simplifyOutput',
type: 'boolean',
default: true,
description: 'Whether to simplify the output structure for easier use',
},
{
displayName: 'Include Media Data',
name: 'includeMediaData',
type: 'boolean',
default: true,
description: 'Whether to include base64 and S3 media data in the output',
},
{
displayName: 'Parse Message Content',
name: 'parseMessageContent',
type: 'boolean',
default: true,
description: 'Whether to parse and extract message content from complex message types',
},
{
displayName: 'Allow Unknown Events',
name: 'allowUnknownEvents',
type: 'boolean',
default: false,
description: 'Whether to process unknown event types not listed in the Events selection. Useful for new event types like custom integrations, ads conversions, or other events that may be added in the future.',
},
],
},
],
};
}
static extractMessageContent(message, options) {
const content = {};
if (!options.parseMessageContent) {
return content;
}
// Text message
if (message.conversation) {
content.messageType = 'text';
content.text = message.conversation;
}
// Extended text message (URLs, links, ads)
else if (message.extendedTextMessage) {
const extMsg = message.extendedTextMessage;
// Check if this is a Facebook Ads conversion
if (extMsg.contextInfo?.conversionSource === 'FB_Ads') {
content.messageType = 'ads';
content.text = extMsg.text;
content.conversionSource = extMsg.contextInfo.conversionSource;
content.conversionData = extMsg.contextInfo.conversionData;
// Extract external ad reply info if present
if (extMsg.contextInfo.externalAdReply) {
content.adInfo = {
title: extMsg.contextInfo.externalAdReply.title,
body: extMsg.contextInfo.externalAdReply.body,
mediaType: extMsg.contextInfo.externalAdReply.mediaType,
thumbnailUrl: extMsg.contextInfo.externalAdReply.thumbnailUrl,
mediaUrl: extMsg.contextInfo.externalAdReply.mediaUrl,
sourceUrl: extMsg.contextInfo.externalAdReply.sourceUrl,
sourceType: extMsg.contextInfo.externalAdReply.sourceType,
sourceId: extMsg.contextInfo.externalAdReply.sourceId
};
}
}
else {
// Regular URL/link message
content.messageType = 'url';
content.text = extMsg.text;
if (extMsg.title)
content.linkTitle = extMsg.title;
if (extMsg.description)
content.linkDescription = extMsg.description;
if (extMsg.matchedText)
content.linkUrl = extMsg.matchedText;
if (extMsg.JPEGThumbnail)
content.linkThumbnail = extMsg.JPEGThumbnail;
}
// Always include contextInfo if present for debugging
if (extMsg.contextInfo) {
content.contextInfo = extMsg.contextInfo;
}
}
// Audio message (voice note)
else if (message.audioMessage) {
content.messageType = message.audioMessage.PTT ? 'ptt' : 'audio';
content.audioUrl = message.audioMessage.URL;
content.duration = message.audioMessage.seconds;
content.mimeType = message.audioMessage.mimetype;
}
// Image message
else if (message.imageMessage) {
content.messageType = 'image';
if (message.imageMessage.caption)
content.caption = message.imageMessage.caption;
if (message.imageMessage.URL)
content.imageUrl = message.imageMessage.URL;
if (message.imageMessage.mimetype)
content.mimeType = message.imageMessage.mimetype;
if (message.imageMessage.JPEGThumbnail)
content.thumbnail = message.imageMessage.JPEGThumbnail;
}
// Video message
else if (message.videoMessage) {
content.messageType = 'video';
if (message.videoMessage.caption)
content.caption = message.videoMessage.caption;
if (message.videoMessage.URL)
content.videoUrl = message.videoMessage.URL;
if (message.videoMessage.mimetype)
content.mimeType = message.videoMessage.mimetype;
if (message.videoMessage.seconds)
content.duration = message.videoMessage.seconds;
if (message.videoMessage.JPEGThumbnail)
content.thumbnail = message.videoMessage.JPEGThumbnail;
}
// Document message
else if (message.documentMessage) {
content.messageType = 'document';
if (message.documentMessage.fileName)
content.fileName = message.documentMessage.fileName;
if (message.documentMessage.mimetype)
content.mimeType = message.documentMessage.mimetype;
if (message.documentMessage.URL)
content.documentUrl = message.documentMessage.URL;
if (message.documentMessage.title)
content.title = message.documentMessage.title;
}
// Sticker message
else if (message.stickerMessage) {
content.messageType = 'sticker';
if (message.stickerMessage.URL)
content.stickerUrl = message.stickerMessage.URL;
if (message.stickerMessage.mimetype)
content.mimeType = message.stickerMessage.mimetype;
}
// Location message
else if (message.locationMessage) {
content.messageType = 'location';
content.latitude = message.locationMessage.degreesLatitude;
content.longitude = message.locationMessage.degreesLongitude;
if (message.locationMessage.name)
content.locationName = message.locationMessage.name;
if (message.locationMessage.address)
content.locationAddress = message.locationMessage.address;
if (message.locationMessage.JPEGThumbnail)
content.thumbnail = message.locationMessage.JPEGThumbnail;
}
// Contact message
else if (message.contactMessage) {
content.messageType = 'contact';
content.contactName = message.contactMessage.displayName;
content.vcard = message.contactMessage.vcard;
}
// Contacts array message
else if (message.contactsArrayMessage) {
content.messageType = 'contacts';
content.contactName = message.contactsArrayMessage.displayName;
content.contacts = message.contactsArrayMessage.contacts;
}
// Buttons message
else if (message.buttonsMessage) {
content.messageType = 'buttons';
content.text = message.buttonsMessage.contentText;
content.headerText = message.buttonsMessage.headerText;
content.footerText = message.buttonsMessage.footerText;
content.buttons = message.buttonsMessage.buttons?.map((btn) => ({
id: btn.buttonID,
text: btn.buttonText?.displayText,
type: btn.type
}));
}
// List message
else if (message.listMessage) {
content.messageType = 'list';
content.title = message.listMessage.title;
content.text = message.listMessage.description;
content.buttonText = message.listMessage.buttonText;
content.footerText = message.listMessage.footerText;
content.sections = message.listMessage.sections?.map((section) => ({
title: section.title,
rows: section.rows?.map((row) => ({
id: row.rowID,
title: row.title,
description: row.description
}))
}));
}
// Template message
else if (message.templateMessage) {
content.messageType = 'template';
content.templateContent = message.templateMessage;
}
// Interactive response message
else if (message.interactiveResponseMessage) {
content.messageType = 'interactiveResponse';
content.responseType = message.interactiveResponseMessage.body?.text;
content.responseData = message.interactiveResponseMessage;
}
// Interactive message (new type from examples)
else if (message.interactiveMessage) {
content.messageType = 'interactive';
content.interactiveData = message.interactiveMessage;
// Extract payment info if present
if (message.interactiveMessage.InteractiveMessage?.NativeFlowMessage?.buttons) {
const paymentButton = message.interactiveMessage.InteractiveMessage.NativeFlowMessage.buttons.find((btn) => btn.name === 'payment_info');
if (paymentButton?.buttonParamsJSON) {
try {
content.paymentInfo = JSON.parse(paymentButton.buttonParamsJSON);
}
catch (e) {
content.paymentInfoRaw = paymentButton.buttonParamsJSON;
}
}
}
}
// Poll message (all versions)
else if (message.pollCreationMessage || message.pollCreationMessageV2 || message.pollCreationMessageV3) {
content.messageType = 'poll';
const pollData = message.pollCreationMessage || message.pollCreationMessageV2 || message.pollCreationMessageV3;
content.pollName = pollData.name;
content.options = pollData.options?.map((opt) => opt.optionName || opt);
content.selectableCount = pollData.selectableOptionsCount;
content.pollData = pollData;
}
// Event message (new type from examples)
else if (message.eventMessage) {
content.messageType = 'event';
content.eventName = message.eventMessage.name;
content.eventDescription = message.eventMessage.description;
content.startTime = message.eventMessage.startTime;
content.endTime = message.eventMessage.endTime;
content.isCanceled = message.eventMessage.isCanceled;
content.extraGuestsAllowed = message.eventMessage.extraGuestsAllowed;
if (message.eventMessage.joinLink)
content.joinLink = message.eventMessage.joinLink;
if (message.eventMessage.location) {
content.eventLocation = {
name: message.eventMessage.location.name,
latitude: message.eventMessage.location.degreesLatitude,
longitude: message.eventMessage.location.degreesLongitude
};
}
}
// Product message (new type from examples)
else if (message.productMessage) {
content.messageType = 'product';
content.businessOwner = message.productMessage.businessOwnerJID;
if (message.productMessage.product) {
const product = message.productMessage.product;
content.productId = product.productID;
content.productTitle = product.title;
content.productDescription = product.description;
content.currency = product.currencyCode;
content.price = product.priceAmount1000 / 1000; // Convert from 1000-based
content.retailerId = product.retailerID;
content.productUrl = product.URL;
if (product.signedURL)
content.signedUrl = product.signedURL;
if (product.productImage) {
content.productImage = {
url: product.productImage.URL,
thumbnail: product.productImage.JPEGThumbnail
};
}
}
}
// Order message
else if (message.orderMessage) {
content.messageType = 'order';
content.orderId = message.orderMessage.orderID || message.orderMessage.orderId;
content.orderStatus = message.orderMessage.orderStatus || message.orderMessage.status;
content.orderData = message.orderMessage;
}
// For any other message type not handled above
else {
// Try to detect message type from available fields
const messageKeys = Object.keys(message);
if (messageKeys.length > 0) {
// Use the first key that ends with "Message" as the type
const messageTypeKey = messageKeys.find(key => key.endsWith('Message'));
if (messageTypeKey) {
content.messageType = messageTypeKey.replace('Message', '');
content.messageData = message[messageTypeKey];
}
else {
// If no standard message type found, mark as unknown but include data
content.messageType = 'unknown';
content.messageData = message;
}
}
}
// Always include message context info if present
if (message.messageContextInfo) {
content.contextInfo = message.messageContextInfo;
}
return content;
}
async webhook() {
const bodyData = this.getBodyData();
const events = this.getNodeParameter('events');
const filters = this.getNodeParameter('filters');
const options = this.getNodeParameter('options');
// Check if the event type matches
const eventType = String(bodyData.type || '');
const allowUnknown = options.allowUnknownEvents;
// Process event if:
// 1. Event type is in selected events list
// 2. "All" is selected in events
// 3. allowUnknownEvents is true
if (!events.includes(eventType) && !events.includes('All') && !allowUnknown) {
return {
workflowData: [],
};
}
// Apply token filter first
if (filters.tokenFilter && bodyData.token !== filters.tokenFilter) {
return { workflowData: [] };
}
// Get event info for message events
const eventInfo = bodyData.event?.Info;
// Apply filters for Message events
if (eventType === 'Message' && eventInfo) {
// Phone number filter (Sender)
if (filters.fromPhone && eventInfo.Sender !== filters.fromPhone) {
return { workflowData: [] };
}
// Chat filter
if (filters.chatId && eventInfo.Chat !== filters.chatId) {
return { workflowData: [] };
}
// Message type filter
if (filters.messageType) {
// First check MediaType field
const mediaType = eventInfo.MediaType || eventInfo.Type || '';
// For complex message types, we need to check the actual message content
const message = bodyData.event?.Message;
let actualMessageType = mediaType;
// Detect actual message type from content
if (message) {
if (message.conversation)
actualMessageType = 'text';
else if (message.extendedTextMessage) {
// Check if it's a Facebook Ads conversion
if (message.extendedTextMessage.contextInfo?.conversionSource === 'FB_Ads') {
actualMessageType = 'ads';
}
else {
actualMessageType = 'url';
}
}
else if (message.audioMessage?.PTT)
actualMessageType = 'ptt';
else if (message.audioMessage)
actualMessageType = 'audio';
else if (message.imageMessage)
actualMessageType = 'image';
else if (message.videoMessage)
actualMessageType = 'video';
else if (message.documentMessage)
actualMessageType = 'document';
else if (message.stickerMessage)
actualMessageType = 'sticker';
else if (message.locationMessage)
actualMessageType = 'location';
else if (message.contactMessage)
actualMessageType = 'contact';
else if (message.contactsArrayMessage)
actualMessageType = 'contacts';
else if (message.buttonsMessage)
actualMessageType = 'buttons';
else if (message.listMessage)
actualMessageType = 'list';
else if (message.templateMessage)
actualMessageType = 'template';
else if (message.interactiveResponseMessage)
actualMessageType = 'interactiveResponse';
else if (message.interactiveMessage)
actualMessageType = 'interactive';
else if (message.pollCreationMessage || message.pollCreationMessageV2 || message.pollCreationMessageV3)
actualMessageType = 'poll';
else if (message.eventMessage)
actualMessageType = 'event';
else if (message.productMessage)
actualMessageType = 'product';
else if (message.orderMessage)
actualMessageType = 'order';
else if (mediaType === 'location')
actualMessageType = 'location';
else if (mediaType === 'product')
actualMessageType = 'product';
}
if (filters.messageType !== actualMessageType) {
return { workflowData: [] };
}
}
// Text content filter
if (filters.containsText) {
const message = bodyData.event?.Message;
let textContent = '';
// Extract text from different message types
if (message?.conversation) {
textContent = message.conversation;
}
else if (message?.extendedTextMessage?.text) {
textContent = message.extendedTextMessage.text;
}
else if (message?.buttonsMessage?.contentText) {
textContent = message.buttonsMessage.contentText;
}
else if (message?.listMessage) {
textContent = `${message.listMessage.title || ''} ${message.listMessage.description || ''}`;
}
else if (message?.templateMessage?.hydratedTemplate?.hydratedContentText) {
textContent = message.templateMessage.hydratedTemplate.hydratedContentText;
}
if (!textContent.toLowerCase().includes(String(filters.containsText).toLowerCase())) {
return { workflowData: [] };
}
}
// Group/Direct filter
if (filters.isGroup !== 'any') {
const isGroup = eventInfo.IsGroup;
if (filters.isGroup === 'true' && !isGroup) {
return { workflowData: [] };
}
if (filters.isGroup === 'false' && isGroup) {
return { workflowData: [] };
}
}
// From me filter
if (filters.isFromMe !== 'any') {
const isFromMe = eventInfo.IsFromMe;
if (filters.isFromMe === 'true' && !isFromMe) {
return { workflowData: [] };
}
if (filters.isFromMe === 'false' && isFromMe) {
return { workflowData: [] };
}
}
}
// Process the data
let outputData = {};
if (options.simplifyOutput) {
// Create simplified output structure
outputData = {
eventType: eventType,
token: bodyData.token,
timestamp: new Date().toISOString(),
};
// Handle Message events
if (eventType === 'Message' && eventInfo) {
outputData.messageId = eventInfo.ID;
outputData.chat = eventInfo.Chat;
outputData.sender = eventInfo.Sender;
outputData.timestamp = eventInfo.Timestamp;
outputData.messageType = eventInfo.Type;
outputData.mediaType = eventInfo.MediaType;
outputData.isFromMe = eventInfo.IsFromMe;
outputData.isGroup = eventInfo.IsGroup;
outputData.pushName = eventInfo.PushName;
if (eventInfo.VerifiedName) {
outputData.verifiedName = eventInfo.VerifiedName.Details?.verifiedName;
}
// Extract message content
const messageContent = WuzapiTrigger.extractMessageContent(bodyData.event?.Message, options);
Object.assign(outputData, messageContent);
// Special handling for Facebook Ads conversions
if (messageContent.messageType === 'ads') {
outputData.isAdsConversion = true;
outputData.adsSource = messageContent.conversionSource;
// Try to parse conversion data if it's JSON
if (messageContent.conversionData) {
try {
outputData.adsConversionData = JSON.parse(String(messageContent.conversionData));
}
catch (e) {
outputData.adsConversionDataRaw = messageContent.conversionData;
}
}
}
// Include media data if present and requested
if (options.includeMediaData) {
if (bodyData.base64)
outputData.mediaBase64 = bodyData.base64;
if (bodyData.mimeType)
outputData.mediaMimeType = bodyData.mimeType;
if (bodyData.fileName)
outputData.mediaFileName = bodyData.fileName;
if (bodyData.s3)
outputData.s3Data = bodyData.s3;
}
}
// Handle Facebook Ads Conversion events
else if (eventType === 'FBAdsConversion') {
const adsEvent = bodyData.event;
outputData.conversionSource = adsEvent?.conversionSource;
outputData.conversionData = adsEvent?.conversionData;
outputData.chat = adsEvent?.Chat;
outputData.sender = adsEvent?.Sender;
outputData.timestamp = adsEvent?.Timestamp;
// Try to parse conversion data
if (adsEvent?.conversionData) {
try {
outputData.parsedConversionData = JSON.parse(adsEvent.conversionData);
}
catch (e) {
outputData.rawConversionData = adsEvent.conversionData;
}
}
}
// Handle ReadReceipt events
else if (eventType === 'ReadReceipt') {
const receiptEvent = bodyData.event;
outputData.state = bodyData.state;
outputData.chat = receiptEvent?.Chat;
outputData.sender = receiptEvent?.Sender;
outputData.timestamp = receiptEvent?.Timestamp;
outputData.messageIds = receiptEvent?.MessageIDs;
outputData.messageSender = receiptEvent?.MessageSender;
}
// Handle ChatPresence events
else if (eventType === 'ChatPresence') {
const presenceEvent = bodyData.event;
outputData.chat = presenceEvent?.Chat;
outputData.sender = presenceEvent?.Sender;
outputData.state = presenceEvent?.State;
outputData.media = presenceEvent?.Media;
}
// Handle Presence events
else if (eventType === 'Presence') {
const presenceEvent = bodyData.event;
outputData.from = presenceEvent?.From;
outputData.unavailable = presenceEvent?.Unavailable;
outputData.lastSeen = presenceEvent?.LastSeen;
}
// Handle Order events
else if (eventType === 'Order') {
const orderEvent = bodyData.event;
outputData.orderId = orderEvent?.ID;
outputData.orderStatus = orderEvent?.Status;
outputData.orderDetails = orderEvent;
}
// Handle Interaction events
else if (eventType === 'Interaction') {
const interactionEvent = bodyData.event;
outputData.interactionType = interactionEvent?.Type;
outputData.interactionData = interactionEvent;
}
// Handle Reaction events
else if (eventType === 'Reaction') {
const reactionEvent = bodyData.event;
outputData.reaction = reactionEvent?.Reaction;
outputData.messageId = reactionEvent?.MessageID;
outputData.reactionData = reactionEvent;
}
// Handle Call events
else if (eventType === 'Call') {
const callEvent = bodyData.event;
outputData.callType = callEvent?.Type;
outputData.callStatus = callEvent?.Status;
outputData.callData = callEvent;
}
// Handle unknown/other event types
else {
// For unknown events, include all available data
outputData.unknownEventType = eventType;
outputData.isUnknownEvent = true;
// Copy event data directly for other types
if (bodyData.event) {
outputData.eventData = bodyData.event;
// Try to extract common fields from unknown events
const event = bodyData.event;
if (event.Info) {
outputData.chat = event.Info.Chat;