// owm-stub — OpenWeatherMap stand-in for the e2e profile (AZ-456 AC-2). // Returns canned `/data/2.5/weather` responses keyed by lat,lon. A request log // is exposed at `/mock/log` for resilience tests; `/mock/config` swaps the // canned set without restarting the container. interface WindResponse { wind: { speed: number; deg: number } name: string coord: { lat: number; lon: number } } const PORT = Number(process.env.PORT ?? 8081) let cannedResponses: Record = { '0,0': { wind: { speed: 5.0, deg: 270 }, name: 'TestCity', coord: { lat: 0, lon: 0 } }, '50.45,30.52': { wind: { speed: 7.5, deg: 90 }, name: 'Kyiv', coord: { lat: 50.45, lon: 30.52 } }, } const requestLog: Array<{ ts: string; method: string; url: string }> = [] function key(lat: string | null, lon: string | null): string { return `${lat ?? '0'},${lon ?? '0'}` } const server = Bun.serve({ port: PORT, fetch(req) { const url = new URL(req.url) requestLog.push({ ts: new Date().toISOString(), method: req.method, url: url.pathname + url.search }) if (url.pathname === '/health') { return new Response('ok', { status: 200 }) } if (url.pathname === '/mock/log') { return Response.json(requestLog) } if (url.pathname === '/mock/config' && req.method === 'POST') { return req.json().then((body) => { cannedResponses = body as Record return new Response(null, { status: 204 }) }) } if (url.pathname === '/data/2.5/weather') { const lat = url.searchParams.get('lat') const lon = url.searchParams.get('lon') const k = key(lat, lon) const payload = cannedResponses[k] ?? cannedResponses['0,0'] return Response.json(payload) } return new Response('not found', { status: 404 }) }, }) console.log(`[owm-stub] listening on :${server.port}`)