const VALHALLA_BASE = process.env.VALHALLA_URL ?? "http://valhalla:8002"; export type ValhallaCosting = "pedestrian" | "bicycle" | "auto"; const COSTING_MAP: Record = { walking: "pedestrian", cycling: "bicycle", driving: "auto", }; export interface IsochroneOpts { lng: number; lat: number; travelMode: string; contourMinutes: number[]; polygons?: boolean; } export async function fetchIsochrone(opts: IsochroneOpts): Promise { const costing = COSTING_MAP[opts.travelMode] ?? "pedestrian"; const body = { locations: [{ lon: opts.lng, lat: opts.lat }], costing, contours: opts.contourMinutes.map((time) => ({ time })), polygons: opts.polygons ?? true, show_locations: false, }; const res = await fetch(`${VALHALLA_BASE}/isochrone`, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify(body), signal: AbortSignal.timeout(30_000), }); if (!res.ok) { const text = await res.text(); throw new Error(`Valhalla error ${res.status}: ${text}`); } return res.json(); } export async function checkValhalla(): Promise { try { const res = await fetch(`${VALHALLA_BASE}/status`, { signal: AbortSignal.timeout(3000), }); return res.ok; } catch { return false; } }