n8n-nodes-wuzapi
Version:
n8n community nodes for Wuzapi - WhatsApp Multi-Device REST API
565 lines • 23.7 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.WuzapiChat = void 0;
const GenericFunctions_1 = require("../GenericFunctions");
class WuzapiChat {
constructor() {
this.description = {
displayName: 'Wuzapi Chat',
name: 'wuzapiChat',
icon: 'file:wuzapi.svg',
group: ['transform'],
version: 1,
subtitle: '={{$parameter["operation"]}}',
description: 'Perform chat operations with Wuzapi WhatsApp API',
defaults: {
name: 'Wuzapi Chat',
},
inputs: ["main" /* NodeConnectionType.Main */],
outputs: ["main" /* NodeConnectionType.Main */],
credentials: [
{
name: 'wuzapiApi',
required: true,
},
],
properties: [
{
displayName: 'Operation',
name: 'operation',
type: 'options',
noDataExpression: true,
options: [
{
name: 'Delete Message',
value: 'delete',
description: 'Delete a message you sent',
action: 'Delete message',
},
{
name: 'Download Media',
value: 'download',
description: 'Download media from a message',
action: 'Download media',
},
{
name: 'Edit Message',
value: 'edit',
description: 'Edit a previously sent message',
action: 'Edit message',
},
{
name: 'Mark as Read',
value: 'markRead',
description: 'Mark messages as read',
action: 'Mark as read',
},
{
name: 'React to Message',
value: 'react',
description: 'Send a reaction to a message',
action: 'React to message',
},
{
name: 'Set Presence',
value: 'presence',
description: 'Set typing/recording indicator',
action: 'Set chat presence',
},
],
default: 'delete',
},
// Delete Message
{
displayName: 'Message ID',
name: 'messageId',
type: 'string',
default: '',
placeholder: 'e.g. 3EB06F9067F80BAB89FF',
description: 'ID of the message to delete',
required: true,
displayOptions: {
show: {
operation: ['delete'],
},
},
},
// Edit Message
{
displayName: 'Message ID',
name: 'editMessageId',
type: 'string',
default: '',
placeholder: 'e.g. 90B2F8B13FAC8A9CF6B06E99C7834DC5',
description: 'ID of the message to edit',
required: true,
displayOptions: {
show: {
operation: ['edit'],
},
},
},
{
displayName: 'Phone Number',
name: 'editPhone',
type: 'string',
default: '',
placeholder: 'e.g. 5491155553934 or me:5491155553934',
description: 'Phone number or "me:" prefix for your own message',
required: true,
displayOptions: {
show: {
operation: ['edit'],
},
},
},
{
displayName: 'New Message',
name: 'newBody',
type: 'string',
default: '',
placeholder: 'Type the updated message here',
description: 'New content for the message',
required: true,
displayOptions: {
show: {
operation: ['edit'],
},
},
},
// Download Media
{
displayName: 'Media Type',
name: 'mediaType',
type: 'options',
default: 'image',
options: [
{
name: 'Audio',
value: 'audio',
description: 'Download audio from message',
},
{
name: 'Document',
value: 'document',
description: 'Download document from message',
},
{
name: 'Image',
value: 'image',
description: 'Download image from message',
},
{
name: 'Video',
value: 'video',
description: 'Download video from message',
},
],
description: 'Type of media to download',
displayOptions: {
show: {
operation: ['download'],
},
},
},
{
displayName: 'Media URL',
name: 'url',
type: 'string',
default: '',
description: 'URL of the media file',
required: true,
displayOptions: {
show: {
operation: ['download'],
},
},
},
{
displayName: 'Direct Path',
name: 'directPath',
type: 'string',
default: '',
description: 'Direct path to the media file',
displayOptions: {
show: {
operation: ['download'],
},
},
},
{
displayName: 'Media Key',
name: 'mediaKey',
type: 'string',
default: '',
description: 'Media encryption key',
required: true,
displayOptions: {
show: {
operation: ['download'],
},
},
},
{
displayName: 'Mime Type',
name: 'mimetype',
type: 'string',
default: '',
placeholder: 'e.g. image/jpeg',
description: 'MIME type of the media',
required: true,
displayOptions: {
show: {
operation: ['download'],
},
},
},
{
displayName: 'File SHA256',
name: 'fileSHA256',
type: 'string',
default: '',
description: 'SHA256 hash of the file',
required: true,
displayOptions: {
show: {
operation: ['download'],
},
},
},
{
displayName: 'File Length',
name: 'fileLength',
type: 'number',
default: 0,
description: 'Size of the file in bytes',
required: true,
displayOptions: {
show: {
operation: ['download'],
},
},
},
{
displayName: 'Additional Fields',
name: 'additionalFields',
type: 'collection',
placeholder: 'Add Field',
default: {},
displayOptions: {
show: {
operation: ['download'],
},
},
options: [
{
displayName: 'File Enc SHA256',
name: 'fileEncSHA256',
type: 'string',
default: '',
description: 'Encrypted file SHA256 hash',
},
{
displayName: 'Binary Property Name',
name: 'binaryPropertyName',
type: 'string',
default: 'data',
description: 'Name of the binary property to store the downloaded media',
},
],
},
// Mark as Read
{
displayName: 'Message IDs',
name: 'messageIds',
type: 'string',
default: '',
placeholder: 'AABBCC11223344,DDEEFF55667788',
description: 'Comma-separated list of message IDs to mark as read',
required: true,
displayOptions: {
show: {
operation: ['markRead'],
},
},
},
{
displayName: 'Chat JID',
name: 'chatJid',
type: 'string',
default: '',
placeholder: 'e.g. 5491155553934.0:1@s.whatsapp.net',
description: 'JID of the chat containing the messages',
required: true,
displayOptions: {
show: {
operation: ['markRead'],
},
},
},
{
displayName: 'Sender JID',
name: 'senderJid',
type: 'string',
default: '',
placeholder: 'e.g. 5491155553111.0:1@s.whatsapp.net',
description: 'JID of the message sender',
displayOptions: {
show: {
operation: ['markRead'],
},
},
},
// React to Message
{
displayName: 'Phone Number',
name: 'reactPhone',
type: 'string',
default: '',
placeholder: 'e.g. 5491155553934 or me:5491155553934',
description: 'Phone number or "me:" prefix for your own message',
required: true,
displayOptions: {
show: {
operation: ['react'],
},
},
},
{
displayName: 'Reaction',
name: 'reaction',
type: 'string',
default: '',
placeholder: 'e.g. ❤️, 👍, 😂',
description: 'Emoji to react with (leave empty to remove reaction)',
displayOptions: {
show: {
operation: ['react'],
},
},
},
{
displayName: 'Message ID',
name: 'reactMessageId',
type: 'string',
default: '',
placeholder: 'e.g. me:3EB06F9067F80BAB89FF',
description: 'ID of the message to react to (prefix with "me:" for your own messages)',
required: true,
displayOptions: {
show: {
operation: ['react'],
},
},
},
// Set Presence
{
displayName: 'Phone Number',
name: 'presencePhone',
type: 'string',
default: '',
placeholder: 'e.g. 5491155553934',
description: 'Phone number to set presence for',
required: true,
displayOptions: {
show: {
operation: ['presence'],
},
},
},
{
displayName: 'State',
name: 'state',
type: 'options',
default: 'composing',
options: [
{
name: 'Typing',
value: 'composing',
description: 'Show typing indicator',
},
{
name: 'Not Typing',
value: 'paused',
description: 'Hide typing indicator',
},
],
description: 'Presence state to set',
displayOptions: {
show: {
operation: ['presence'],
},
},
},
{
displayName: 'Media Type',
name: 'presenceMedia',
type: 'options',
default: '',
options: [
{
name: 'None',
value: '',
description: 'Regular typing indicator',
},
{
name: 'Audio',
value: 'audio',
description: 'Recording audio indicator',
},
],
description: 'Type of media being composed',
displayOptions: {
show: {
operation: ['presence'],
},
},
},
],
};
}
async execute() {
const items = this.getInputData();
const returnData = [];
for (let i = 0; i < items.length; i++) {
try {
const operation = this.getNodeParameter('operation', i);
let responseData;
if (operation === 'delete') {
const messageId = this.getNodeParameter('messageId', i);
const body = {
Id: messageId,
};
responseData = await GenericFunctions_1.wuzapiApiRequest.call(this, 'POST', '/chat/delete', body);
}
else if (operation === 'edit') {
const messageId = this.getNodeParameter('editMessageId', i);
const phone = this.getNodeParameter('editPhone', i);
const newBody = this.getNodeParameter('newBody', i);
const body = {
Id: messageId,
Phone: phone,
Body: newBody,
};
responseData = await GenericFunctions_1.wuzapiApiRequest.call(this, 'POST', '/chat/send/edit', body);
}
else if (operation === 'download') {
const mediaType = this.getNodeParameter('mediaType', i);
const url = this.getNodeParameter('url', i);
const directPath = this.getNodeParameter('directPath', i);
const mediaKey = this.getNodeParameter('mediaKey', i);
const mimetype = this.getNodeParameter('mimetype', i);
const fileSHA256 = this.getNodeParameter('fileSHA256', i);
const fileLength = this.getNodeParameter('fileLength', i);
const additionalFields = this.getNodeParameter('additionalFields', i);
const body = {
Url: url,
MediaKey: mediaKey,
Mimetype: mimetype,
FileSHA256: fileSHA256,
FileLength: fileLength,
};
if (directPath) {
body.DirectPath = directPath;
}
if (additionalFields.fileEncSHA256) {
body.FileEncSHA256 = additionalFields.fileEncSHA256;
}
let endpoint = '/chat/download';
switch (mediaType) {
case 'image':
endpoint = '/chat/downloadimage';
break;
case 'video':
endpoint = '/chat/downloadvideo';
break;
case 'audio':
endpoint = '/chat/downloadaudio';
break;
case 'document':
endpoint = '/chat/downloaddocument';
break;
}
responseData = await GenericFunctions_1.wuzapiApiRequest.call(this, 'POST', endpoint, body);
// Handle binary data
if (responseData.data && responseData.data.Data) {
const binaryPropertyName = additionalFields.binaryPropertyName || 'data';
const dataUrl = responseData.data.Data;
const matches = dataUrl.match(/^data:([^;]+);base64,(.+)$/);
if (matches && matches[2]) {
const mimeType = matches[1] || mimetype;
const base64Data = matches[2];
// Determine file extension from mime type
let fileExtension = 'bin';
if (mimeType.includes('image'))
fileExtension = mimeType.split('/')[1] || 'jpg';
else if (mimeType.includes('video'))
fileExtension = mimeType.split('/')[1] || 'mp4';
else if (mimeType.includes('audio'))
fileExtension = mimeType.split('/')[1] || 'ogg';
else if (mimeType.includes('pdf'))
fileExtension = 'pdf';
items[i].binary = items[i].binary || {};
items[i].binary[binaryPropertyName] = {
data: base64Data,
mimeType,
fileExtension,
fileName: `downloaded-media.${fileExtension}`,
};
}
}
}
else if (operation === 'markRead') {
const messageIds = this.getNodeParameter('messageIds', i);
const chatJid = this.getNodeParameter('chatJid', i);
const senderJid = this.getNodeParameter('senderJid', i);
const body = {
Id: messageIds.split(',').map(id => id.trim()),
Chat: chatJid,
};
if (senderJid) {
body.Sender = senderJid;
}
responseData = await GenericFunctions_1.wuzapiApiRequest.call(this, 'POST', '/chat/markread', body);
}
else if (operation === 'react') {
const phone = this.getNodeParameter('reactPhone', i);
const reaction = this.getNodeParameter('reaction', i);
const messageId = this.getNodeParameter('reactMessageId', i);
const body = {
Phone: phone,
Body: reaction,
Id: messageId,
};
responseData = await GenericFunctions_1.wuzapiApiRequest.call(this, 'POST', '/chat/react', body);
}
else if (operation === 'presence') {
const phone = this.getNodeParameter('presencePhone', i);
const state = this.getNodeParameter('state', i);
const media = this.getNodeParameter('presenceMedia', i);
const body = {
Phone: phone,
State: state,
};
if (media) {
body.Media = media;
}
responseData = await GenericFunctions_1.wuzapiApiRequest.call(this, 'POST', '/chat/presence', body);
}
const executionData = this.helpers.constructExecutionMetaData(this.helpers.returnJsonArray(responseData), { itemData: { item: i } });
returnData.push(...executionData);
}
catch (error) {
if (this.continueOnFail()) {
const executionErrorData = this.helpers.constructExecutionMetaData(this.helpers.returnJsonArray({ error: error.message }), { itemData: { item: i } });
returnData.push(...executionErrorData);
continue;
}
throw error;
}
}
return [returnData];
}
}
exports.WuzapiChat = WuzapiChat;
//# sourceMappingURL=WuzapiChat.node.js.map