events: add UA parser (device_type/os/browser)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
51b0508561
commit
d974e865c2
1 changed files with 51 additions and 0 deletions
51
src/ua.js
Normal file
51
src/ua.js
Normal file
|
|
@ -0,0 +1,51 @@
|
|||
// ─────────────────────────────────────────────────────────────
|
||||
// src/ua.js — minimal User-Agent parser.
|
||||
//
|
||||
// Coarse-grained classification only: device_type / os / browser.
|
||||
// We deliberately do NOT pull in ua-parser-js — the project keeps a
|
||||
// small dependency footprint and we only need three buckets. The raw
|
||||
// UA is also stored alongside parsed fields (see src/events.js) so a
|
||||
// regex miss can be re-classified later.
|
||||
//
|
||||
// Also owns MOBILE_UA_RE — the existing /timeline view-dispatch
|
||||
// regex used by server.js. Single source of truth.
|
||||
// ─────────────────────────────────────────────────────────────
|
||||
|
||||
// UA substrings that mean "phone-class small screen". Tablets (iPad,
|
||||
// Android tablets) deliberately do NOT match — they get the desktop
|
||||
// view, which matches existing behaviour in server.js.
|
||||
export const MOBILE_UA_RE =
|
||||
/\b(iPhone|iPod|Android.*Mobile|Mobile.*Firefox|IEMobile|BlackBerry|Opera Mini)\b/i;
|
||||
|
||||
// Tablet-class devices. Order matters in parseUA(): tablet check runs
|
||||
// before mobile so "iPad" doesn't accidentally fall through to desktop.
|
||||
const TABLET_UA_RE = /\b(iPad|Android(?!.*Mobile))\b/i;
|
||||
|
||||
export function parseUA(ua) {
|
||||
if (!ua || typeof ua !== 'string') {
|
||||
return { device_type: null, os: null, browser: null };
|
||||
}
|
||||
|
||||
// device_type
|
||||
let device_type = 'desktop';
|
||||
if (TABLET_UA_RE.test(ua)) device_type = 'tablet';
|
||||
else if (MOBILE_UA_RE.test(ua)) device_type = 'mobile';
|
||||
|
||||
// os
|
||||
let os = 'other';
|
||||
if (/\b(iPhone|iPad|iPod)\b/.test(ua)) os = 'iOS';
|
||||
else if (/\bAndroid\b/.test(ua)) os = 'Android';
|
||||
else if (/\bWindows\b/.test(ua)) os = 'Windows';
|
||||
else if (/Mac OS X|Macintosh/.test(ua)) os = 'macOS';
|
||||
else if (/\bLinux\b/.test(ua)) os = 'Linux';
|
||||
|
||||
// browser — order matters. All Chromium UAs include "Safari/", all
|
||||
// Edge UAs include "Chrome/", so the most specific token must win.
|
||||
let browser = 'other';
|
||||
if (/\bEdg\//.test(ua)) browser = 'Edge';
|
||||
else if (/\bFirefox\//.test(ua)) browser = 'Firefox';
|
||||
else if (/\bChrome\//.test(ua)) browser = 'Chrome';
|
||||
else if (/\bSafari\//.test(ua)) browser = 'Safari';
|
||||
|
||||
return { device_type, os, browser };
|
||||
}
|
||||
Loading…
Add table
Reference in a new issue