JavaScript 56.7%
TypeScript 42.6%
1export interface GeoInfo {2 country: string;3 city: string;4}56const LOCAL_IPS = new Set(["127.0.0.1", "::1", "localhost"]);78function isLocalIp(ip: string): boolean {9 if (LOCAL_IPS.has(ip)) return true;10 if (ip.startsWith("192.168.") || ip.startsWith("10.") || ip.startsWith("172.")) return true;11 return false;12}1314export async function getGeoFromIp(ip: string): Promise<GeoInfo> {15 // Strip port if present (e.g. "::ffff:1.2.3.4")16 const cleanIp = ip.replace(/^::ffff:/, "").split(",")[0].trim();1718 if (isLocalIp(cleanIp)) {19 return { country: "Réseau local", city: "" };20 }2122 try {23 const res = await fetch(24 `http://ip-api.com/json/${encodeURIComponent(cleanIp)}?fields=status,country,city&lang=fr`,25 { signal: AbortSignal.timeout(3000) }26 );27 if (!res.ok) throw new Error("HTTP error");28 const data = await res.json();29 if (data.status === "success") {30 return { country: data.country || "", city: data.city || "" };31 }32 } catch {33 // Geo lookup failed — non-blocking34 }3536 return { country: "", city: "" };37}38