// server/cloudflare-worker/src/index.ts // D3RO Voice — Global Cloudflare Edge Gateway & Proxy Worker export interface Env { BACKEND_ORIGIN: string SERVICE_NAME?: string } const CORS_HEADERS: Record = { 'Access-Control-Allow-Origin': '*', 'Access-Control-Allow-Methods': 'GET, POST, PUT, DELETE, PATCH, OPTIONS', 'Access-Control-Allow-Headers': 'Content-Type, Authorization, X-Requested-With, Range', 'Access-Control-Expose-Headers': 'Content-Length, Content-Range, X-D3RO-Status', 'Access-Control-Max-Age': '86400', } export default { async fetch(request: Request, env: Env, _ctx: ExecutionContext): Promise { const url = new URL(request.url) // 1. Handle CORS Preflight (OPTIONS) if (request.method === 'OPTIONS') { return new Response(null, { status: 204, headers: CORS_HEADERS, }) } // 2. Edge Health Check Ping (/worker-health) if (url.pathname === '/worker-health') { return new Response( JSON.stringify({ status: 'Healthy', worker: env.SERVICE_NAME ?? 'D3RO Voice Edge Worker', backendOrigin: env.BACKEND_ORIGIN, timestamp: new Date().toISOString(), region: request.cf?.colo ?? 'global', }), { headers: { 'Content-Type': 'application/json', ...CORS_HEADERS, }, } ) } // 3. Construct Target Backend URL const backendOrigin = (env.BACKEND_ORIGIN || 'https://d3ro.chanpaca.net').replace(/\/$/, '') const targetUrl = new URL(`${url.pathname}${url.search}`, backendOrigin) // Forward Headers const forwardHeaders = new Headers(request.headers) forwardHeaders.set('X-Forwarded-Host', url.host) forwardHeaders.set('X-Forwarded-Proto', url.protocol.replace(':', '')) forwardHeaders.set('X-D3RO-Edge-Proxy', 'Cloudflare-Worker') try { const response = await fetch(targetUrl.toString(), { method: request.method, headers: forwardHeaders, body: request.method !== 'GET' && request.method !== 'HEAD' ? request.body : undefined, redirect: 'follow', }) // Clone response headers and attach CORS const newHeaders = new Headers(response.headers) for (const [key, value] of Object.entries(CORS_HEADERS)) { newHeaders.set(key, value) } return new Response(response.body, { status: response.status, statusText: response.statusText, headers: newHeaders, }) } catch (err: unknown) { const errorMessage = err instanceof Error ? err.message : String(err) return new Response( JSON.stringify({ error: 'EdgeGatewayError', message: `Unable to connect to origin NAS backend: ${errorMessage}`, targetUrl: targetUrl.toString(), timestamp: new Date().toISOString(), }), { status: 502, headers: { 'Content-Type': 'application/json', ...CORS_HEADERS, }, } ) } }, }