UNPKG

n8n-nodes-wuzapi

Version:

n8n community nodes for Wuzapi - WhatsApp Multi-Device REST API

1,004 lines 44.2 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.WuzapiAI = void 0; const GenericFunctions_1 = require("../GenericFunctions"); class WuzapiAI { constructor() { this.description = { displayName: 'Wuzapi AI', name: 'wuzapiAi', icon: 'file:wuzapi.svg', group: ['transform'], version: 1, subtitle: '={{$parameter["operation"]}} message', description: 'Send WhatsApp messages using Wuzapi - optimized for AI workflows', defaults: { name: 'Wuzapi AI', }, usableAsTool: true, inputs: ["main" /* NodeConnectionType.Main */], outputs: ["main" /* NodeConnectionType.Main */], credentials: [ { name: 'wuzapiApi', required: true, }, ], properties: [ { displayName: 'Operation', name: 'operation', type: 'options', noDataExpression: true, options: [ { name: 'Send Text', value: 'sendText', description: 'Send a text message', action: 'Send a text message', }, { name: 'Send Image', value: 'sendImage', description: 'Send an image message', action: 'Send an image message', }, { name: 'Send Document', value: 'sendDocument', description: 'Send a document message', action: 'Send a document message', }, { name: 'Send Audio', value: 'sendAudio', description: 'Send an audio message', action: 'Send an audio message', }, { name: 'Send Video', value: 'sendVideo', description: 'Send a video message', action: 'Send a video message', }, { name: 'Send Location', value: 'sendLocation', description: 'Send a location message', action: 'Send a location message', }, { name: 'Send Contact', value: 'sendContact', description: 'Send a contact message', action: 'Send a contact message', }, { name: 'Send Sticker', value: 'sendSticker', description: 'Send a sticker', action: 'Send a sticker message', }, { name: 'Send Buttons', value: 'sendButtons', description: 'Send a message with buttons', action: 'Send buttons message', }, { name: 'Send List', value: 'sendList', description: 'Send a list message', action: 'Send list message', }, { name: 'Send Poll', value: 'sendPoll', description: 'Send a poll', action: 'Send poll message', }, ], default: 'sendText', }, // Phone Number { displayName: 'Phone Number', name: 'phoneNumber', type: 'string', default: '', placeholder: '5491155553934', description: 'Phone number in international format (without +)', required: true, }, // Text Message { displayName: 'Message', name: 'message', type: 'string', displayOptions: { show: { operation: ['sendText', 'sendButtons'], }, }, default: '', description: 'The text message to send', required: true, }, // Image fields - complete implementation { displayName: 'Image Source', name: 'imageSource', type: 'options', default: 'url', options: [ { name: 'Binary Data', value: 'binary', description: 'Use binary data from previous node', }, { name: 'Base64', value: 'base64', description: 'Provide base64 encoded image', }, { name: 'URL', value: 'url', description: 'Provide URL to image file', }, ], displayOptions: { show: { operation: ['sendImage'], }, }, }, { displayName: 'Binary Property', name: 'imageBinaryProperty', type: 'string', default: 'data', description: 'Name of the binary property containing the image', displayOptions: { show: { operation: ['sendImage'], imageSource: ['binary'], }, }, }, { displayName: 'Base64 Image', name: 'imageBase64', type: 'string', default: '', placeholder: 'data:image/jpeg;base64,iVBORw0...', description: 'Base64 encoded image with data URL prefix', displayOptions: { show: { operation: ['sendImage'], imageSource: ['base64'], }, }, required: true, }, { displayName: 'Image URL', name: 'imageUrl', type: 'string', default: '', placeholder: 'https://example.com/image.jpg', description: 'URL to the image file', displayOptions: { show: { operation: ['sendImage'], imageSource: ['url'], }, }, required: true, }, // Video fields - complete implementation { displayName: 'Video Source', name: 'videoSource', type: 'options', default: 'url', options: [ { name: 'Binary Data', value: 'binary', description: 'Use binary data from previous node', }, { name: 'Base64', value: 'base64', description: 'Provide base64 encoded video', }, { name: 'URL', value: 'url', description: 'Provide URL to video file', }, ], displayOptions: { show: { operation: ['sendVideo'], }, }, }, { displayName: 'Binary Property', name: 'videoBinaryProperty', type: 'string', default: 'data', description: 'Name of the binary property containing the video', displayOptions: { show: { operation: ['sendVideo'], videoSource: ['binary'], }, }, }, { displayName: 'Base64 Video', name: 'videoBase64', type: 'string', default: '', placeholder: 'data:video/mp4;base64,iVBORw0...', description: 'Base64 encoded video (H.264 codec, AAC audio)', displayOptions: { show: { operation: ['sendVideo'], videoSource: ['base64'], }, }, required: true, }, { displayName: 'Video URL', name: 'videoUrl', type: 'string', default: '', placeholder: 'https://example.com/video.mp4', description: 'URL to the video file', displayOptions: { show: { operation: ['sendVideo'], videoSource: ['url'], }, }, required: true, }, // Document fields - complete implementation { displayName: 'Document Source', name: 'documentSource', type: 'options', default: 'url', options: [ { name: 'Binary Data', value: 'binary', description: 'Use binary data from previous node', }, { name: 'Base64', value: 'base64', description: 'Provide base64 encoded document', }, { name: 'URL', value: 'url', description: 'Provide URL to document file', }, ], displayOptions: { show: { operation: ['sendDocument'], }, }, }, { displayName: 'Binary Property', name: 'documentBinaryProperty', type: 'string', default: 'data', description: 'Name of the binary property containing the document', displayOptions: { show: { operation: ['sendDocument'], documentSource: ['binary'], }, }, }, { displayName: 'Base64 Document', name: 'documentBase64', type: 'string', default: '', placeholder: 'data:application/pdf;base64,iVBORw0...', description: 'Base64 encoded document', displayOptions: { show: { operation: ['sendDocument'], documentSource: ['base64'], }, }, required: true, }, { displayName: 'Document URL', name: 'documentUrl', type: 'string', default: '', placeholder: 'https://example.com/document.pdf', description: 'URL to the document file', displayOptions: { show: { operation: ['sendDocument'], documentSource: ['url'], }, }, required: true, }, { displayName: 'File Name', name: 'fileName', type: 'string', displayOptions: { show: { operation: ['sendDocument'], }, }, default: '', placeholder: 'document.pdf', description: 'Name of the document file', required: true, }, // Audio fields - complete implementation { displayName: 'Audio Source', name: 'audioSource', type: 'options', default: 'url', options: [ { name: 'Binary Data', value: 'binary', description: 'Use binary data from previous node', }, { name: 'Base64', value: 'base64', description: 'Provide base64 encoded audio', }, { name: 'URL', value: 'url', description: 'Provide URL to audio file', }, ], displayOptions: { show: { operation: ['sendAudio'], }, }, }, { displayName: 'Binary Property', name: 'audioBinaryProperty', type: 'string', default: 'data', description: 'Name of the binary property containing the audio', displayOptions: { show: { operation: ['sendAudio'], audioSource: ['binary'], }, }, }, { displayName: 'Base64 Audio', name: 'audioBase64', type: 'string', default: '', placeholder: 'data:audio/ogg;base64,iVBORw0...', description: 'Base64 encoded audio in opus format', displayOptions: { show: { operation: ['sendAudio'], audioSource: ['base64'], }, }, required: true, }, { displayName: 'Audio URL', name: 'audioUrl', type: 'string', default: '', placeholder: 'https://example.com/audio.ogg', description: 'URL to the audio file', displayOptions: { show: { operation: ['sendAudio'], audioSource: ['url'], }, }, required: true, }, { displayName: 'Voice Note (PTT)', name: 'ptt', type: 'boolean', default: true, description: 'Whether to send as voice note (PTT) or audio file', displayOptions: { show: { operation: ['sendAudio'], }, }, }, // Sticker fields - complete implementation { displayName: 'Sticker Source', name: 'stickerSource', type: 'options', default: 'url', options: [ { name: 'Binary Data', value: 'binary', description: 'Use binary data from previous node', }, { name: 'Base64', value: 'base64', description: 'Provide base64 encoded sticker', }, { name: 'URL', value: 'url', description: 'Provide URL to sticker file', }, ], displayOptions: { show: { operation: ['sendSticker'], }, }, }, { displayName: 'Binary Property', name: 'stickerBinaryProperty', type: 'string', default: 'data', description: 'Name of the binary property containing the sticker', displayOptions: { show: { operation: ['sendSticker'], stickerSource: ['binary'], }, }, }, { displayName: 'Base64 Sticker', name: 'stickerBase64', type: 'string', default: '', placeholder: 'data:image/webp;base64,iVBORw0...', description: 'Base64 encoded sticker in WebP format', displayOptions: { show: { operation: ['sendSticker'], stickerSource: ['base64'], }, }, required: true, }, { displayName: 'Sticker URL', name: 'stickerUrl', type: 'string', default: '', placeholder: 'https://example.com/sticker.webp', description: 'URL to the sticker file', displayOptions: { show: { operation: ['sendSticker'], stickerSource: ['url'], }, }, required: true, }, // Caption for media { displayName: 'Caption', name: 'caption', type: 'string', displayOptions: { show: { operation: ['sendImage', 'sendDocument', 'sendVideo'], }, }, default: '', description: 'Caption for the media file', }, // Location fields { displayName: 'Latitude', name: 'latitude', type: 'number', displayOptions: { show: { operation: ['sendLocation'], }, }, default: 0, description: 'Latitude coordinate', required: true, }, { displayName: 'Longitude', name: 'longitude', type: 'number', displayOptions: { show: { operation: ['sendLocation'], }, }, default: 0, description: 'Longitude coordinate', required: true, }, { displayName: 'Location Name', name: 'locationName', type: 'string', displayOptions: { show: { operation: ['sendLocation'], }, }, default: '', description: 'Name of the location', }, // Contact fields { displayName: 'Contact Name', name: 'contactName', type: 'string', displayOptions: { show: { operation: ['sendContact'], }, }, default: '', description: 'Name of the contact', required: true, }, { displayName: 'VCard', name: 'vcard', type: 'string', displayOptions: { show: { operation: ['sendContact'], }, }, default: '', placeholder: 'BEGIN:VCARD\nVERSION:3.0\nFN:John Doe\nTEL:+1234567890\nEND:VCARD', description: 'VCard data for the contact', required: true, }, // List fields { displayName: 'Button Text', name: 'buttonText', type: 'string', default: '', placeholder: 'Click here', description: 'Text for the list button', required: true, displayOptions: { show: { operation: ['sendList'], }, }, }, { displayName: 'Description', name: 'description', type: 'string', default: '', placeholder: 'Choose an option', description: 'Description of the list', required: true, displayOptions: { show: { operation: ['sendList'], }, }, }, { displayName: 'Top Text', name: 'topText', type: 'string', default: '', placeholder: 'Header text', description: 'Text to show above the list', required: true, displayOptions: { show: { operation: ['sendList'], }, }, }, { displayName: 'Footer Text', name: 'footerText', type: 'string', default: '', placeholder: 'Footer text', description: 'Text to show below the list', displayOptions: { show: { operation: ['sendList'], }, }, }, { displayName: 'List Items', name: 'listItems', type: 'fixedCollection', typeOptions: { multipleValues: true, }, default: {}, description: 'Items in the list', required: true, displayOptions: { show: { operation: ['sendList'], }, }, options: [ { name: 'item', displayName: 'Item', values: [ { displayName: 'Title', name: 'title', type: 'string', default: '', description: 'Title of the list item', required: true, }, { displayName: 'Description', name: 'desc', type: 'string', default: '', description: 'Description of the list item', }, { displayName: 'Row ID', name: 'rowId', type: 'string', default: '', description: 'Unique identifier for the row', required: true, }, ], }, ], }, // Poll fields { displayName: 'Poll Question', name: 'pollHeader', type: 'string', default: '', placeholder: "What's your favorite color?", required: true, displayOptions: { show: { operation: ['sendPoll'], }, }, }, { displayName: 'Poll Options', name: 'pollOptions', type: 'string', default: '', placeholder: 'Red,Blue,Green,Yellow', description: 'Comma-separated list of poll options', required: true, displayOptions: { show: { operation: ['sendPoll'], }, }, }, // Additional Options for all message types { displayName: 'Additional Options', name: 'additionalOptions', type: 'collection', placeholder: 'Add Option', default: {}, options: [ { displayName: 'Message ID', name: 'id', type: 'string', default: '', description: 'Custom message ID (auto-generated if not provided)', }, { displayName: 'Mentions', name: 'mentions', type: 'fixedCollection', default: {}, description: 'Mention specific users or all group members', options: [ { name: 'mentionConfig', displayName: 'Mention Configuration', values: [ { displayName: 'Mention Type', name: 'type', type: 'options', default: 'none', options: [ { name: 'None', value: 'none', description: 'No mentions', }, { name: 'Specific Users', value: 'specific', description: 'Mention specific users', }, { name: 'All Group Members', value: 'all', description: 'Mention all group members (groups only)', }, ], }, { displayName: 'User JIDs', name: 'jids', type: 'string', default: '', placeholder: 'e.g. 5491155553934@s.whatsapp.net,5491155553935@s.whatsapp.net', description: 'Comma-separated list of user JIDs to mention', displayOptions: { show: { type: ['specific'], }, }, }, ], }, ], }, ], }, ], }; } async execute() { const items = this.getInputData(); const returnData = []; for (let i = 0; i < items.length; i++) { try { const operation = this.getNodeParameter('operation', i); const phoneNumber = this.getNodeParameter('phoneNumber', i); const additionalOptions = this.getNodeParameter('additionalOptions', i); // Format phone number for WhatsApp const phone = phoneNumber.includes('@') ? phoneNumber : `${phoneNumber}@s.whatsapp.net`; let endpoint = ''; let body = { Phone: phone, }; // Add common fields if (additionalOptions.id) { body.Id = additionalOptions.id; } // Handle mentions if (additionalOptions.mentions && additionalOptions.mentions.mentionConfig) { const mentionConfig = additionalOptions.mentions.mentionConfig; if (Array.isArray(mentionConfig) && mentionConfig.length > 0) { const config = mentionConfig[0]; if (config.type === 'specific' && config.jids) { const jids = config.jids.split(',').map((jid) => jid.trim()); body.mention_info = { mentions: jids, }; } else if (config.type === 'all') { body.mention_info = { mention_all: true, }; } } } switch (operation) { case 'sendText': endpoint = '/chat/send/text'; body.Body = this.getNodeParameter('message', i); break; case 'sendImage': endpoint = '/chat/send/image'; const imageSource = this.getNodeParameter('imageSource', i); if (imageSource === 'binary') { const binaryProperty = this.getNodeParameter('imageBinaryProperty', i); const binaryData = items[i].binary?.[binaryProperty]; if (!binaryData) { throw new Error(`Binary property "${binaryProperty}" not found`); } const buffer = Buffer.from(binaryData.data, 'base64'); body.Image = (0, GenericFunctions_1.prepareMediaData)(buffer, binaryData.mimeType || 'image/jpeg'); } else if (imageSource === 'base64') { body.Image = this.getNodeParameter('imageBase64', i); } else if (imageSource === 'url') { body.Image = this.getNodeParameter('imageUrl', i); } const imageCaption = this.getNodeParameter('caption', i, ''); if (imageCaption) body.Caption = imageCaption; break; case 'sendDocument': endpoint = '/chat/send/document'; const documentSource = this.getNodeParameter('documentSource', i); if (documentSource === 'binary') { const binaryProperty = this.getNodeParameter('documentBinaryProperty', i); const binaryData = items[i].binary?.[binaryProperty]; if (!binaryData) { throw new Error(`Binary property "${binaryProperty}" not found`); } const buffer = Buffer.from(binaryData.data, 'base64'); body.Document = (0, GenericFunctions_1.prepareMediaData)(buffer, binaryData.mimeType || 'application/octet-stream'); } else if (documentSource === 'base64') { body.Document = this.getNodeParameter('documentBase64', i); } else if (documentSource === 'url') { body.Document = this.getNodeParameter('documentUrl', i); } body.FileName = this.getNodeParameter('fileName', i); const docCaption = this.getNodeParameter('caption', i, ''); if (docCaption) body.Caption = docCaption; break; case 'sendAudio': endpoint = '/chat/send/audio'; const audioSource = this.getNodeParameter('audioSource', i); const ptt = this.getNodeParameter('ptt', i); if (audioSource === 'binary') { const binaryProperty = this.getNodeParameter('audioBinaryProperty', i); const binaryData = items[i].binary?.[binaryProperty]; if (!binaryData) { throw new Error(`Binary property "${binaryProperty}" not found`); } const buffer = Buffer.from(binaryData.data, 'base64'); body.Audio = (0, GenericFunctions_1.prepareMediaData)(buffer, binaryData.mimeType || 'audio/ogg'); } else if (audioSource === 'base64') { body.Audio = this.getNodeParameter('audioBase64', i); } else if (audioSource === 'url') { body.Audio = this.getNodeParameter('audioUrl', i); } body.PTT = ptt; break; case 'sendVideo': endpoint = '/chat/send/video'; const videoSource = this.getNodeParameter('videoSource', i); if (videoSource === 'binary') { const binaryProperty = this.getNodeParameter('videoBinaryProperty', i); const binaryData = items[i].binary?.[binaryProperty]; if (!binaryData) { throw new Error(`Binary property "${binaryProperty}" not found`); } const buffer = Buffer.from(binaryData.data, 'base64'); body.Video = (0, GenericFunctions_1.prepareMediaData)(buffer, binaryData.mimeType || 'video/mp4'); } else if (videoSource === 'base64') { body.Video = this.getNodeParameter('videoBase64', i); } else if (videoSource === 'url') { body.Video = this.getNodeParameter('videoUrl', i); } const videoCaption = this.getNodeParameter('caption', i, ''); if (videoCaption) body.Caption = videoCaption; break; case 'sendLocation': endpoint = '/chat/send/location'; body.Latitude = this.getNodeParameter('latitude', i); body.Longitude = this.getNodeParameter('longitude', i); const locationName = this.getNodeParameter('locationName', i, ''); if (locationName) body.Name = locationName; break; case 'sendContact': endpoint = '/chat/send/contact'; body.Name = this.getNodeParameter('contactName', i); body.Vcard = this.getNodeParameter('vcard', i); break; case 'sendSticker': endpoint = '/chat/send/sticker'; const stickerSource = this.getNodeParameter('stickerSource', i); if (stickerSource === 'binary') { const binaryProperty = this.getNodeParameter('stickerBinaryProperty', i); const binaryData = items[i].binary?.[binaryProperty]; if (!binaryData) { throw new Error(`Binary property "${binaryProperty}" not found`); } const buffer = Buffer.from(binaryData.data, 'base64'); body.Sticker = (0, GenericFunctions_1.prepareMediaData)(buffer, binaryData.mimeType || 'image/webp'); } else if (stickerSource === 'base64') { body.Sticker = this.getNodeParameter('stickerBase64', i); } else if (stickerSource === 'url') { body.Sticker = this.getNodeParameter('stickerUrl', i); } break; case 'sendButtons': endpoint = '/chat/send/buttons'; body.Body = this.getNodeParameter('message', i); break; case 'sendList': endpoint = '/chat/send/list'; body.ButtonText = this.getNodeParameter('buttonText', i); body.Desc = this.getNodeParameter('description', i); body.TopText = this.getNodeParameter('topText', i); const footerText = this.getNodeParameter('footerText', i, ''); if (footerText) body.FooterText = footerText; const listItems = this.getNodeParameter('listItems', i).item; if (listItems && listItems.length > 0) { body.List = listItems.map((item) => ({ title: item.title, desc: item.desc || '', RowId: item.rowId, })); } break; case 'sendPoll': endpoint = '/chat/send/poll'; body.Group = phone; // For polls, phone should be a group ID body.Header = this.getNodeParameter('pollHeader', i); const pollOptions = this.getNodeParameter('pollOptions', i); body.Options = pollOptions.split(',').map(opt => opt.trim()); break; default: throw new Error(`Unknown operation: ${operation}`); } const response = await GenericFunctions_1.wuzapiApiRequest.call(this, 'POST', endpoint, body); const executionData = this.helpers.constructExecutionMetaData([{ json: response }], { itemData: { item: i } }); returnData.push(...executionData); } catch (error) { if (this.continueOnFail()) { const executionData = this.helpers.constructExecutionMetaData([{ json: { error: error.message } }], { itemData: { item: i } }); returnData.push(...executionData); continue; } throw error; } } return [returnData]; } } exports.WuzapiAI = WuzapiAI; //# sourceMappingURL=WuzapiAI.node.js.map