spb/datacenterindex
Public
HTML 53.9%
TypeScript 44.5%
JavaScript 0.6%
SQL 0.5%
1import { readFileSync, existsSync } from "node:fs";2import { dirname, join } from "node:path";3import { fileURLToPath } from "node:url";45/**6 * Offline point-in-country lookup (Natural Earth 1:50m admin-0, public domain) — used when a source publishes7 * coordinates but no country (OpenStreetMap features rarely carry addr:country). Deterministic, no network.8 */9type Ring = number[][];10interface Feat { iso2: string; bbox: [number, number, number, number]; polys: Ring[][] }11let feats: Feat[] | null = null;1213function load(): Feat[] {14 if (feats) return feats;15 const here = dirname(fileURLToPath(import.meta.url));16 const candidates = [join(here, "..", "..", "data", "ne_50m_admin_0_countries.geojson"), join(process.cwd(), "apps", "worker", "data", "ne_50m_admin_0_countries.geojson"), join(process.cwd(), "data", "ne_50m_admin_0_countries.geojson")];17 const file = candidates.find((f) => existsSync(f));18 if (!file) { feats = []; return feats; }19 const gj = JSON.parse(readFileSync(file, "utf8")) as { features: Array<{ properties: Record<string, unknown>; geometry: { type: string; coordinates: unknown } }> };20 const out: Feat[] = [];21 for (const f of gj.features) {22 const p = f.properties;23 let iso2 = String(p.ISO_A2_EH ?? p.ISO_A2 ?? "-99");24 if (iso2 === "-99") { const a = String(p.ADM0_A3 ?? ""); iso2 = ({ FRA: "FR", NOR: "NO", KOS: "XK", SDS: "SS", SOL: "SO" } as Record<string, string>)[a] ?? "-99"; }25 if (!/^[A-Z]{2}$/.test(iso2)) continue;26 const polys: Ring[][] = f.geometry.type === "Polygon" ? [f.geometry.coordinates as Ring[]] : f.geometry.type === "MultiPolygon" ? (f.geometry.coordinates as Ring[][]) : [];27 let minX = 180, minY = 90, maxX = -180, maxY = -90;28 for (const poly of polys) for (const [x, y] of poly[0] ?? []) { if (x! < minX) minX = x!; if (x! > maxX) maxX = x!; if (y! < minY) minY = y!; if (y! > maxY) maxY = y!; }29 out.push({ iso2, bbox: [minX, minY, maxX, maxY], polys });30 }31 feats = out;32 return feats;33}3435function inRing(x: number, y: number, ring: Ring): boolean {36 let inside = false;37 for (let i = 0, j = ring.length - 1; i < ring.length; j = i++) {38 const xi = ring[i]![0]!, yi = ring[i]![1]!, xj = ring[j]![0]!, yj = ring[j]![1]!;39 if (yi > y !== yj > y && x < ((xj - xi) * (y - yi)) / (yj - yi) + xi) inside = !inside;40 }41 return inside;42}4344/** ISO-2 of the country containing the point, or null (ocean / unknown). Handles holes. */45export function countryFromPoint(lat: number, lng: number): string | null {46 if (!Number.isFinite(lat) || !Number.isFinite(lng)) return null;47 for (const f of load()) {48 const [minX, minY, maxX, maxY] = f.bbox;49 if (lng < minX || lng > maxX || lat < minY || lat > maxY) continue;50 for (const poly of f.polys) {51 if (!poly[0] || !inRing(lng, lat, poly[0])) continue;52 let hole = false;53 for (let k = 1; k < poly.length; k++) if (inRing(lng, lat, poly[k]!)) { hole = true; break; }54 if (!hole) return f.iso2;55 }56 }57 return null;58}59