browser.ts (3153B)
1 export type BrowserPlatformInfo = { 2 os: string; 3 browser: string; 4 version: string; 5 }; 6 7 const REMOVE_EXCESS_MOZILLA_AND_VERSION = /^mozilla\/\d\.\d\W/; 8 const BROWSER_PATTERN = /(\w+)\/(\d+\.\d+(?:\.\d+)?(?:\.\d+)?)/g; 9 const ENGINE_AND_VERSION_PATTERN = /^(ver|cri|gec)/; 10 const BRAND_LIST = ['chrome', 'opera', 'safari', 'edge', 'firefox']; 11 12 const MOBILE_OS_PATTERNS: Record<string, RegExp> = { 13 iphone: /iphone/, 14 ipad: /ipad|macintosh/, 15 android: /android/ 16 }; 17 18 const DESKTOP_OS_PATTERNS: Record<string, RegExp> = { 19 windows: /win/, 20 mac: /macintosh/, 21 linux: /linux/ 22 }; 23 24 const parse_user_agent_string = (ua_string: string): BrowserPlatformInfo => { 25 const ua = ua_string.toLowerCase().replace(REMOVE_EXCESS_MOZILLA_AND_VERSION, ''); 26 27 const mobile_os = Object.keys(MOBILE_OS_PATTERNS).find( 28 (key) => MOBILE_OS_PATTERNS[key].test(ua) && navigator.maxTouchPoints >= 1 29 ); 30 const desktop_os = Object.keys(DESKTOP_OS_PATTERNS).find((key) => DESKTOP_OS_PATTERNS[key].test(ua)); 31 const os = mobile_os || desktop_os || ''; 32 33 const browser_matches = ua.match(BROWSER_PATTERN); 34 const version_regex = /version\/(\d+(\.\d+)*)/; 35 const safari_version_match = ua.match(version_regex); 36 const safari_version = Array.isArray(safari_version_match) ? safari_version_match[1] : null; 37 38 const browser_offset = 39 browser_matches && browser_matches.length > 2 && !ENGINE_AND_VERSION_PATTERN.test(browser_matches[1]) 40 ? 1 41 : 0; 42 const browser_result = 43 browser_matches && browser_matches[browser_matches.length - 1 - browser_offset].split('/'); 44 const browser = browser_result ? browser_result[0] : ''; 45 const version = safari_version || (browser_result ? browser_result[1] : ''); 46 47 return { os, browser, version }; 48 }; 49 50 export const browser_platform = (): BrowserPlatformInfo | undefined => { 51 if (typeof navigator !== 'undefined') { 52 if ('userAgentData' in navigator && navigator.userAgentData) { 53 const ua_data = navigator.userAgentData; 54 const os = ua_data.platform.toLowerCase(); 55 let browser = ''; 56 let version = ''; 57 58 if (Array.isArray(ua_data.brands)) { 59 for (const { brand, version: brand_version } of ua_data.brands) { 60 const lower_brand = brand.toLowerCase(); 61 if (BRAND_LIST.some((b) => lower_brand.includes(b))) { 62 browser = lower_brand; 63 version = brand_version; 64 break; 65 } 66 } 67 } 68 69 if (!browser && navigator.userAgent) { 70 return parse_user_agent_string(navigator.userAgent); 71 } 72 return { os, browser, version }; 73 } 74 75 if (navigator.userAgent) { 76 return parse_user_agent_string(navigator.userAgent); 77 } 78 79 const nav_platform = navigator.platform; 80 if (!nav_platform) return undefined; 81 return { 82 os: nav_platform, 83 browser: '', 84 version: '' 85 }; 86 } 87 88 return undefined; 89 };