autotel
Version:
Write Once, Observe Anywhere
1 lines • 6.5 kB
Source Map (JSON)
{"version":3,"file":"enrichers.cjs","names":[],"sources":["../src/enrichers.ts"],"sourcesContent":["type Headers = Record<string, string | string[] | undefined>;\n\nfunction get(headers: Headers, key: string): string | undefined {\n const lower = key.toLowerCase();\n for (const [k, v] of Object.entries(headers)) {\n if (k.toLowerCase() === lower) {\n return Array.isArray(v) ? v[0] : v;\n }\n }\n return undefined;\n}\n\n// --- User Agent ---\n\nexport interface UserAgentAttributes {\n 'user_agent.raw': string;\n 'user_agent.browser'?: string;\n 'user_agent.os'?: string;\n 'user_agent.device'?: string;\n}\n\nconst BROWSER_RE = /(Firefox|OPR|Edg|Chrome|Safari|MSIE|Trident)[\\s/]?([\\d.]*)/;\nconst OS_RE =\n /(Windows NT|Mac OS X|Linux|Android|iPhone OS|iPad|CrOS)[\\s]?([\\d._]*)/;\n\nfunction parseBrowser(ua: string): string | undefined {\n const m = BROWSER_RE.exec(ua);\n if (!m) return undefined;\n const name =\n m[1] === 'OPR'\n ? 'Opera'\n : m[1] === 'Edg'\n ? 'Edge'\n : m[1] === 'Trident'\n ? 'IE'\n : m[1];\n return m[2] ? `${name} ${m[2]}` : name;\n}\n\nfunction parseOS(ua: string): string | undefined {\n const m = OS_RE.exec(ua);\n if (!m) return undefined;\n const name =\n m[1] === 'iPhone OS'\n ? 'iOS'\n : m[1] === 'Windows NT'\n ? 'Windows'\n : m[1] === 'Mac OS X'\n ? 'macOS'\n : m[1];\n const ver = m[2]?.replaceAll('_', '.') || undefined;\n return ver ? `${name} ${ver}` : name;\n}\n\nfunction parseDevice(ua: string): string | undefined {\n if (/Mobi|Android.*Mobile|iPhone/.test(ua)) return 'mobile';\n if (/iPad|Android(?!.*Mobile)|Tablet/.test(ua)) return 'tablet';\n if (/Bot|Crawler|Spider|Lighthouse/i.test(ua)) return 'bot';\n return 'desktop';\n}\n\nexport function userAgent(headers: Headers): UserAgentAttributes | undefined {\n const raw = get(headers, 'user-agent');\n if (!raw) return undefined;\n\n const attrs: UserAgentAttributes = { 'user_agent.raw': raw };\n const browser = parseBrowser(raw);\n if (browser) attrs['user_agent.browser'] = browser;\n const os = parseOS(raw);\n if (os) attrs['user_agent.os'] = os;\n const device = parseDevice(raw);\n if (device) attrs['user_agent.device'] = device;\n\n return attrs;\n}\n\n// --- Geo ---\n\nexport interface GeoAttributes {\n 'geo.country'?: string;\n 'geo.region'?: string;\n 'geo.city'?: string;\n 'geo.latitude'?: string;\n 'geo.longitude'?: string;\n}\n\nexport function geo(headers: Headers): GeoAttributes | undefined {\n const country =\n get(headers, 'x-vercel-ip-country') ?? get(headers, 'cf-ipcountry');\n const region = get(headers, 'x-vercel-ip-country-region');\n const city = get(headers, 'x-vercel-ip-city');\n const latitude = get(headers, 'x-vercel-ip-latitude');\n const longitude = get(headers, 'x-vercel-ip-longitude');\n\n if (!country && !region && !city && !latitude && !longitude) return undefined;\n\n const attrs: GeoAttributes = {};\n if (country) attrs['geo.country'] = country;\n if (region) attrs['geo.region'] = region;\n if (city) {\n try {\n attrs['geo.city'] = decodeURIComponent(city);\n } catch {\n attrs['geo.city'] = city;\n }\n }\n if (latitude) attrs['geo.latitude'] = latitude;\n if (longitude) attrs['geo.longitude'] = longitude;\n\n return attrs;\n}\n\n// --- Request Size ---\n\nexport interface RequestSizeAttributes {\n 'http.request.body.size'?: number;\n 'http.response.body.size'?: number;\n}\n\nconst DIGITS_RE = /^\\d+$/;\n\nfunction parseContentLength(value: string | undefined): number | undefined {\n if (!value || !DIGITS_RE.test(value)) return undefined;\n return Number(value);\n}\n\nexport function requestSize(\n requestHeaders: Headers,\n responseHeaders?: Headers,\n): RequestSizeAttributes | undefined {\n const reqLen = get(requestHeaders, 'content-length');\n const resLen = responseHeaders\n ? get(responseHeaders, 'content-length')\n : undefined;\n\n if (!reqLen && !resLen) return undefined;\n\n const attrs: RequestSizeAttributes = {};\n const reqBytes = parseContentLength(reqLen);\n if (reqBytes !== undefined) attrs['http.request.body.size'] = reqBytes;\n const resBytes = parseContentLength(resLen);\n if (resBytes !== undefined) attrs['http.response.body.size'] = resBytes;\n\n return Object.keys(attrs).length > 0 ? attrs : undefined;\n}\n"],"mappings":"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"}