TypeScript 61.9%
HTML 37.2%
SQL 0.7%
1import 'server-only';2import { headers } from 'next/headers';34export async function clientInfo(): Promise<{ ip: string | null; userAgent: string | null }> {5 const h = await headers();6 const xff = h.get('x-forwarded-for');7 const ip = (xff ? xff.split(',').pop()?.trim() : null) ?? h.get('x-real-ip') ?? null;8 const userAgent = h.get('user-agent')?.slice(0, 200) ?? null;9 return { ip, userAgent };10}1112/** Short device label from a user agent, for security lists. */13export function deviceLabel(ua: string | null | undefined): string {14 if (!ua) return 'Unknown device';15 const os = /iPhone|iPad/.test(ua) ? 'iOS' : /Android/.test(ua) ? 'Android' : /Mac OS X/.test(ua) ? 'macOS' : /Windows/.test(ua) ? 'Windows' : /Linux/.test(ua) ? 'Linux' : 'Unknown OS';16 const browser = /Edg\//.test(ua) ? 'Edge' : /OPR\//.test(ua) ? 'Opera' : /Chrome\//.test(ua) ? 'Chrome' : /Safari\//.test(ua) ? 'Safari' : /Firefox\//.test(ua) ? 'Firefox' : /curl|node|undici/i.test(ua) ? 'API client' : 'Browser';17 return `${browser} · ${os}`;18}19