UNPKG

evolution-api-sdk

Version:

Unofficial SDK for the Evolution Whatsapp API v2

1 lines 15.6 kB
{"version":3,"sources":["../../src/api/errors.ts","../../src/api/service.ts"],"sourcesContent":["export class EvolutionApiError extends Error {\n\tpublic readonly statusCode?: number;\n\tpublic readonly details?: unknown;\n\n\tconstructor(message: string, cause?: unknown, statusCode?: number) {\n\t\tconst extractedMessage = extractErrorMessage(cause);\n\t\tconst finalMessage = extractedMessage || message || \"Unknown error occurred\";\n\n\t\tsuper(finalMessage);\n\n\t\tthis.name = EvolutionApiError.name;\n\t\tthis.message = finalMessage;\n\t\tthis.statusCode = statusCode;\n\t\tthis.details = cause;\n\n\t\t// Maintain proper stack trace\n\t\tif (Error.captureStackTrace) {\n\t\t\tError.captureStackTrace(this, EvolutionApiError);\n\t\t}\n\t}\n\n\t/**\n\t * Returns a user-friendly string representation of the error\n\t */\n\ttoString(): string {\n\t\tlet result = `${this.name}: ${this.message}`;\n\t\t\n\t\tif (this.statusCode) {\n\t\t\tresult += ` (${this.statusCode})`;\n\t\t}\n\t\t\n\t\t// Add relevant details without showing [Object ...]\n\t\tif (this.details && typeof this.details === 'object') {\n\t\t\tconst details = this.details as Record<string, any>;\n\t\t\tconst relevantDetails: string[] = [];\n\t\t\t\n\t\t\tif (details.url) {\n\t\t\t\trelevantDetails.push(`URL: ${details.url}`);\n\t\t\t}\n\t\t\t\n\t\t\tif (details.method) {\n\t\t\t\trelevantDetails.push(`Method: ${details.method}`);\n\t\t\t}\n\t\t\t\n\t\t\t// Show response details if they exist and are meaningful\n\t\t\tif (details.response && typeof details.response === 'object') {\n\t\t\t\tconst response = details.response as Record<string, any>;\n\t\t\t\tif (response.error && response.error !== this.message) {\n\t\t\t\t\trelevantDetails.push(`Server Error: ${response.error}`);\n\t\t\t\t}\n\t\t\t\tif (response.message && response.message !== this.message) {\n\t\t\t\t\trelevantDetails.push(`Server Message: ${response.message}`);\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\tif (relevantDetails.length > 0) {\n\t\t\t\tresult += `\\n ${relevantDetails.join('\\n ')}`;\n\t\t\t}\n\t\t}\n\t\t\n\t\treturn result;\n\t}\n\n\t/**\n\t * Returns a JSON representation suitable for logging\n\t */\n\ttoJSON(): object {\n\t\treturn {\n\t\t\tname: this.name,\n\t\t\tmessage: this.message,\n\t\t\tstatusCode: this.statusCode,\n\t\t\tdetails: this.details,\n\t\t\tstack: this.stack,\n\t\t};\n\t}\n}\n\n/**\n * Extracts error message from various Evolution API error response formats\n */\nexport function extractErrorMessage(response: unknown): string | null {\n\tif (!response) {\n\t\treturn null;\n\t}\n\n\t// Handle string responses\n\tif (typeof response === \"string\") {\n\t\treturn response;\n\t}\n\n\t// Handle object responses\n\tif (typeof response === \"object\" && response !== null) {\n\t\tconst errorObj = response as Record<string, any>;\n\n\t\t// Try different common error message paths, prioritizing Evolution API format\n\t\tconst messagePaths = [\n\t\t\t// Evolution API specific nested structure (most common)\n\t\t\terrorObj.response?.response?.message?.[0],\n\t\t\terrorObj.response?.response?.error,\n\t\t\terrorObj.response?.response?.description,\n\t\t\t\n\t\t\t// Evolution API first level nested\n\t\t\tArray.isArray(errorObj.response?.message) ? errorObj.response.message[0] : null,\n\t\t\terrorObj.response?.error,\n\t\t\terrorObj.response?.description,\n\t\t\t\n\t\t\t// Direct error message\n\t\t\tArray.isArray(errorObj.message) ? errorObj.message[0] : errorObj.message,\n\t\t\terrorObj.error,\n\t\t\terrorObj.description,\n\t\t\terrorObj.detail,\n\t\t\t\n\t\t\t// Other nested error messages\n\t\t\terrorObj.data?.error,\n\t\t\terrorObj.data?.message,\n\t\t\t\n\t\t\t// Array format messages (fallback)\n\t\t\tArray.isArray(errorObj.error) ? errorObj.error[0] : null,\n\t\t\tArray.isArray(errorObj.errors) ? errorObj.errors[0] : null,\n\t\t];\n\n\t\tfor (const path of messagePaths) {\n\t\t\tif (typeof path === \"string\" && path.trim()) {\n\t\t\t\treturn path.trim();\n\t\t\t}\n\t\t\t// Handle nested objects in arrays\n\t\t\tif (typeof path === \"object\" && path !== null) {\n\t\t\t\tconst nestedMessage = extractErrorMessage(path);\n\t\t\t\tif (nestedMessage) {\n\t\t\t\t\treturn nestedMessage;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// Handle validation errors (common format)\n\t\tif (errorObj.validation && Array.isArray(errorObj.validation)) {\n\t\t\tconst validationErrors = errorObj.validation\n\t\t\t\t.map((v: any) => v.message || v.error || String(v))\n\t\t\t\t.filter(Boolean)\n\t\t\t\t.join(\", \");\n\t\t\tif (validationErrors) {\n\t\t\t\treturn `Validation error: ${validationErrors}`;\n\t\t\t}\n\t\t}\n\n\t\t// Handle specific Evolution API error patterns\n\t\tif (errorObj.statusCode && errorObj.statusText) {\n\t\t\treturn `${errorObj.statusCode}: ${errorObj.statusText}`;\n\t\t}\n\n\t\t// Last resort: try to stringify the object meaningfully\n\t\tif (Object.keys(errorObj).length > 0) {\n\t\t\ttry {\n\t\t\t\treturn JSON.stringify(errorObj);\n\t\t\t} catch {\n\t\t\t\treturn \"[Complex error object]\";\n\t\t\t}\n\t\t}\n\t}\n\n\treturn null;\n}\n\n/**\n * Legacy error message patterns for specific Evolution API errors\n * Kept for backward compatibility\n */\nconst SpecificErrorPatterns = [\n\t{\n\t\tpattern: (obj: any) => \n\t\t\tobj?.message?.some?.((m: any) => m?.exists === false && m?.jid && m?.number),\n\t\tmessage: \"Provided number is not a valid WhatsApp number\"\n\t},\n\t{\n\t\tpattern: (obj: any) => \n\t\t\tobj?.message?.some?.((m: string) => typeof m === \"string\" && m.includes(\"Media upload failed\")),\n\t\tmessage: \"Media upload failed on all hosts\"\n\t},\n\t{\n\t\tpattern: (obj: any) => \n\t\t\tobj?.message?.some?.((m: string) => typeof m === \"string\" && m.includes(\"No session\")),\n\t\tmessage: \"No session found, try restarting your instance\"\n\t},\n\t{\n\t\tpattern: (obj: any) => \n\t\t\tobj?.message?.some?.((m: string) => typeof m === \"string\" && m.includes(\"AggregateError\")),\n\t\tmessage: \"Connection error occurred\"\n\t},\n\t{\n\t\tpattern: (obj: any) => \n\t\t\tobj?.message?.some?.((m: string) => typeof m === \"string\" && m.includes(\"AxiosError\")),\n\t\tmessage: (obj: any) => obj.message[0] || \"Network error occurred\"\n\t},\n];\n\n/**\n * Enhanced error message extraction with specific pattern matching\n */\nfunction getErrorMessage(response: unknown): string | null {\n\t// First try the general extraction\n\tconst generalMessage = extractErrorMessage(response);\n\tif (generalMessage) {\n\t\treturn generalMessage;\n\t}\n\n\t// Then try specific patterns\n\tif (typeof response === \"object\" && response !== null) {\n\t\tfor (const { pattern, message } of SpecificErrorPatterns) {\n\t\t\ttry {\n\t\t\t\tif (pattern(response)) {\n\t\t\t\t\treturn typeof message === \"string\" ? message : message(response);\n\t\t\t\t}\n\t\t\t} catch {\n\t\t\t\t// Continue to next pattern if this one fails\n\t\t\t}\n\t\t}\n\t}\n\n\treturn null;\n}\n","import type { ClientOptions } from \"@/schemas/client\";\nimport type { APIRequestInit } from \"@/types/api\";\n\nimport { EvolutionApiError, extractErrorMessage } from \"./errors\";\n\nexport class ApiService {\n constructor(private options: ClientOptions) {}\n\n setInstance(instance: string) {\n this.options.instance = instance;\n }\n\n async request<T = unknown>(\n path: string,\n options: APIRequestInit = {}\n ): Promise<T> {\n const { isInstanceUrl = true } = options;\n let instance = this.options.instance;\n\n // Priority: options.instance > this.options.instance\n if (options.instance) {\n instance = options.instance;\n delete options.instance;\n }\n\n if (isInstanceUrl && !instance) {\n throw new EvolutionApiError(\"Instance not set\", {\n message:\n \"Please set the instance before making a request or pass instance in the method options.\",\n });\n }\n\n const { init, params } = this.makeInit(options);\n\n const urlPath = isInstanceUrl ? `/${path}/${instance}/` : `/${path}/`;\n const url = new URL(urlPath, this.options.serverUrl);\n\n // Add query parameters if any\n if (params.toString()) {\n url.search = params.toString();\n }\n\n let response: Response;\n let data: any;\n\n try {\n response = await fetch(url, init);\n data = await response.json();\n } catch (error) {\n // Handle network errors or JSON parsing errors\n throw new EvolutionApiError(\"Network or parsing error\", error);\n }\n\n if (!response.ok) {\n // Extract meaningful error message from the response\n const errorMessage =\n extractErrorMessage(data) ||\n `Request failed with status ${response.status}: ${response.statusText}`;\n\n throw new EvolutionApiError(\n errorMessage,\n {\n message: errorMessage,\n response: JSON.stringify(data),\n url: url.toString(),\n params: params.toString(),\n body: JSON.stringify(options.body),\n } as unknown as Record<string, any>,\n response.status\n );\n }\n\n return data;\n }\n\n private makeInit(options: APIRequestInit): {\n init: RequestInit;\n params: URLSearchParams;\n } {\n const init: RequestInit = {\n method: options.method || \"GET\",\n headers: {\n \"Content-Type\": \"application/json\",\n apikey: this.options.token, // Evolution API uses apikey header\n ...this.options.headers,\n ...options.headers,\n },\n };\n\n if (options.body) {\n init.body = JSON.stringify(options.body);\n }\n\n const params = new URLSearchParams();\n if (options.params) {\n // Convert any object to URLSearchParams\n Object.entries(options.params).forEach(([key, value]) => {\n if (value !== undefined && value !== null) {\n params.append(key, String(value));\n }\n });\n }\n\n return { init, params };\n }\n\n async get<T = unknown>(\n path: string,\n options: Omit<APIRequestInit, \"method\"> = {}\n ): Promise<T> {\n return this.request<T>(path, { ...options, method: \"GET\" });\n }\n\n async post<T = unknown>(\n path: string,\n options: Omit<APIRequestInit, \"method\"> = {}\n ): Promise<T> {\n return this.request<T>(path, { ...options, method: \"POST\" });\n }\n\n async put<T = unknown>(\n path: string,\n options: Omit<APIRequestInit, \"method\"> = {}\n ): Promise<T> {\n return this.request<T>(path, { ...options, method: \"PUT\" });\n }\n\n async patch<T = unknown>(\n path: string,\n options: Omit<APIRequestInit, \"method\"> = {}\n ): Promise<T> {\n return this.request<T>(path, { ...options, method: \"PATCH\" });\n }\n\n async delete<T = unknown>(\n path: string,\n options: Omit<APIRequestInit, \"method\"> = {}\n ): Promise<T> {\n return this.request<T>(path, { ...options, method: \"DELETE\" });\n }\n}\n"],"mappings":"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","names":[]}