Dashboard-Automatizase/lib/evolutionapi.ts
Luis Erlacher 0152a2fda0 feat: add n8n API testing script for Google OAuth2 schema and existing credentials
- Implemented a bash script to test n8n API and retrieve credential schemas.
- Added types for API responses, Google Calendar, and WhatsApp instances.
- Configured Vitest for testing with React and added setup for testing-library.
2025-10-10 14:29:02 -03:00

194 lines
5.3 KiB
TypeScript

/**
* EvolutionAPI Client
* Integração com EvolutionAPI v2 para gerenciamento de instâncias WhatsApp
* Documentação: https://doc.evolution-api.com/v2/
*/
import type {
ConnectionStateAPIResponse,
InstanceStatus,
LogoutResponse,
QRCodeResponse,
} from "@/types/whatsapp";
// Re-export InstanceStatus for convenience
export type { InstanceStatus } from "@/types/whatsapp";
const EVOLUTION_API_URL = process.env.EVOLUTION_API_URL ?? "";
const EVOLUTION_API_KEY = process.env.EVOLUTION_API_KEY ?? "";
/**
* Get list of instance names from env
* Parse EVOLUTION_INSTANCE_NAMES (comma-separated) into array
*/
export function getInstanceNames(): string[] {
const names = process.env.EVOLUTION_INSTANCE_NAMES || "";
return names
.split(",")
.map((n) => n.trim())
.filter(Boolean);
}
/**
* Get status of a specific instance
* Endpoint: GET /instance/connectionState/{instance}
* Doc: https://doc.evolution-api.com/v2/api-reference/instance-controller/connection-state
*/
export async function getInstanceStatus(
instanceName: string,
): Promise<InstanceStatus> {
try {
console.log(`[EvolutionAPI] Fetching status for instance: ${instanceName}`);
const response = await fetch(
`${EVOLUTION_API_URL}/instance/connectionState/${encodeURIComponent(instanceName)}`,
{
method: "GET",
headers: {
apikey: EVOLUTION_API_KEY,
"Content-Type": "application/json",
},
},
);
if (!response.ok) {
if (response.status === 404) {
throw new Error(`Instance "${instanceName}" does not exist`);
}
throw new Error(`API returned ${response.status}`);
}
const data: ConnectionStateAPIResponse = await response.json();
console.log(`[EvolutionAPI] Status response:`, data);
// Mapear estado da API para nosso formato
// Estados possíveis: "open", "close", etc
const status =
data.instance.state === "open" ? "connected" : "disconnected";
return {
instance: instanceName,
status,
};
} catch (error) {
const errorMessage =
error instanceof Error ? error.message : "Unknown error";
console.error(
`[EvolutionAPI] Error fetching status for ${instanceName}:`,
error,
);
return {
instance: instanceName,
status: "error",
error: errorMessage,
};
}
}
/**
* Get status for all instances
*/
export async function getAllInstancesStatus(): Promise<InstanceStatus[]> {
const instances = getInstanceNames();
const promises = instances.map((name) => getInstanceStatus(name));
return Promise.all(promises);
}
/**
* Generate pairing code for instance connection
* Endpoint: GET /instance/connect/{instance}
* Doc: https://doc.evolution-api.com/v2/api-reference/instance-controller/instance-connect
*
* @param instanceName Nome da instância
* @param phoneNumber Número de telefone com código do país (opcional)
* @returns QRCodeResponse com pairingCode, code e count
*/
export async function generateQRCode(
instanceName: string,
phoneNumber?: string,
): Promise<QRCodeResponse> {
try {
console.log(
`[EvolutionAPI] Generating QR code for instance: ${instanceName}`,
);
const url = new URL(
`${EVOLUTION_API_URL}/instance/connect/${encodeURIComponent(instanceName)}`,
);
if (phoneNumber) {
url.searchParams.append("number", phoneNumber);
}
const response = await fetch(url.toString(), {
method: "GET",
headers: {
apikey: EVOLUTION_API_KEY,
"Content-Type": "application/json",
},
});
if (!response.ok) {
if (response.status === 404) {
throw new Error(`Instance "${instanceName}" does not exist`);
}
throw new Error(`API returned ${response.status}`);
}
const data = await response.json();
console.log(`[EvolutionAPI] QR code response:`, data);
return {
pairingCode: data.pairingCode,
code: data.code,
count: data.count,
base64: data.base64,
qrcode: data.qrcode,
instance: instanceName,
};
} catch (error) {
console.error(
`[EvolutionAPI] Error generating QR code for ${instanceName}:`,
error,
);
throw error;
}
}
/**
* Disconnect instance (logout)
* Endpoint: DELETE /instance/logout/{instance}
* Doc: https://doc.evolution-api.com/v2/api-reference/instance-controller/logout-instance
*/
export async function disconnectInstance(instanceName: string): Promise<void> {
try {
console.log(`[EvolutionAPI] Disconnecting instance: ${instanceName}`);
const response = await fetch(
`${EVOLUTION_API_URL}/instance/logout/${encodeURIComponent(instanceName)}`,
{
method: "DELETE",
headers: {
apikey: EVOLUTION_API_KEY,
"Content-Type": "application/json",
},
},
);
if (!response.ok) {
if (response.status === 404) {
throw new Error(`Instance "${instanceName}" does not exist`);
}
throw new Error(`API returned ${response.status}`);
}
const data: LogoutResponse = await response.json();
console.log(
`[EvolutionAPI] Instance ${instanceName} disconnected:`,
data.response.message,
);
} catch (error) {
console.error(`[EvolutionAPI] Error disconnecting ${instanceName}:`, error);
throw error;
}
}