import { NextResponse, type NextRequest } from "next/server"; import { fetchJson } from "@/lib/weather/http"; import { errorResponse, forbidCrossSite } from "@/lib/weather/respond"; import type { RadarFrame } from "@/lib/weather/types"; /** * GET /api/radar → RainViewer frames, oldest first, ready for Leaflet. * * RainViewer publishes an index of frames. Each frame's `path` is a hash, not a * timestamp, so tile URLs must always be built from this index — never guessed. * Docs: https://www.rainviewer.com/api/weather-maps-api.html */ interface RainViewerIndex { host: string; radar: { past: { time: number; path: string }[] }; } // Last 7 frames ≈ one hour. Keeps tile requests well under RainViewer's // limit of 100 requests per minute per IP. const FRAME_COUNT = 7; const COLOR_SCHEME = 2; // "Universal Blue", the only scheme still offered const OPTIONS = "1_1"; // smoothed, snow shown in its own colors export async function GET(request: NextRequest) { const blocked = forbidCrossSite(request); if (blocked) return blocked; try { const index = await fetchJson("https://api.rainviewer.com/public/weather-maps.json", "RainViewer", { cacheSeconds: 300, // new frames arrive every 10 minutes }); const frames: RadarFrame[] = index.radar.past.slice(-FRAME_COUNT).map((frame) => ({ time: new Date(frame.time * 1000).toISOString(), url: `${index.host}${frame.path}/256/{z}/{x}/{y}/${COLOR_SCHEME}/${OPTIONS}.png`, })); return NextResponse.json(frames); } catch (error) { return errorResponse(error); } }