{"version":3,"file":"routing.cjs","names":[],"sources":["../../src/geo/routing.ts"],"sourcesContent":["import { durationFactor } from \"./estimate\";\nimport type { Coordinate, TravelEstimate, TravelMode } from \"./types\";\n\n/**\n * Pluggable routing backend. A backend turns two coordinates into a\n * {@link TravelEstimate}. Mirrors the `RoutingBackend` protocol from\n * `tempest-fastapi-sdk` so client and server share the same contract.\n *\n * Implement this to route against your own self-hosted engine (OSRM, Valhalla,\n * GraphHopper). The offline {@link estimateTravel} heuristic satisfies the same\n * shape without any network.\n */\nexport interface RoutingBackend {\n    route: (\n        origin: Coordinate,\n        destination: Coordinate,\n        options?: { mode?: TravelMode },\n    ) => Promise<TravelEstimate>;\n}\n\n/** Options for {@link createOSRMBackend}. */\nexport interface OSRMBackendOptions {\n    /**\n     * Base URL of an **OSRM** HTTP server. There is no default on purpose — this\n     * SDK ships no external endpoint. Point it at a routing engine **you host**.\n     */\n    baseUrl: string;\n    /** `fetch` implementation. Default: the global `fetch`. */\n    fetch?: typeof globalThis.fetch;\n    /** Per-mode duration multipliers applied over the car profile. */\n    modeDurationFactors?: Partial<Record<TravelMode, number>>;\n}\n\ninterface OSRMRoute {\n    distance: number;\n    duration: number;\n}\n\ninterface OSRMResponse {\n    code?: string;\n    routes?: OSRMRoute[];\n}\n\n/**\n * Build a {@link RoutingBackend} backed by an OSRM server **you host**. OSRM\n * only serves a driving profile, so motorcycle/bus durations are derived by\n * scaling the car duration through {@link durationFactor} — same approach as\n * the FastAPI SDK's `OSRMBackend`.\n *\n * !!! warning\n *     This makes a network request to `baseUrl`. It is opt-in: nothing in the\n *     SDK calls it unless you construct it and pass your own server URL. For a\n *     zero-network estimate, use {@link estimateTravel} instead.\n *\n * @param options - Server URL, optional `fetch`, per-mode factors.\n * @returns A backend whose `route()` queries OSRM.\n *\n * @example\n * const backend = createOSRMBackend({ baseUrl: \"https://osrm.internal\" });\n * const estimate = await backend.route(origin, destination, { mode: \"car\" });\n */\nexport function createOSRMBackend(options: OSRMBackendOptions): RoutingBackend {\n    const { baseUrl, fetch = globalThis.fetch, modeDurationFactors } = options;\n    const trimmedBaseUrl = baseUrl.replace(/\\/+$/, \"\");\n\n    return {\n        async route(origin, destination, routeOptions = {}): Promise<TravelEstimate> {\n            const mode = routeOptions.mode ?? \"car\";\n            const coords = `${origin.longitude},${origin.latitude};${destination.longitude},${destination.latitude}`;\n            const url = `${trimmedBaseUrl}/route/v1/driving/${coords}?overview=false`;\n\n            let payload: OSRMResponse;\n            try {\n                const response = await fetch(url);\n                payload = (await response.json()) as OSRMResponse;\n            } catch (cause) {\n                throw new Error(`OSRM request failed: ${String(cause)}`, { cause });\n            }\n\n            const route = payload.routes?.[0];\n            if (payload.code !== \"Ok\" || !route) {\n                throw new Error(`OSRM returned no route (code: ${payload.code ?? \"unknown\"})`);\n            }\n\n            const distanceKm = route.distance / 1000.0;\n            const carMinutes = route.duration / 60.0;\n            const durationMinutes = carMinutes * durationFactor(mode, modeDurationFactors);\n\n            return {\n                mode,\n                distance_km: distanceKm,\n                duration_minutes: durationMinutes,\n                source: \"osrm\",\n            };\n        },\n    };\n}\n"],"mappings":"kCA6DA,SAAgB,EAAkB,EAA6C,CAC3E,GAAM,CAAE,UAAS,QAAQ,WAAW,MAAO,uBAAwB,EAC7D,EAAiB,EAAQ,QAAQ,OAAQ,EAAE,EAEjD,MAAO,CACH,MAAM,MAAM,EAAQ,EAAa,EAAe,CAAC,EAA4B,CACzE,IAAM,EAAO,EAAa,MAAQ,MAC5B,EAAS,GAAG,EAAO,UAAU,GAAG,EAAO,SAAS,GAAG,EAAY,UAAU,GAAG,EAAY,WACxF,EAAM,GAAG,EAAe,oBAAoB,EAAO,iBAErD,EACJ,GAAI,CAEA,EAAW,MAAM,MADM,EAAM,CAAG,EAAA,CACN,KAAK,CACnC,OAAS,EAAO,CACZ,MAAU,MAAM,wBAAwB,OAAO,CAAK,IAAK,CAAE,OAAM,CAAC,CACtE,CAEA,IAAM,EAAQ,EAAQ,SAAS,GAC/B,GAAI,EAAQ,OAAS,MAAQ,CAAC,EAC1B,MAAU,MAAM,iCAAiC,EAAQ,MAAQ,UAAU,EAAE,EAOjF,MAAO,CACH,OACA,YANe,EAAM,SAAW,IAOhC,iBANe,EAAM,SAAW,GACC,EAAA,eAAe,EAAM,CAAmB,EAMzE,OAAQ,MACZ,CACJ,CACJ,CACJ"}