export interface GeoInfo { ip: string | null; city: string | null; region: string | null; country: string | null; } /** * Extract geolocation info from request headers * Supports Cloudflare headers in production, falls back to standard headers * @param headers - Request headers * @returns Geolocation information extracted from headers */ export const getGeoInfo = (headers: Headers): GeoInfo => { // Try Cloudflare headers first (production) const cfIP = headers.get("CF-Connecting-IP"); const cfCountry = headers.get("CF-IPCountry"); const cfCity = headers.get("CF-IPCity"); const cfRegion = headers.get("CF-Region"); // Fallback to X-Forwarded-For or X-Real-IP const forwardedFor = headers.get("X-Forwarded-For"); const realIP = headers.get("X-Real-IP"); const ip = cfIP ?? realIP ?? forwardedFor?.split(",")[0]?.trim() ?? null; return { ip, city: cfCity ?? null, region: cfRegion ?? null, country: cfCountry ?? null, }; }; /** * Extract User-Agent from request headers * @param headers - Request headers * @returns User-Agent string or "Unknown" if not present */ export const getUserAgent = (headers: Headers): string => { return headers.get("User-Agent") ?? "Unknown"; };