UNPKG

client-parser

Version:

A utility to detect the device type (Android, iOS, Windows Phone, PC, unknown) based on the User Agent string.

317 lines (314 loc) 12.7 kB
// src/constants/regex.ts var USER_AGENT_REGEX = Object.freeze({ // --- OS and Device Detection --- /** Regular expression to detect Windows Phone and extract its OS version. */ WINDOWS_PHONE: /Windows Phone (?:OS )?([\d.]+)/i, // Handles "Windows Phone" and "Windows Phone OS 7.0" /** Regular expression to detect iPad and extract its OS version. */ // Modern iPads on iPadOS often report as "MacIntel" and "Mac OS X" in UA string, // so it's crucial to detect "iPad" first. IPAD: /iPad.*(?:OS|CPU) ([\d_.]+)/i, // Covers "iPad; CPU OS 13_5_1" or "iPad; OS 14_0" /** Regular expression to detect iPhone and extract its OS version. */ IPHONE: /iPhone.*(?:OS|CPU) ([\d_.]+)/i, // Covers "iPhone; CPU OS 13_5_1" or "iPhone; OS 14_0" /** Regular expression to detect iPod and extract its OS version (often similar to iPhone). */ IPOD: /iPod.*(?:OS|CPU) ([\d_.]+)/i, // Added for completeness if you want to differentiate iPods /** Regular expression to extract iOS version (common pattern for all iOS devices). */ IOS_VERSION: /(?:iPhone|iPad|iPod).*OS ([\d_]+)/i, // More robust for any iOS device /** Regular expression to detect Android and extract its version. */ ANDROID: /Android ([\d.]+)/i, /** Regular expression to detect if the device is specifically a mobile device. */ // Used to differentiate between Android phone and tablet if 'Android' alone isn't enough. // 'Mobi' is a strong indicator for phones. MOBILE_INDICATOR: /Mobi/i, /** Regular expression to detect common tablet indicators beyond just 'Android'. * This helps distinguish tablets when 'Mobi' is absent. */ TABLET_INDICATOR: /Tablet|iPad|SM-T\d+|KF[A-Z0-9]{2,}|Nexus 7|Nexus 10/i, // Added more common tablet UAs /** Regular expression to detect Windows NT (desktop Windows) and extract its version. */ // Version mapping: 5.1 -> XP, 6.0 -> Vista, 6.1 -> 7, 6.2 -> 8, 6.3 -> 8.1, 10.0 -> 10/11 WINDOWS_NT: /Windows NT ([\d.]+)/i, /** Regular expression to detect macOS and extract its version. */ // macOS versions are typically X_Y or X_Y_Z. MAC_OS_X: /Macintosh; Intel Mac OS X ([\d_.]+)/i, /** Regular expression to detect Linux (excluding Android due to order of operations). */ LINUX: /Linux/i, // --- Browser Detection --- /** Regular expression to detect Microsoft Edge (Chromium-based) and extract its version. */ // "Edg/" for Chromium Edge, "Edge/" for legacy EdgeHTML. Prioritize "Edg". EDGE: /Edg[eA]?\/([\d.]+)/i, // "Edg", "Edge", "EdgA" (Android) /** Regular expression to detect Opera browser and extract its version. */ // OPR for Opera Touch/Mini, Opera for desktop. OPR is usually more modern. OPERA: /(?:Opera|OPR)\/([\d.]+)/i, /** Regular expression to detect Firefox browser and extract its version. */ FIREFOX: /Firefox\/([\d.]+)/i, /** Regular expression to detect Chrome (desktop) or CriOS (Chrome on iOS) and extract its version. */ // Prioritize this AFTER Edge and Opera detection. CHROME_CRIOS: /(?:Chrome|CriOS|Chromium)\/([\d.]+)/i, // Added Chromium for broader detection /** Regular expression to detect Safari browser. Needs to be checked AFTER Chrome/Opera/Edge/Firefox. */ SAFARI: /Safari\/([\d.]+)/i, // This captures the WebKit version, typically. /** Regular expression to extract a Safari browser 'Version/' number. This is the true browser version. */ SAFARI_VERSION: /Version\/([\d.]+).*Safari/i, // This is key for actual Safari version /** Regular expression to detect Internet Explorer (MSIE for IE10 and below, Trident for IE11). */ INTERNET_EXPLORER: /MSIE ([\d.]+)|Trident\/.+?rv:([\d.]+)/i, // Capture either MSIE version or rv: version // --- Rendering Engine Detection --- /** Regular expression to detect WebKit engine and extract its version (used by Safari, older Chrome/Opera). */ WEBKIT_ENGINE: /AppleWebKit\/([\d.]+)/i, /** Regular expression to detect Gecko engine and extract its version (used by Firefox). */ GECKO_ENGINE: /Gecko\/(\d{8}|\d+\.\d+)/i, // Gecko version can be YYYYMMDD or X.Y /** Regular expression to detect Trident engine and extract its version (used by Internet Explorer 11). */ TRIDENT_ENGINE: /Trident\/([\d.]+)/i, /** Regular expression to detect Presto engine and extract its version (older Opera). */ PRESTO_ENGINE: /Presto\/([\d.]+)/i // Added for older Opera support }); var regex_default = USER_AGENT_REGEX; // src/constants/names.ts var DEVICE_TYPES = Object.freeze({ /** Represents an unknown or uncategorized device type. */ UNKNOWN: "unknown", /** Represents a Windows Phone device. */ WINDOWS_PHONE: "windows_phone", /** Represents an iOS device (iPhone, iPad, iPod Touch). */ IOS: "ios", /** Represents an Android device. */ ANDROID: "android", /** Represents a personal computer (desktop or laptop). */ PC: "pc" }); var OS_NAMES = Object.freeze({ /** Represents an unknown or uncategorized operating system. */ UNKNOWN: "unknown", /** Represents the Windows Phone operating system. */ WINDOWS_PHONE: "Windows Phone", /** Represents the iOS operating system. */ IOS: "iOS", /** Represents the Android operating system. */ ANDROID: "Android", /** Represents the Windows desktop operating system. */ WINDOWS: "Windows", /** Represents the macOS operating system. */ MACOS: "macOS", /** Represents the Linux operating system. */ LINUX: "Linux" }); var BROWSER_NAMES = Object.freeze({ /** Represents an unknown or uncategorized browser. */ UNKNOWN: "unknown", /** Represents the Microsoft Edge browser. */ EDGE: "Edge", /** Represents the Opera browser. */ OPERA: "Opera", /** Represents the Mozilla Firefox browser. */ FIREFOX: "Firefox", /** Represents the Google Chrome browser. */ CHROME: "Chrome", /** Represents the Apple Safari browser. */ SAFARI: "Safari", /** Represents the Internet Explorer browser. */ INTERNET_EXPLORER: "Internet Explorer" }); // src/index.ts var _detectOSAndDevice = (userAgent, deviceInfo) => { if (regex_default.WINDOWS_PHONE.test(userAgent)) { deviceInfo.device.type = DEVICE_TYPES.WINDOWS_PHONE; deviceInfo.os.name = OS_NAMES.WINDOWS_PHONE; const wpMatch = userAgent.match(regex_default.WINDOWS_PHONE); if (wpMatch && wpMatch[1]) { deviceInfo.os.version = wpMatch[1]; } deviceInfo.device.name = "Windows Phone"; return; } if (regex_default.IPAD.test(userAgent)) { deviceInfo.device.type = DEVICE_TYPES.IOS; deviceInfo.os.name = OS_NAMES.IOS; const versionMatch = userAgent.match(regex_default.IOS_VERSION); if (versionMatch && versionMatch[1]) { deviceInfo.os.version = versionMatch[1].replace(/_/g, "."); } deviceInfo.device.name = "iPad"; return; } const iPhoneMatch = userAgent.match(regex_default.IPHONE); if (iPhoneMatch) { deviceInfo.device.type = DEVICE_TYPES.IOS; deviceInfo.os.name = OS_NAMES.IOS; const versionMatch = userAgent.match(regex_default.IOS_VERSION); if (versionMatch && versionMatch[1]) { deviceInfo.os.version = versionMatch[1].replace(/_/g, "."); } deviceInfo.device.name = "iPhone"; return; } const iPodMatch = userAgent.match(regex_default.IPOD); if (iPodMatch) { deviceInfo.device.type = DEVICE_TYPES.IOS; deviceInfo.os.name = OS_NAMES.IOS; const versionMatch = userAgent.match(regex_default.IOS_VERSION); if (versionMatch && versionMatch[1]) { deviceInfo.os.version = versionMatch[1].replace(/_/g, "."); } deviceInfo.device.name = "iPod Touch"; return; } const androidMatch = userAgent.match(regex_default.ANDROID); if (androidMatch) { deviceInfo.os.name = OS_NAMES.ANDROID; deviceInfo.os.version = androidMatch[1]; if (regex_default.MOBILE_INDICATOR.test(userAgent)) { deviceInfo.device.type = DEVICE_TYPES.ANDROID; deviceInfo.device.name = "Android Phone"; } else if (regex_default.TABLET_INDICATOR.test(userAgent)) { deviceInfo.device.type = DEVICE_TYPES.ANDROID; deviceInfo.device.name = "Android Tablet"; } else { deviceInfo.device.type = DEVICE_TYPES.ANDROID; deviceInfo.device.name = "Android Device"; } return; } const windowsMatch = userAgent.match(regex_default.WINDOWS_NT); if (windowsMatch) { deviceInfo.device.type = DEVICE_TYPES.PC; deviceInfo.os.name = OS_NAMES.WINDOWS; deviceInfo.os.version = windowsMatch[1]; deviceInfo.device.name = "Windows PC"; return; } if (regex_default.MAC_OS_X.test(userAgent)) { deviceInfo.device.type = DEVICE_TYPES.PC; deviceInfo.os.name = OS_NAMES.MACOS; const macMatch = userAgent.match(regex_default.MAC_OS_X); if (macMatch && macMatch[1]) { deviceInfo.os.version = macMatch[1].replace(/_/g, "."); } deviceInfo.device.name = "macOS PC"; return; } if (regex_default.LINUX.test(userAgent)) { deviceInfo.device.type = DEVICE_TYPES.PC; deviceInfo.os.name = OS_NAMES.LINUX; deviceInfo.device.name = "Linux PC"; return; } }; var _detectBrowser = (userAgent, deviceInfo) => { const edgeMatch = userAgent.match(regex_default.EDGE); if (edgeMatch) { deviceInfo.browser.name = BROWSER_NAMES.EDGE; deviceInfo.browser.version = edgeMatch[1]; const webkitMatch = userAgent.match(regex_default.WEBKIT_ENGINE); if (webkitMatch && webkitMatch[1]) { deviceInfo.engine.name = "Blink"; deviceInfo.engine.version = webkitMatch[1]; } return; } const operaMatch = userAgent.match(regex_default.OPERA); if (operaMatch) { deviceInfo.browser.name = BROWSER_NAMES.OPERA; deviceInfo.browser.version = operaMatch[1]; const webkitMatch = userAgent.match(regex_default.WEBKIT_ENGINE); if (webkitMatch && webkitMatch[1]) { deviceInfo.engine.name = "Blink"; deviceInfo.engine.version = webkitMatch[1]; } const prestoMatch = userAgent.match(regex_default.PRESTO_ENGINE); if (prestoMatch && prestoMatch[1]) { deviceInfo.engine.name = "Presto"; deviceInfo.engine.version = prestoMatch[1]; } return; } const firefoxMatch = userAgent.match(regex_default.FIREFOX); if (firefoxMatch) { deviceInfo.browser.name = BROWSER_NAMES.FIREFOX; deviceInfo.browser.version = firefoxMatch[1]; const geckoMatch = userAgent.match(regex_default.GECKO_ENGINE); if (geckoMatch && geckoMatch[1]) { deviceInfo.engine.name = "Gecko"; deviceInfo.engine.version = geckoMatch[1]; } return; } const chromeMatch = userAgent.match(regex_default.CHROME_CRIOS); if (chromeMatch) { deviceInfo.browser.name = BROWSER_NAMES.CHROME; deviceInfo.browser.version = chromeMatch[1]; const webkitMatch = userAgent.match(regex_default.WEBKIT_ENGINE); if (webkitMatch && webkitMatch[1]) { deviceInfo.engine.name = "Blink"; deviceInfo.engine.version = webkitMatch[1]; } return; } const safariVersionMatch = userAgent.match(regex_default.SAFARI_VERSION); if (safariVersionMatch) { deviceInfo.browser.name = BROWSER_NAMES.SAFARI; deviceInfo.browser.version = safariVersionMatch[1]; const webkitMatch = userAgent.match(regex_default.WEBKIT_ENGINE); if (webkitMatch && webkitMatch[1]) { deviceInfo.engine.name = "WebKit"; deviceInfo.engine.version = webkitMatch[1]; } return; } const ieMatch = userAgent.match(regex_default.INTERNET_EXPLORER); if (ieMatch) { deviceInfo.browser.name = BROWSER_NAMES.INTERNET_EXPLORER; deviceInfo.browser.version = ieMatch[1] || ieMatch[2]; const tridentMatch = userAgent.match(regex_default.TRIDENT_ENGINE); if (tridentMatch && tridentMatch[1]) { deviceInfo.engine.name = "Trident"; deviceInfo.engine.version = tridentMatch[1]; } return; } }; var getDeviceType = (userAgent, platform = "") => { const deviceInfo = { userAgentString: userAgent, device: { type: DEVICE_TYPES.UNKNOWN, name: "unknown", model: "unknown", manufacturer: "unknown" }, engine: { name: "unknown", version: "unknown" }, os: { name: OS_NAMES.UNKNOWN, version: void 0, // undefined initially, will be populated if detected architecture: void 0 // undefined initially, will be populated if detected }, browser: { name: BROWSER_NAMES.UNKNOWN, version: "unknown" }, platform, // Can be passed as an argument if available (e.g., navigator.platform) isBot: false // Requires separate bot detection logic }; _detectOSAndDevice(userAgent, deviceInfo); _detectBrowser(userAgent, deviceInfo); return deviceInfo; }; var index_default = getDeviceType; export { index_default as default };