// Fetch real Bengaluru roads (primary/secondary/trunk/tertiary) ONCE from the // OpenStreetMap Overpass API and cache them as a static GeoJSON FeatureCollection // of LineStrings, so the runtime never depends on the flaky public Overpass // instance. Writes to public/ (fetchable) and src/data/ (bundled import). // // Run: node scripts/build-roads.mjs import { writeFileSync, mkdirSync } from 'fs' const OVERPASS_ENDPOINTS = [ 'https://overpass-api.de/api/interpreter', 'https://overpass.kumi.systems/api/interpreter', 'https://maps.mail.ru/osm/tools/overpass/api/interpreter', ] // Bengaluru bbox (south, west, north, east). const QUERY = 'data=[out:json][timeout:60];way["highway"~"primary|secondary|trunk|tertiary"](12.85,77.48,13.08,77.72);out geom;' function widthForHighway(highway) { switch (highway) { case 'trunk': case 'primary': return 14 case 'secondary': return 9 case 'tertiary': return 8 default: return 8 } } async function fetchRoads() { let lastErr for (const url of OVERPASS_ENDPOINTS) { try { console.log(`Fetching roads from ${url} ...`) const res = await fetch(url, { method: 'POST', headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, body: QUERY, }) console.log(` → HTTP ${res.status}`) if (!res.ok) { lastErr = new Error(`Overpass HTTP ${res.status} @ ${url}`) continue } const json = await res.json() const ways = (json.elements ?? []).filter( (w) => w.type === 'way' && Array.isArray(w.geometry) && w.geometry.length >= 2, ) console.log(` → ${ways.length} ways returned`) return ways } catch (err) { console.warn(` → failed: ${err.message}`) lastErr = err } } throw lastErr ?? new Error('All Overpass endpoints failed') } const ways = await fetchRoads() const features = ways.map((way) => { const highway = way.tags?.highway ?? 'road' return { type: 'Feature', properties: { id: way.id, name: way.tags?.name ?? way.tags?.ref ?? 'Unnamed road', highway, widthMeters: widthForHighway(highway), }, geometry: { type: 'LineString', // GeoJSON order is [lng, lat]. coordinates: way.geometry.map((p) => [p.lon, p.lat]), }, } }) const fc = { type: 'FeatureCollection', features } // Sanity print: first 3 segments' first coordinate. for (let i = 0; i < Math.min(3, features.length); i++) { console.log( `sample ${i}: ${features[i].properties.name} first=[${features[i].geometry.coordinates[0].join(', ')}]`, ) } mkdirSync('public', { recursive: true }) writeFileSync('public/bengaluru-roads.geojson', JSON.stringify(fc)) writeFileSync('src/data/bengaluru-roads.geojson', JSON.stringify(fc)) console.log(`Wrote ${features.length} road features.`)