UNPKG

evolution-api-mcp

Version:

MCP Server for Evolution API v2 - Integrate WhatsApp functionality with Claude Desktop and other MCP clients

1,059 lines (1,057 loc) 45.8 kB
"use strict"; /** * Message Controller MCP Tools Implementation * Implements all tools for sending messages through Evolution API */ Object.defineProperty(exports, "__esModule", { value: true }); exports.messageTools = exports.MessageTools = void 0; const zod_1 = require("zod"); const evolution_http_client_1 = require("../../clients/evolution-http-client"); const message_endpoints_1 = require("../../registry/endpoints/message-endpoints"); /** * Message Controller tool implementations */ class MessageTools { constructor(httpClient) { this.httpClient = httpClient; } /** * Send text message */ createSendTextTool() { const endpoint = message_endpoints_1.messageEndpoints.find(e => e.name === 'send-text'); return { name: 'evolution_send_text_message', description: 'Send a text message to a WhatsApp number', controller: 'message', endpoint, schema: zod_1.z.object({ instance: zod_1.z.string() .min(1, 'Instance name is required') .describe('Name of the WhatsApp instance to send from'), number: zod_1.z.string() .min(10, 'Valid phone number is required') .regex(/^\d+$/, 'Phone number must contain only digits') .describe('Recipient phone number (format: 5511999999999)'), text: zod_1.z.string() .min(1, 'Message text is required') .max(4096, 'Message text cannot exceed 4096 characters') .describe('Text message content to send'), delay: zod_1.z.number() .min(0) .max(60000) .optional() .describe('Delay in milliseconds before sending (0-60000)'), quoted: zod_1.z.object({ key: zod_1.z.object({ remoteJid: zod_1.z.string().describe('JID of the chat where the original message was sent'), fromMe: zod_1.z.boolean().describe('Whether the original message was sent by this instance'), id: zod_1.z.string().describe('ID of the original message') }), message: zod_1.z.any().describe('Original message content') }).optional().describe('Quote a previous message') }), handler: this.sendTextHandler.bind(this), examples: { usage: 'Send a text message to a WhatsApp number', parameters: { instance: 'my_whatsapp_bot', number: '5511999999999', text: 'Hello! This is a test message.', delay: 1000 } } }; } async sendTextHandler(params) { try { const requestData = { number: params.number, text: params.text, ...(params.delay && { delay: params.delay }), ...(params.quoted && { quoted: params.quoted }) }; const response = await this.httpClient.post(`/message/sendText/${params.instance}`, requestData); if (!response.success) { return this.handleApiError(response.error, 'send text message'); } return { success: true, data: { message: `Text message sent successfully to ${params.number}`, messageId: response.data?.key?.id, instance: params.instance, recipient: params.number, text: params.text, result: response.data } }; } catch (error) { return this.handleUnexpectedError(error, 'send text message'); } } /** * Send media message (images, videos, documents) */ createSendMediaTool() { const endpoint = message_endpoints_1.messageEndpoints.find(e => e.name === 'send-media'); return { name: 'evolution_send_media_message', description: 'Send media (image, video, document) to a WhatsApp number', controller: 'message', endpoint, schema: zod_1.z.object({ instance: zod_1.z.string() .min(1, 'Instance name is required') .describe('Name of the WhatsApp instance to send from'), number: zod_1.z.string() .min(10, 'Valid phone number is required') .regex(/^\d+$/, 'Phone number must contain only digits') .describe('Recipient phone number (format: 5511999999999)'), media: zod_1.z.string() .min(1, 'Media URL or base64 is required') .describe('Media URL (https://...) or base64 encoded media data'), caption: zod_1.z.string() .max(1024, 'Caption cannot exceed 1024 characters') .optional() .describe('Optional caption for the media'), fileName: zod_1.z.string() .optional() .describe('Optional filename for documents'), delay: zod_1.z.number() .min(0) .max(60000) .optional() .describe('Delay in milliseconds before sending (0-60000)') }), handler: this.sendMediaHandler.bind(this), examples: { usage: 'Send an image, video, or document to a WhatsApp number', parameters: { instance: 'my_whatsapp_bot', number: '5511999999999', media: 'https://example.com/image.jpg', caption: 'Check out this image!', delay: 1000 } } }; } async sendMediaHandler(params) { try { const requestData = { number: params.number, media: params.media, ...(params.caption && { caption: params.caption }), ...(params.fileName && { fileName: params.fileName }), ...(params.delay && { delay: params.delay }) }; const response = await this.httpClient.post(`/message/sendMedia/${params.instance}`, requestData); if (!response.success) { return this.handleApiError(response.error, 'send media message'); } return { success: true, data: { message: `Media message sent successfully to ${params.number}`, messageId: response.data?.key?.id, instance: params.instance, recipient: params.number, mediaType: this.detectMediaType(params.media), caption: params.caption, result: response.data } }; } catch (error) { return this.handleUnexpectedError(error, 'send media message'); } } /** * Send audio/voice message */ createSendAudioTool() { const endpoint = message_endpoints_1.messageEndpoints.find(e => e.name === 'send-audio'); return { name: 'evolution_send_audio_message', description: 'Send audio or voice message to a WhatsApp number', controller: 'message', endpoint, schema: zod_1.z.object({ instance: zod_1.z.string() .min(1, 'Instance name is required') .describe('Name of the WhatsApp instance to send from'), number: zod_1.z.string() .min(10, 'Valid phone number is required') .regex(/^\d+$/, 'Phone number must contain only digits') .describe('Recipient phone number (format: 5511999999999)'), audio: zod_1.z.string() .min(1, 'Audio URL or base64 is required') .describe('Audio URL (https://...) or base64 encoded audio data'), delay: zod_1.z.number() .min(0) .max(60000) .optional() .describe('Delay in milliseconds before sending (0-60000)') }), handler: this.sendAudioHandler.bind(this), examples: { usage: 'Send an audio or voice message to a WhatsApp number', parameters: { instance: 'my_whatsapp_bot', number: '5511999999999', audio: 'https://example.com/audio.mp3', delay: 1000 } } }; } async sendAudioHandler(params) { try { const requestData = { number: params.number, audio: params.audio, ...(params.delay && { delay: params.delay }) }; const response = await this.httpClient.post(`/message/sendWhatsAppAudio/${params.instance}`, requestData); if (!response.success) { return this.handleApiError(response.error, 'send audio message'); } return { success: true, data: { message: `Audio message sent successfully to ${params.number}`, messageId: response.data?.key?.id, instance: params.instance, recipient: params.number, result: response.data } }; } catch (error) { return this.handleUnexpectedError(error, 'send audio message'); } } /** * Send sticker */ createSendStickerTool() { const endpoint = message_endpoints_1.messageEndpoints.find(e => e.name === 'send-sticker'); return { name: 'evolution_send_sticker', description: 'Send a sticker to a WhatsApp number', controller: 'message', endpoint, schema: zod_1.z.object({ instance: zod_1.z.string() .min(1, 'Instance name is required') .describe('Name of the WhatsApp instance to send from'), number: zod_1.z.string() .min(10, 'Valid phone number is required') .regex(/^\d+$/, 'Phone number must contain only digits') .describe('Recipient phone number (format: 5511999999999)'), sticker: zod_1.z.string() .min(1, 'Sticker URL or base64 is required') .describe('Sticker URL (https://...) or base64 encoded sticker data'), delay: zod_1.z.number() .min(0) .max(60000) .optional() .describe('Delay in milliseconds before sending (0-60000)') }), handler: this.sendStickerHandler.bind(this), examples: { usage: 'Send a sticker to a WhatsApp number', parameters: { instance: 'my_whatsapp_bot', number: '5511999999999', sticker: 'https://example.com/sticker.webp', delay: 1000 } } }; } async sendStickerHandler(params) { try { const requestData = { number: params.number, sticker: params.sticker, ...(params.delay && { delay: params.delay }) }; const response = await this.httpClient.post(`/message/sendSticker/${params.instance}`, requestData); if (!response.success) { return this.handleApiError(response.error, 'send sticker'); } return { success: true, data: { message: `Sticker sent successfully to ${params.number}`, messageId: response.data?.key?.id, instance: params.instance, recipient: params.number, result: response.data } }; } catch (error) { return this.handleUnexpectedError(error, 'send sticker'); } } /* * * Send location */ createSendLocationTool() { const endpoint = message_endpoints_1.messageEndpoints.find(e => e.name === 'send-location'); return { name: 'evolution_send_location', description: 'Send a location to a WhatsApp number', controller: 'message', endpoint, schema: zod_1.z.object({ instance: zod_1.z.string() .min(1, 'Instance name is required') .describe('Name of the WhatsApp instance to send from'), number: zod_1.z.string() .min(10, 'Valid phone number is required') .regex(/^\d+$/, 'Phone number must contain only digits') .describe('Recipient phone number (format: 5511999999999)'), latitude: zod_1.z.number() .min(-90) .max(90) .describe('Latitude coordinate (-90 to 90)'), longitude: zod_1.z.number() .min(-180) .max(180) .describe('Longitude coordinate (-180 to 180)'), name: zod_1.z.string() .optional() .describe('Optional name/title for the location'), address: zod_1.z.string() .optional() .describe('Optional address description'), delay: zod_1.z.number() .min(0) .max(60000) .optional() .describe('Delay in milliseconds before sending (0-60000)') }), handler: this.sendLocationHandler.bind(this), examples: { usage: 'Send a location with coordinates to a WhatsApp number', parameters: { instance: 'my_whatsapp_bot', number: '5511999999999', latitude: -23.5505, longitude: -46.6333, name: 'São Paulo', address: 'São Paulo, SP, Brazil', delay: 1000 } } }; } async sendLocationHandler(params) { try { const requestData = { number: params.number, latitude: params.latitude, longitude: params.longitude, ...(params.name && { name: params.name }), ...(params.address && { address: params.address }), ...(params.delay && { delay: params.delay }) }; const response = await this.httpClient.post(`/message/sendLocation/${params.instance}`, requestData); if (!response.success) { return this.handleApiError(response.error, 'send location'); } return { success: true, data: { message: `Location sent successfully to ${params.number}`, messageId: response.data?.key?.id, instance: params.instance, recipient: params.number, coordinates: `${params.latitude}, ${params.longitude}`, locationName: params.name, result: response.data } }; } catch (error) { return this.handleUnexpectedError(error, 'send location'); } } /** * Send contact */ createSendContactTool() { const endpoint = message_endpoints_1.messageEndpoints.find(e => e.name === 'send-contact'); return { name: 'evolution_send_contact', description: 'Send a contact card to a WhatsApp number', controller: 'message', endpoint, schema: zod_1.z.object({ instance: zod_1.z.string() .min(1, 'Instance name is required') .describe('Name of the WhatsApp instance to send from'), number: zod_1.z.string() .min(10, 'Valid phone number is required') .regex(/^\d+$/, 'Phone number must contain only digits') .describe('Recipient phone number (format: 5511999999999)'), contact: zod_1.z.object({ fullName: zod_1.z.string() .min(1, 'Contact full name is required') .describe('Full name of the contact'), wuid: zod_1.z.string() .describe('WhatsApp user ID of the contact'), phoneNumber: zod_1.z.string() .min(10, 'Valid phone number is required') .describe('Phone number of the contact') }).describe('Contact information to send'), delay: zod_1.z.number() .min(0) .max(60000) .optional() .describe('Delay in milliseconds before sending (0-60000)') }), handler: this.sendContactHandler.bind(this), examples: { usage: 'Send a contact card to a WhatsApp number', parameters: { instance: 'my_whatsapp_bot', number: '5511999999999', contact: { fullName: 'John Doe', wuid: '5511888888888', phoneNumber: '5511888888888' }, delay: 1000 } } }; } async sendContactHandler(params) { try { const requestData = { number: params.number, contact: params.contact, ...(params.delay && { delay: params.delay }) }; const response = await this.httpClient.post(`/message/sendContact/${params.instance}`, requestData); if (!response.success) { return this.handleApiError(response.error, 'send contact'); } return { success: true, data: { message: `Contact card sent successfully to ${params.number}`, messageId: response.data?.key?.id, instance: params.instance, recipient: params.number, contactName: params.contact.fullName, result: response.data } }; } catch (error) { return this.handleUnexpectedError(error, 'send contact'); } } /** * Send reaction to a message */ createSendReactionTool() { const endpoint = message_endpoints_1.messageEndpoints.find(e => e.name === 'send-reaction'); return { name: 'evolution_send_reaction', description: 'Send a reaction (emoji) to a specific message', controller: 'message', endpoint, schema: zod_1.z.object({ instance: zod_1.z.string() .min(1, 'Instance name is required') .describe('Name of the WhatsApp instance to send from'), key: zod_1.z.object({ remoteJid: zod_1.z.string() .describe('JID of the chat where the message is located'), fromMe: zod_1.z.boolean() .describe('Whether the message was sent by this instance'), id: zod_1.z.string() .describe('ID of the message to react to') }).describe('Message key identifying which message to react to'), reaction: zod_1.z.string() .min(1, 'Reaction emoji is required') .max(10, 'Reaction must be a single emoji or short text') .describe('Emoji or reaction text (e.g., "👍", "❤️", "😂")') }), handler: this.sendReactionHandler.bind(this), examples: { usage: 'Send a reaction emoji to a specific message', parameters: { instance: 'my_whatsapp_bot', key: { remoteJid: '5511999999999@s.whatsapp.net', fromMe: false, id: 'message_id_here' }, reaction: '👍' } } }; } async sendReactionHandler(params) { try { const requestData = { key: params.key, reaction: params.reaction }; const response = await this.httpClient.post(`/message/sendReaction/${params.instance}`, requestData); if (!response.success) { return this.handleApiError(response.error, 'send reaction'); } return { success: true, data: { message: `Reaction "${params.reaction}" sent successfully`, instance: params.instance, messageId: params.key.id, reaction: params.reaction, result: response.data } }; } catch (error) { return this.handleUnexpectedError(error, 'send reaction'); } } /** * Send poll */ createSendPollTool() { const endpoint = message_endpoints_1.messageEndpoints.find(e => e.name === 'send-poll'); return { name: 'evolution_send_poll', description: 'Send an interactive poll to a WhatsApp number', controller: 'message', endpoint, schema: zod_1.z.object({ instance: zod_1.z.string() .min(1, 'Instance name is required') .describe('Name of the WhatsApp instance to send from'), number: zod_1.z.string() .min(10, 'Valid phone number is required') .regex(/^\d+$/, 'Phone number must contain only digits') .describe('Recipient phone number (format: 5511999999999)'), name: zod_1.z.string() .min(1, 'Poll question is required') .max(255, 'Poll question cannot exceed 255 characters') .describe('The poll question'), selectableCount: zod_1.z.number() .min(1) .max(12) .describe('Number of options users can select (1-12)'), values: zod_1.z.array(zod_1.z.string()) .min(2, 'Poll must have at least 2 options') .max(12, 'Poll cannot have more than 12 options') .describe('Array of poll options'), delay: zod_1.z.number() .min(0) .max(60000) .optional() .describe('Delay in milliseconds before sending (0-60000)') }), handler: this.sendPollHandler.bind(this), examples: { usage: 'Send an interactive poll with multiple choice options', parameters: { instance: 'my_whatsapp_bot', number: '5511999999999', name: 'What is your favorite programming language?', selectableCount: 1, values: ['JavaScript', 'Python', 'Java', 'TypeScript'], delay: 1000 } } }; } async sendPollHandler(params) { try { const requestData = { number: params.number, name: params.name, selectableCount: params.selectableCount, values: params.values, ...(params.delay && { delay: params.delay }) }; const response = await this.httpClient.post(`/message/sendPoll/${params.instance}`, requestData); if (!response.success) { return this.handleApiError(response.error, 'send poll'); } return { success: true, data: { message: `Poll sent successfully to ${params.number}`, messageId: response.data?.key?.id, instance: params.instance, recipient: params.number, pollQuestion: params.name, optionsCount: params.values.length, selectableCount: params.selectableCount, result: response.data } }; } catch (error) { return this.handleUnexpectedError(error, 'send poll'); } } /** * Send interactive list */ createSendListTool() { const endpoint = message_endpoints_1.messageEndpoints.find(e => e.name === 'send-list'); return { name: 'evolution_send_list', description: 'Send an interactive list message to a WhatsApp number', controller: 'message', endpoint, schema: zod_1.z.object({ instance: zod_1.z.string() .min(1, 'Instance name is required') .describe('Name of the WhatsApp instance to send from'), number: zod_1.z.string() .min(10, 'Valid phone number is required') .regex(/^\d+$/, 'Phone number must contain only digits') .describe('Recipient phone number (format: 5511999999999)'), title: zod_1.z.string() .min(1, 'List title is required') .max(60, 'Title cannot exceed 60 characters') .describe('Title of the list message'), description: zod_1.z.string() .min(1, 'List description is required') .max(1024, 'Description cannot exceed 1024 characters') .describe('Description of the list message'), buttonText: zod_1.z.string() .min(1, 'Button text is required') .max(20, 'Button text cannot exceed 20 characters') .describe('Text displayed on the list button'), footerText: zod_1.z.string() .max(60, 'Footer text cannot exceed 60 characters') .optional() .describe('Optional footer text'), sections: zod_1.z.array(zod_1.z.object({ title: zod_1.z.string() .min(1, 'Section title is required') .max(24, 'Section title cannot exceed 24 characters') .describe('Title of the section'), rows: zod_1.z.array(zod_1.z.object({ title: zod_1.z.string() .min(1, 'Row title is required') .max(24, 'Row title cannot exceed 24 characters') .describe('Title of the row'), description: zod_1.z.string() .max(72, 'Row description cannot exceed 72 characters') .optional() .describe('Optional description of the row'), rowId: zod_1.z.string() .min(1, 'Row ID is required') .max(200, 'Row ID cannot exceed 200 characters') .describe('Unique identifier for the row') })).min(1, 'Section must have at least 1 row') .max(10, 'Section cannot have more than 10 rows') .describe('Rows in the section') })).min(1, 'List must have at least 1 section') .max(10, 'List cannot have more than 10 sections') .describe('Sections of the list'), delay: zod_1.z.number() .min(0) .max(60000) .optional() .describe('Delay in milliseconds before sending (0-60000)') }), handler: this.sendListHandler.bind(this), examples: { usage: 'Send an interactive list with selectable options', parameters: { instance: 'my_whatsapp_bot', number: '5511999999999', title: 'Choose a Service', description: 'Please select one of the available services below:', buttonText: 'View Options', footerText: 'Powered by Evolution API', sections: [ { title: 'Main Services', rows: [ { title: 'Support', description: 'Get technical support', rowId: 'support_option' }, { title: 'Sales', description: 'Talk to sales team', rowId: 'sales_option' } ] } ], delay: 1000 } } }; } async sendListHandler(params) { try { const requestData = { number: params.number, title: params.title, description: params.description, buttonText: params.buttonText, sections: params.sections, ...(params.footerText && { footerText: params.footerText }), ...(params.delay && { delay: params.delay }) }; const response = await this.httpClient.post(`/message/sendList/${params.instance}`, requestData); if (!response.success) { return this.handleApiError(response.error, 'send list'); } const totalRows = params.sections.reduce((total, section) => total + section.rows.length, 0); return { success: true, data: { message: `Interactive list sent successfully to ${params.number}`, messageId: response.data?.key?.id, instance: params.instance, recipient: params.number, listTitle: params.title, sectionsCount: params.sections.length, totalOptions: totalRows, result: response.data } }; } catch (error) { return this.handleUnexpectedError(error, 'send list'); } } /** * Send interactive buttons */ createSendButtonTool() { const endpoint = message_endpoints_1.messageEndpoints.find(e => e.name === 'send-button'); return { name: 'evolution_send_button', description: 'Send interactive buttons to a WhatsApp number', controller: 'message', endpoint, schema: zod_1.z.object({ instance: zod_1.z.string() .min(1, 'Instance name is required') .describe('Name of the WhatsApp instance to send from'), number: zod_1.z.string() .min(10, 'Valid phone number is required') .regex(/^\d+$/, 'Phone number must contain only digits') .describe('Recipient phone number (format: 5511999999999)'), title: zod_1.z.string() .min(1, 'Message title is required') .max(1024, 'Title cannot exceed 1024 characters') .describe('Title of the button message'), description: zod_1.z.string() .min(1, 'Message description is required') .max(1024, 'Description cannot exceed 1024 characters') .describe('Description of the button message'), footer: zod_1.z.string() .max(60, 'Footer text cannot exceed 60 characters') .optional() .describe('Optional footer text'), buttons: zod_1.z.array(zod_1.z.object({ type: zod_1.z.literal('replyButton') .describe('Button type (must be "replyButton")'), reply: zod_1.z.object({ displayText: zod_1.z.string() .min(1, 'Button text is required') .max(20, 'Button text cannot exceed 20 characters') .describe('Text displayed on the button'), id: zod_1.z.string() .min(1, 'Button ID is required') .max(256, 'Button ID cannot exceed 256 characters') .describe('Unique identifier for the button') }).describe('Button reply configuration') })).min(1, 'Must have at least 1 button') .max(3, 'Cannot have more than 3 buttons') .describe('Array of interactive buttons'), delay: zod_1.z.number() .min(0) .max(60000) .optional() .describe('Delay in milliseconds before sending (0-60000)') }), handler: this.sendButtonHandler.bind(this), examples: { usage: 'Send interactive buttons for user selection', parameters: { instance: 'my_whatsapp_bot', number: '5511999999999', title: 'Choose an Option', description: 'Please select one of the options below:', footer: 'Powered by Evolution API', buttons: [ { type: 'replyButton', reply: { displayText: 'Yes', id: 'yes_button' } }, { type: 'replyButton', reply: { displayText: 'No', id: 'no_button' } } ], delay: 1000 } } }; } async sendButtonHandler(params) { try { const requestData = { number: params.number, title: params.title, description: params.description, buttons: params.buttons, ...(params.footer && { footer: params.footer }), ...(params.delay && { delay: params.delay }) }; const response = await this.httpClient.post(`/message/sendButtons/${params.instance}`, requestData); if (!response.success) { return this.handleApiError(response.error, 'send button'); } return { success: true, data: { message: `Interactive buttons sent successfully to ${params.number}`, messageId: response.data?.key?.id, instance: params.instance, recipient: params.number, buttonCount: params.buttons.length, buttonLabels: params.buttons.map((btn) => btn.reply.displayText), result: response.data } }; } catch (error) { return this.handleUnexpectedError(error, 'send button'); } } /** * Get all message controller tools */ getAllTools() { return [ this.createSendTextTool(), this.createSendMediaTool(), this.createSendAudioTool(), this.createSendStickerTool(), this.createSendLocationTool(), this.createSendContactTool(), this.createSendReactionTool(), this.createSendPollTool(), this.createSendListTool(), this.createSendButtonTool() ]; } /** * Detect media type from URL or base64 */ detectMediaType(media) { if (media.startsWith('data:')) { // Base64 data URL const mimeType = media.split(';')[0].split(':')[1]; if (mimeType.startsWith('image/')) return 'image'; if (mimeType.startsWith('video/')) return 'video'; if (mimeType.startsWith('audio/')) return 'audio'; return 'document'; } // URL - try to detect from extension const extension = media.split('.').pop()?.toLowerCase(); const imageExts = ['jpg', 'jpeg', 'png', 'gif', 'webp', 'bmp']; const videoExts = ['mp4', 'avi', 'mov', 'wmv', 'flv', 'webm']; const audioExts = ['mp3', 'wav', 'ogg', 'aac', 'm4a']; if (extension && imageExts.includes(extension)) return 'image'; if (extension && videoExts.includes(extension)) return 'video'; if (extension && audioExts.includes(extension)) return 'audio'; return 'document'; } /** * Handle API errors with user-friendly messages */ handleApiError(error, operation) { const baseMessage = `Failed to ${operation}`; switch (error.type) { case evolution_http_client_1.ErrorType.AUTHENTICATION_ERROR: return { success: false, error: { type: 'AUTHENTICATION_ERROR', message: `${baseMessage}: Authentication failed. Please check your Evolution API key.`, code: error.code, details: { suggestion: 'Verify that your EVOLUTION_API_KEY environment variable is set correctly', originalError: error.message } } }; case evolution_http_client_1.ErrorType.NETWORK_ERROR: return { success: false, error: { type: 'NETWORK_ERROR', message: `${baseMessage}: Network error occurred. Please check your connection to the Evolution API.`, code: error.code, details: { suggestion: 'Verify that your EVOLUTION_URL is correct and the API is accessible', originalError: error.message } } }; case evolution_http_client_1.ErrorType.TIMEOUT_ERROR: return { success: false, error: { type: 'TIMEOUT_ERROR', message: `${baseMessage}: Request timed out. The Evolution API did not respond in time.`, code: error.code, details: { suggestion: 'Try again in a few moments. If the problem persists, check the API server status', originalError: error.message } } }; case evolution_http_client_1.ErrorType.API_ERROR: // Handle specific API error codes if (error.statusCode === 404) { return { success: false, error: { type: 'API_ERROR', message: `${baseMessage}: Instance not found or endpoint not available.`, code: error.code, details: { suggestion: 'Check that the instance name is correct and that the instance exists', statusCode: error.statusCode, originalError: error.message } } }; } if (error.statusCode === 400) { return { success: false, error: { type: 'VALIDATION_ERROR', message: `${baseMessage}: Invalid parameters provided.`, code: error.code, details: { suggestion: 'Check the parameter values and format. Ensure phone numbers are in correct format (e.g., 5511999999999)', statusCode: error.statusCode, originalError: error.message, apiResponse: error.details } } }; } if (error.statusCode === 409) { return { success: false, error: { type: 'API_ERROR', message: `${baseMessage}: Conflict - instance may not be connected or ready.`, code: error.code, details: { suggestion: 'Ensure the instance is connected and authenticated with WhatsApp', statusCode: error.statusCode, originalError: error.message } } }; } return { success: false, error: { type: 'API_ERROR', message: `${baseMessage}: ${error.message}`, code: error.code, details: { statusCode: error.statusCode, originalError: error.message, apiResponse: error.details } } }; case evolution_http_client_1.ErrorType.RATE_LIMIT_ERROR: return { success: false, error: { type: 'RATE_LIMIT_ERROR', message: `${baseMessage}: Rate limit exceeded. Too many requests.`, code: error.code, details: { suggestion: 'Wait a moment before trying again', retryAfter: error.details?.retryAfter, originalError: error.message } } }; default: return { success: false, error: { type: 'UNKNOWN_ERROR', message: `${baseMessage}: ${error.message || 'Unknown error occurred'}`, code: error.code, details: { suggestion: 'Please try again or contact support if the problem persists', originalError: error } } }; } } /** * Handle unexpected errors */ handleUnexpectedError(error, operation) { const errorMessage = error instanceof Error ? error.message : 'Unknown error occurred'; return { success: false, error: { type: 'UNKNOWN_ERROR', message: `Failed to ${operation}: ${errorMessage}`, details: { suggestion: 'This is an unexpected error. Please try again or contact support.', originalError: error } } }; } } exports.MessageTools = MessageTools; // Export instance for use in tests and other modules exports.messageTools = new MessageTools(new evolution_http_client_1.EvolutionHttpClient({ baseURL: process.env.EVOLUTION_URL || 'http://localhost', apiKey: process.env.EVOLUTION_API_KEY || 'test-key', timeout: 30000 }));