n8n-nodes-wuzapi
Version:
n8n community nodes for Wuzapi - WhatsApp Multi-Device REST API
898 lines • 41.7 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.WuzapiSession = void 0;
const GenericFunctions_1 = require("../GenericFunctions");
class WuzapiSession {
constructor() {
this.description = {
displayName: 'Wuzapi Session',
name: 'wuzapiSession',
icon: 'file:wuzapi.svg',
group: ['transform'],
version: 1,
subtitle: '={{$parameter["operation"]}}',
description: 'Manage WhatsApp sessions in Wuzapi',
defaults: {
name: 'Wuzapi Session',
},
inputs: ["main" /* NodeConnectionType.Main */],
outputs: ["main" /* NodeConnectionType.Main */],
credentials: [
{
name: 'wuzapiApi',
required: true,
},
],
properties: [
{
displayName: 'Operation',
name: 'operation',
type: 'options',
noDataExpression: true,
options: [
{
name: 'Connect',
value: 'connect',
description: 'Connect to WhatsApp servers',
action: 'Connect to whats app',
},
{
name: 'Disconnect',
value: 'disconnect',
description: 'Disconnect from WhatsApp servers',
action: 'Disconnect from whats app',
},
{
name: 'Get QR Code',
value: 'getQr',
description: 'Get QR code for scanning',
action: 'Get QR code',
},
{
name: 'Get Status',
value: 'getStatus',
description: 'Get connection and session status',
action: 'Get connection status',
},
{
name: 'Logout',
value: 'logout',
description: 'Logout and terminate session',
action: 'Logout from whats app',
},
{
name: 'Pair Phone',
value: 'pairPhone',
description: 'Get pairing code for phone',
action: 'Get phone pairing code',
},
{
name: 'Set Proxy',
value: 'setProxy',
description: 'Configure proxy settings',
action: 'Set proxy configuration',
},
// S3 Operations
{
name: 'Configure S3',
value: 'configureS3',
description: 'Configure S3 storage settings',
action: 'Configure S3 storage',
},
{
name: 'Get S3 Config',
value: 'getS3Config',
description: 'Get current S3 configuration',
action: 'Get S3 configuration',
},
{
name: 'Remove S3 Config',
value: 'removeS3Config',
description: 'Remove S3 configuration',
action: 'Remove S3 configuration',
},
{
name: 'Test S3 Connection',
value: 'testS3Connection',
action: 'Test S3 connection',
},
// RabbitMQ Operations
{
name: 'Configure RabbitMQ',
value: 'configureRabbitMQ',
description: 'Configure RabbitMQ settings',
action: 'Configure rabbit mq',
},
{
name: 'Get RabbitMQ Config',
value: 'getRabbitMQConfig',
description: 'Get current RabbitMQ configuration',
action: 'Get rabbit mq configuration',
},
{
name: 'Remove RabbitMQ Config',
value: 'removeRabbitMQConfig',
description: 'Remove RabbitMQ configuration',
action: 'Remove rabbit mq configuration',
},
{
name: 'Test RabbitMQ Connection',
value: 'testRabbitMQConnection',
action: 'Test rabbit mq connection',
},
],
default: 'connect',
},
// Connect Operation
{
displayName: 'Wait for Connection',
name: 'immediate',
type: 'boolean',
default: false,
description: 'Whether to wait for actual connection status or return immediately',
displayOptions: {
show: {
operation: ['connect'],
},
},
},
{
displayName: 'Subscribe to Events',
name: 'subscribe',
type: 'multiOptions',
default: ['All'],
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 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: 'Event types to subscribe to',
displayOptions: {
show: {
operation: ['connect'],
},
},
},
// Pair Phone Operation
{
displayName: 'Phone Number',
name: 'phone',
type: 'string',
default: '',
placeholder: 'e.g. 5491155553934',
description: 'Phone number to pair with (without + or spaces)',
required: true,
displayOptions: {
show: {
operation: ['pairPhone'],
},
},
},
// Set Proxy Operation
{
displayName: 'Proxy URL',
name: 'proxy_url',
type: 'string',
default: '',
placeholder: 'e.g. socks5://user:pass@host:port',
description: 'Proxy URL in format "http://host:port" or "socks5://user:pass@host:port"',
required: true,
displayOptions: {
show: {
operation: ['setProxy'],
},
},
},
{
displayName: 'Enable Proxy',
name: 'enable',
type: 'boolean',
default: true,
description: 'Whether to enable or disable the proxy',
displayOptions: {
show: {
operation: ['setProxy'],
},
},
},
// S3 Configuration fields
{
displayName: 'S3 Enabled',
name: 's3Enabled',
type: 'boolean',
default: true,
description: 'Whether S3 storage is enabled',
displayOptions: {
show: {
operation: ['configureS3'],
},
},
},
{
displayName: 'S3 Configuration',
name: 's3Config',
type: 'collection',
placeholder: 'Add S3 Configuration',
default: {},
required: true,
displayOptions: {
show: {
operation: ['configureS3'],
s3Enabled: [true],
},
},
options: [
{
displayName: 'Endpoint',
name: 'endpoint',
type: 'string',
default: 'https://s3.amazonaws.com',
placeholder: 'e.g. https://s3.amazonaws.com',
description: 'S3 endpoint URL (leave default for AWS S3)',
},
{
displayName: 'Region',
name: 'region',
type: 'string',
default: 'us-east-1',
placeholder: 'e.g. us-east-1',
description: 'S3 region',
required: true,
},
{
displayName: 'Bucket',
name: 'bucket',
type: 'string',
default: '',
placeholder: 'e.g. my-whatsapp-media',
description: 'S3 bucket name',
required: true,
},
{
displayName: 'Access Key',
name: 'accessKey',
type: 'string',
default: '',
placeholder: 'e.g. AKIAIOSFODNN7EXAMPLE',
description: 'S3 access key ID',
required: true,
},
{
displayName: 'Secret Key',
name: 'secretKey',
type: 'string',
default: '',
placeholder: 'e.g. wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY',
description: 'S3 secret access key',
typeOptions: {
password: true,
},
required: true,
},
{
displayName: 'Path Style',
name: 'pathStyle',
type: 'boolean',
default: false,
description: 'Whether to use path-style URLs (required for MinIO)',
},
{
displayName: 'Public URL',
name: 'publicURL',
type: 'string',
default: '',
placeholder: 'e.g. https://cdn.example.com',
description: 'Custom public URL for accessing files (optional)',
},
{
displayName: 'Media Delivery',
name: 'mediaDelivery',
type: 'options',
default: 'both',
options: [
{
name: 'Base64 Only',
value: 'base64',
},
{
name: 'S3 URL Only',
value: 's3',
},
{
name: 'Both',
value: 'both',
},
],
description: 'How to deliver media files',
},
{
displayName: 'Retention Days',
name: 'retentionDays',
type: 'number',
default: 30,
description: 'Number of days to retain files (0 for no expiration)',
typeOptions: {
minValue: 0,
maxValue: 365,
},
},
],
},
// RabbitMQ Configuration fields
{
displayName: 'RabbitMQ Enabled',
name: 'rabbitmqEnabled',
type: 'boolean',
default: true,
description: 'Whether RabbitMQ publishing is enabled',
displayOptions: {
show: {
operation: ['configureRabbitMQ'],
},
},
},
{
displayName: 'RabbitMQ Configuration',
name: 'rabbitmqConfig',
type: 'collection',
placeholder: 'Add RabbitMQ Configuration',
default: {},
required: true,
displayOptions: {
show: {
operation: ['configureRabbitMQ'],
rabbitmqEnabled: [true],
},
},
options: [
{
displayName: 'Host',
name: 'host',
type: 'string',
default: 'localhost',
placeholder: 'e.g. localhost',
description: 'RabbitMQ server hostname or IP address',
},
{
displayName: 'Port',
name: 'port',
type: 'number',
default: 5672,
description: 'RabbitMQ server port',
typeOptions: {
minValue: 1,
maxValue: 65535,
},
},
{
displayName: 'Username',
name: 'username',
type: 'string',
default: 'guest',
placeholder: 'e.g. guest',
description: 'RabbitMQ username',
required: true,
},
{
displayName: 'Password',
name: 'password',
type: 'string',
default: 'guest',
placeholder: 'e.g. guest',
description: 'RabbitMQ password',
typeOptions: {
password: true,
},
required: true,
},
{
displayName: 'Virtual Host',
name: 'vhost',
type: 'string',
default: '/',
placeholder: 'e.g. /',
description: 'RabbitMQ virtual host',
},
{
displayName: 'Exchange',
name: 'exchange',
type: 'string',
default: 'whatsapp.events',
placeholder: 'e.g. whatsapp.events',
description: 'Exchange name for publishing events',
required: true,
},
{
displayName: 'Exclusive',
name: 'exclusive',
type: 'boolean',
default: false,
description: 'Whether the queue should be exclusive to the connection',
},
{
displayName: 'No Wait',
name: 'noWait',
type: 'boolean',
default: false,
description: 'Whether to wait for server confirmation',
},
{
displayName: 'Delivery Mode',
name: 'deliveryMode',
type: 'options',
default: 2,
options: [
{
name: 'Non-Persistent (1)',
value: 1,
},
{
name: 'Persistent (2)',
value: 2,
},
],
description: 'Message delivery mode',
},
{
displayName: 'Routing Key',
name: 'routingKey',
type: 'string',
default: 'whatsapp.{event_type}',
placeholder: 'e.g. whatsapp.{event_type}',
description: 'Routing key pattern (use {event_type} placeholder)',
},
{
displayName: 'Queue',
name: 'queue',
type: 'string',
default: 'whatsapp.user.{user_id}',
placeholder: 'e.g. whatsapp.user.{user_id}',
description: 'Queue name pattern (use {user_id} placeholder)',
},
{
displayName: 'Durable',
name: 'durable',
type: 'boolean',
default: true,
description: 'Whether the exchange and queue should be durable',
},
{
displayName: 'Auto Delete',
name: 'autoDelete',
type: 'boolean',
default: false,
description: 'Whether the exchange and queue should auto-delete when unused',
},
{
displayName: 'Events',
name: 'events',
type: 'multiOptions',
default: ['Message'],
options: [
{
name: 'All Events',
value: 'All',
},
{
name: 'Chat Presence',
value: 'ChatPresence',
},
{
name: 'Connected',
value: 'Connected',
},
{
name: 'Disconnected',
value: 'Disconnected',
},
{
name: 'Group Info',
value: 'GroupInfo',
},
{
name: 'Message',
value: 'Message',
},
{
name: 'Presence',
value: 'Presence',
},
{
name: 'QR Code',
value: 'QR',
},
{
name: 'Receipt',
value: 'Receipt',
},
],
description: 'Event types to publish to RabbitMQ',
},
],
},
],
};
}
async execute() {
const items = this.getInputData();
const returnData = [];
const operation = this.getNodeParameter('operation', 0);
for (let i = 0; i < items.length; i++) {
try {
let responseData;
if (operation === 'connect') {
const immediate = this.getNodeParameter('immediate', i);
const subscribe = this.getNodeParameter('subscribe', i);
const body = {
Immediate: immediate,
Subscribe: subscribe.length === 1 && subscribe[0] === 'All' ? undefined : subscribe,
};
responseData = await GenericFunctions_1.wuzapiApiRequest.call(this, 'POST', '/session/connect', body);
}
else if (operation === 'disconnect') {
responseData = await GenericFunctions_1.wuzapiApiRequest.call(this, 'POST', '/session/disconnect');
}
else if (operation === 'getStatus') {
responseData = await GenericFunctions_1.wuzapiApiRequest.call(this, 'GET', '/session/status');
}
else if (operation === 'getQr') {
responseData = await GenericFunctions_1.wuzapiApiRequest.call(this, 'GET', '/session/qr');
// If QR code is present, add it as binary data for easier display
if (responseData.data?.QRCode) {
const qrCodeData = responseData.data.QRCode;
const matches = qrCodeData.match(/^data:([^;]+);base64,(.+)$/);
if (matches && matches[2]) {
const binaryData = Buffer.from(matches[2], 'base64');
const mimeType = matches[1] || 'image/png';
items[i].binary = items[i].binary || {};
items[i].binary.qrCode = {
data: binaryData.toString('base64'),
mimeType,
fileExtension: mimeType.split('/')[1] || 'png',
fileName: 'whatsapp-qr-code.png',
};
}
}
}
else if (operation === 'logout') {
responseData = await GenericFunctions_1.wuzapiApiRequest.call(this, 'POST', '/session/logout');
}
else if (operation === 'pairPhone') {
const phone = this.getNodeParameter('phone', i);
const cleanPhone = (0, GenericFunctions_1.validatePhoneNumber)(phone);
const body = {
Phone: cleanPhone,
};
responseData = await GenericFunctions_1.wuzapiApiRequest.call(this, 'POST', '/session/pairphone', body);
}
else if (operation === 'setProxy') {
const proxyUrl = this.getNodeParameter('proxy_url', i);
const enable = this.getNodeParameter('enable', i);
const body = {
proxy_url: proxyUrl,
enable,
};
responseData = await GenericFunctions_1.wuzapiApiRequest.call(this, 'POST', '/session/proxy', body);
}
// S3 Operations
else if (operation === 'configureS3') {
const enabled = this.getNodeParameter('s3Enabled', i);
if (enabled) {
const s3Config = this.getNodeParameter('s3Config', i);
const body = {
enabled,
endpoint: s3Config.endpoint || 'https://s3.amazonaws.com',
region: s3Config.region,
bucket: s3Config.bucket,
accessKey: s3Config.accessKey,
secretKey: s3Config.secretKey,
pathStyle: s3Config.pathStyle || false,
publicURL: s3Config.publicURL || '',
mediaDelivery: s3Config.mediaDelivery || 'both',
retentionDays: s3Config.retentionDays || 30,
};
responseData = await GenericFunctions_1.wuzapiApiRequest.call(this, 'POST', '/session/s3/config', body);
}
else {
const body = {
enabled: false,
};
responseData = await GenericFunctions_1.wuzapiApiRequest.call(this, 'POST', '/session/s3/config', body);
}
}
else if (operation === 'getS3Config') {
responseData = await GenericFunctions_1.wuzapiApiRequest.call(this, 'GET', '/session/s3/config');
}
else if (operation === 'removeS3Config') {
responseData = await GenericFunctions_1.wuzapiApiRequest.call(this, 'DELETE', '/session/s3/config');
}
else if (operation === 'testS3Connection') {
responseData = await GenericFunctions_1.wuzapiApiRequest.call(this, 'POST', '/session/s3/test');
}
// RabbitMQ Operations
else if (operation === 'configureRabbitMQ') {
const enabled = this.getNodeParameter('rabbitmqEnabled', i);
if (enabled) {
const rabbitmqConfig = this.getNodeParameter('rabbitmqConfig', i);
// Build proper URL format
const url = `amqp://${rabbitmqConfig.username}:${rabbitmqConfig.password}@${rabbitmqConfig.host}:${rabbitmqConfig.port || 5672}${rabbitmqConfig.vhost || '/'}`;
const body = {
enabled,
url: url,
exchange: rabbitmqConfig.exchange,
routing_key: rabbitmqConfig.routingKey || 'wuzapi.{user_id}.{event_type}',
queue: rabbitmqConfig.queue || 'wuzapi.user.{user_id}.events',
durable: rabbitmqConfig.durable !== false,
auto_delete: rabbitmqConfig.autoDelete === true,
exclusive: rabbitmqConfig.exclusive === true,
no_wait: rabbitmqConfig.noWait === true,
delivery_mode: rabbitmqConfig.deliveryMode || 2,
events: Array.isArray(rabbitmqConfig.events) ? rabbitmqConfig.events.join(',') : 'Message',
};
responseData = await GenericFunctions_1.wuzapiApiRequest.call(this, 'POST', '/session/rabbitmq/config', body);
}
else {
const body = {
enabled: false,
};
responseData = await GenericFunctions_1.wuzapiApiRequest.call(this, 'POST', '/session/rabbitmq/config', body);
}
}
else if (operation === 'getRabbitMQConfig') {
responseData = await GenericFunctions_1.wuzapiApiRequest.call(this, 'GET', '/session/rabbitmq/config');
}
else if (operation === 'removeRabbitMQConfig') {
responseData = await GenericFunctions_1.wuzapiApiRequest.call(this, 'DELETE', '/session/rabbitmq/config');
}
else if (operation === 'testRabbitMQConnection') {
responseData = await GenericFunctions_1.wuzapiApiRequest.call(this, 'POST', '/session/rabbitmq/test');
}
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.WuzapiSession = WuzapiSession;
//# sourceMappingURL=WuzapiSession.node.js.map