UNPKG

n8n-nodes-wuzapi

Version:

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

898 lines 41.7 kB
"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