// Webhook receiver for external integrations // Path: /webhook addEventListener('fetch', event => { event.respondWith(handleRequest(event.request)) }) async function handleRequest(request) { const corsHeaders = { 'Access-Control-Allow-Origin': '*', 'Access-Control-Allow-Methods': 'GET, POST, OPTIONS', 'Access-Control-Allow-Headers': 'Content-Type, Authorization, X-Webhook-Secret', } if (request.method === 'OPTIONS') { return new Response(null, { headers: corsHeaders }) } const url = new URL(request.url) const path = url.pathname // Log incoming webhook const logEntry = { timestamp: new Date().toISOString(), method: request.method, path: path, headers: Object.fromEntries(request.headers.entries()), query: Object.fromEntries(url.searchParams.entries()) } if (request.method === 'POST') { try { const contentType = request.headers.get('content-type') || '' let payload if (contentType.includes('application/json')) { payload = await request.json() } else if (contentType.includes('form')) { payload = Object.fromEntries(await request.formData()) } else { payload = await request.text() } logEntry.payload = payload // Route based on webhook type/source const source = url.searchParams.get('source') || 'unknown' // Forward to appropriate n8n workflow based on source const webhookMap = { 'gitea': 'https://n8n.mylder.io/webhook/gitea-event', 'stripe': 'https://n8n.mylder.io/webhook/stripe-event', 'supabase': 'https://n8n.mylder.io/webhook/supabase-event', 'default': 'https://n8n.mylder.io/webhook/generic-event' } const targetUrl = webhookMap[source] || webhookMap['default'] // Async forward (fire and forget for speed) fetch(targetUrl, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ source, payload, received_at: logEntry.timestamp, headers: logEntry.headers }) }).catch(err => console.error('Forward failed:', err)) return new Response(JSON.stringify({ received: true, source, timestamp: logEntry.timestamp }), { headers: { 'Content-Type': 'application/json', ...corsHeaders } }) } catch (error) { return new Response(JSON.stringify({ received: false, error: error.message }), { status: 400, headers: { 'Content-Type': 'application/json', ...corsHeaders } }) } } // GET request - return webhook info return new Response(JSON.stringify({ endpoint: '/webhook', method: 'POST', supported_sources: ['gitea', 'stripe', 'supabase', 'default'], usage: 'POST /webhook?source=gitea with JSON body' }), { headers: { 'Content-Type': 'application/json', ...corsHeaders } }) }