import { Bun } from 'bun'; import { CommandService } from './services/command'; import { ResponseQueue } from './services/response-queue'; const PORT = 3007; type WebhookPayload = { event: string; instance: string; data: any; // Other fields from Evolution API }; export class WebhookServer { static async handleRequest(request: Request): Promise { // 1. Method validation if (request.method !== 'POST') { return new Response('Method not allowed', { status: 405 }); } // 2. Content-Type validation const contentType = request.headers.get('content-type'); if (!contentType?.includes('application/json')) { return new Response('Invalid content type', { status: 400 }); } try { // 3. Parse and validate payload const payload = await request.json() as WebhookPayload; if (!payload.event || !payload.instance) { return new Response('Invalid payload', { status: 400 }); } // 4. Verify instance matches if (payload.instance !== process.env.INSTANCE_NAME) { return new Response('Invalid instance', { status: 403 }); } // 5. Route events switch (payload.event) { case 'messages.upsert': await this.handleMessageUpsert(payload.data); break; // Other events will be added later } return new Response('OK', { status: 200 }); } catch (error) { return new Response('Invalid request', { status: 400 }); } } private static async handleMessageUpsert(data: any) { // Basic message validation if (!data?.key?.remoteJid || !data.message) return; // Forward to command service if applicable const messageText = data.message.conversation; if (messageText?.startsWith('/tarea')) { const responses = await CommandService.handle({ sender: data.key.participant, groupId: data.key.remoteJid, message: messageText, mentions: data.contextInfo?.mentionedJid || [] }); // Queue responses for sending await ResponseQueue.add(responses); } } } static start() { if (process.env.NODE_ENV !== 'test') { const server = Bun.serve({ port: PORT, fetch: WebhookServer.handleRequest, }); console.log(`Server running on port ${PORT}`); return server; } }