@posthog/core
Advanced tools
| /** | ||
| * Hints from sources outside the User-Agent string. These let us identify Brave | ||
| * on desktop / Android — Chromium-based with no UA marker, but it exposes | ||
| * `navigator.brave`. (Brave on iOS is detected via its `Brave/X` UA marker — | ||
| * WebKit doesn't expose `navigator.brave` — so no hint is needed there.) | ||
| */ | ||
| export interface BrowserDetectionHints { | ||
| brave?: boolean; | ||
| } | ||
| /** | ||
| * This function detects which browser is running this script. | ||
| * The order of the checks are important since many user agents | ||
| * include keywords used in later checks. | ||
| * | ||
| * `hints` is an optional bag of out-of-band signals (`navigator.brave`) used to | ||
| * detect browsers that intentionally do not identify themselves in the UA | ||
| * string. When omitted, only UA-string detection runs — preserving the previous | ||
| * behaviour. | ||
| */ | ||
| export declare const detectBrowser: (user_agent: string, vendor: string | undefined) => string; | ||
| export declare const detectBrowser: (user_agent: string, vendor: string | undefined, hints?: BrowserDetectionHints) => string; | ||
| /** | ||
@@ -15,3 +29,3 @@ * This function detects which browser version is running this script, | ||
| */ | ||
| export declare const detectBrowserVersion: (userAgent: string, vendor: string | undefined) => number | null; | ||
| export declare const detectBrowserVersion: (userAgent: string, vendor: string | undefined, hints?: BrowserDetectionHints) => number | null; | ||
| export declare const detectOS: (user_agent: string) => [string, string]; | ||
@@ -18,0 +32,0 @@ export declare const detectDevice: (user_agent: string) => string; |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"user-agent-utils.d.ts","sourceRoot":"","sources":["../../src/utils/user-agent-utils.ts"],"names":[],"mappings":"AAsFA;;;;GAIG;AACH,eAAO,MAAM,aAAa,GAAa,YAAY,MAAM,EAAE,QAAQ,MAAM,GAAG,SAAS,KAAG,MAmDvF,CAAA;AAuBD;;;;;;;GAOG;AACH,eAAO,MAAM,oBAAoB,GAAa,WAAW,MAAM,EAAE,QAAQ,MAAM,GAAG,SAAS,KAAG,MAAM,GAAG,IAetG,CAAA;AA0FD,eAAO,MAAM,QAAQ,GAAa,YAAY,MAAM,KAAG,CAAC,MAAM,EAAE,MAAM,CAUrE,CAAA;AAED,eAAO,MAAM,YAAY,GAAa,YAAY,MAAM,KAAG,MAuD1D,CAAA;AAED,eAAO,MAAM,gBAAgB,GAC3B,YAAY,MAAM,EAClB,UAAU;IACR,qBAAqB,CAAC,EAAE,MAAM,CAAA;IAC9B,cAAc,CAAC,EAAE,MAAM,CAAA;IACvB,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,gBAAgB,CAAC,EAAE,MAAM,CAAA;CAC1B,KACA,MA4BF,CAAA"} | ||
| {"version":3,"file":"user-agent-utils.d.ts","sourceRoot":"","sources":["../../src/utils/user-agent-utils.ts"],"names":[],"mappings":"AA+DA;;;;;GAKG;AACH,MAAM,WAAW,qBAAqB;IAGpC,KAAK,CAAC,EAAE,OAAO,CAAA;CAChB;AAuCD;;;;;;;;;GASG;AACH,eAAO,MAAM,aAAa,GACxB,YAAY,MAAM,EAClB,QAAQ,MAAM,GAAG,SAAS,EAC1B,QAAQ,qBAAqB,KAC5B,MAmFF,CAAA;AAkCD;;;;;;;GAOG;AACH,eAAO,MAAM,oBAAoB,GAC/B,WAAW,MAAM,EACjB,QAAQ,MAAM,GAAG,SAAS,EAC1B,QAAQ,qBAAqB,KAC5B,MAAM,GAAG,IAmBX,CAAA;AA0FD,eAAO,MAAM,QAAQ,GAAa,YAAY,MAAM,KAAG,CAAC,MAAM,EAAE,MAAM,CAUrE,CAAA;AAED,eAAO,MAAM,YAAY,GAAa,YAAY,MAAM,KAAG,MAuD1D,CAAA;AAED,eAAO,MAAM,gBAAgB,GAC3B,YAAY,MAAM,EAClB,UAAU;IACR,qBAAqB,CAAC,EAAE,MAAM,CAAA;IAC9B,cAAc,CAAC,EAAE,MAAM,CAAA;IACvB,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,gBAAgB,CAAC,EAAE,MAAM,CAAA;CAC1B,KACA,MA4BF,CAAA"} |
@@ -74,4 +74,15 @@ "use strict"; | ||
| const OCULUS_BROWSER = 'Oculus Browser'; | ||
| const VIVALDI = 'Vivaldi'; | ||
| const YANDEX = 'Yandex'; | ||
| const WHALE = 'Whale'; | ||
| const DUCKDUCKGO = 'DuckDuckGo'; | ||
| const PALE_MOON = 'Pale Moon'; | ||
| const WATERFOX = 'Waterfox'; | ||
| const BRAVE = 'Brave'; | ||
| const BROWSER_VERSION_REGEX_SUFFIX = '(\\d+(\\.\\d+)?)'; | ||
| const DEFAULT_BROWSER_VERSION_REGEX = new RegExp('Version/' + BROWSER_VERSION_REGEX_SUFFIX); | ||
| function browserFromHints(hints) { | ||
| if (hints?.brave) return BRAVE; | ||
| return null; | ||
| } | ||
| const XBOX_REGEX = new RegExp(XBOX, 'i'); | ||
@@ -98,4 +109,6 @@ const PLAYSTATION_REGEX = new RegExp(PLAYSTATION + ' \\w+', 'i'); | ||
| const safariCheck = (ua, vendor)=>vendor && (0, external_string_utils_js_namespaceObject.includes)(vendor, APPLE) || isSafari(ua); | ||
| const detectBrowser = function(user_agent, vendor) { | ||
| const detectBrowser = function(user_agent, vendor, hints) { | ||
| vendor = vendor || ''; | ||
| const fromHints = browserFromHints(hints); | ||
| if (fromHints) return fromHints; | ||
| if ((0, external_string_utils_js_namespaceObject.includes)(user_agent, ' OPR/') && (0, external_string_utils_js_namespaceObject.includes)(user_agent, 'Mini')) return OPERA_MINI; | ||
@@ -108,2 +121,6 @@ if ((0, external_string_utils_js_namespaceObject.includes)(user_agent, ' OPR/')) return OPERA; | ||
| else if ((0, external_string_utils_js_namespaceObject.includes)(user_agent, EDGE) || (0, external_string_utils_js_namespaceObject.includes)(user_agent, 'Edg/')) return MICROSOFT_EDGE; | ||
| else if ((0, external_string_utils_js_namespaceObject.includes)(user_agent, VIVALDI + '/')) return VIVALDI; | ||
| else if ((0, external_string_utils_js_namespaceObject.includes)(user_agent, 'YaBrowser/')) return YANDEX; | ||
| else if ((0, external_string_utils_js_namespaceObject.includes)(user_agent, WHALE + '/')) return WHALE; | ||
| else if ((0, external_string_utils_js_namespaceObject.includes)(user_agent, DUCKDUCKGO + '/') || (0, external_string_utils_js_namespaceObject.includes)(user_agent, 'Ddg/')) return DUCKDUCKGO; | ||
| else if ((0, external_string_utils_js_namespaceObject.includes)(user_agent, 'FBIOS')) return FACEBOOK + ' ' + MOBILE; | ||
@@ -117,3 +134,6 @@ else if ((0, external_string_utils_js_namespaceObject.includes)(user_agent, 'UCWEB') || (0, external_string_utils_js_namespaceObject.includes)(user_agent, 'UCBrowser')) return 'UC Browser'; | ||
| else if ((0, external_string_utils_js_namespaceObject.includes)(user_agent.toLowerCase(), KONQUEROR.toLowerCase())) return KONQUEROR; | ||
| else if ((0, external_string_utils_js_namespaceObject.includes)(user_agent, BRAVE + '/')) return BRAVE; | ||
| else if (safariCheck(user_agent, vendor)) return (0, external_string_utils_js_namespaceObject.includes)(user_agent, MOBILE) ? MOBILE_SAFARI : SAFARI; | ||
| else if ((0, external_string_utils_js_namespaceObject.includes)(user_agent, 'PaleMoon/')) return PALE_MOON; | ||
| else if ((0, external_string_utils_js_namespaceObject.includes)(user_agent, WATERFOX + '/')) return WATERFOX; | ||
| else if ((0, external_string_utils_js_namespaceObject.includes)(user_agent, FIREFOX)) return FIREFOX; | ||
@@ -171,2 +191,23 @@ else if ((0, external_string_utils_js_namespaceObject.includes)(user_agent, 'MSIE') || (0, external_string_utils_js_namespaceObject.includes)(user_agent, 'Trident/')) return INTERNET_EXPLORER; | ||
| ], | ||
| [VIVALDI]: [ | ||
| new RegExp(VIVALDI + '\\/' + BROWSER_VERSION_REGEX_SUFFIX) | ||
| ], | ||
| [YANDEX]: [ | ||
| new RegExp('YaBrowser\\/' + BROWSER_VERSION_REGEX_SUFFIX) | ||
| ], | ||
| [WHALE]: [ | ||
| new RegExp(WHALE + '\\/' + BROWSER_VERSION_REGEX_SUFFIX) | ||
| ], | ||
| [BRAVE]: [ | ||
| new RegExp(BRAVE + '\\/' + BROWSER_VERSION_REGEX_SUFFIX) | ||
| ], | ||
| [DUCKDUCKGO]: [ | ||
| new RegExp('(DuckDuckGo|Ddg)\\/' + BROWSER_VERSION_REGEX_SUFFIX) | ||
| ], | ||
| [PALE_MOON]: [ | ||
| new RegExp('PaleMoon\\/' + BROWSER_VERSION_REGEX_SUFFIX) | ||
| ], | ||
| [WATERFOX]: [ | ||
| new RegExp(WATERFOX + '\\/' + BROWSER_VERSION_REGEX_SUFFIX) | ||
| ], | ||
| [INTERNET_EXPLORER]: [ | ||
@@ -179,4 +220,4 @@ new RegExp('(rv:|MSIE )' + BROWSER_VERSION_REGEX_SUFFIX) | ||
| }; | ||
| const detectBrowserVersion = function(userAgent, vendor) { | ||
| const browser = detectBrowser(userAgent, vendor); | ||
| const detectBrowserVersion = function(userAgent, vendor, hints) { | ||
| const browser = detectBrowser(userAgent, vendor, hints); | ||
| const regexes = versionRegexes[browser]; | ||
@@ -183,0 +224,0 @@ if ((0, external_type_utils_js_namespaceObject.isUndefined)(regexes)) return null; |
@@ -42,4 +42,15 @@ import { includes } from "./string-utils.mjs"; | ||
| const OCULUS_BROWSER = 'Oculus Browser'; | ||
| const VIVALDI = 'Vivaldi'; | ||
| const YANDEX = 'Yandex'; | ||
| const WHALE = 'Whale'; | ||
| const DUCKDUCKGO = 'DuckDuckGo'; | ||
| const PALE_MOON = 'Pale Moon'; | ||
| const WATERFOX = 'Waterfox'; | ||
| const BRAVE = 'Brave'; | ||
| const BROWSER_VERSION_REGEX_SUFFIX = '(\\d+(\\.\\d+)?)'; | ||
| const DEFAULT_BROWSER_VERSION_REGEX = new RegExp('Version/' + BROWSER_VERSION_REGEX_SUFFIX); | ||
| function browserFromHints(hints) { | ||
| if (hints?.brave) return BRAVE; | ||
| return null; | ||
| } | ||
| const XBOX_REGEX = new RegExp(XBOX, 'i'); | ||
@@ -66,4 +77,6 @@ const PLAYSTATION_REGEX = new RegExp(PLAYSTATION + ' \\w+', 'i'); | ||
| const safariCheck = (ua, vendor)=>vendor && includes(vendor, APPLE) || isSafari(ua); | ||
| const detectBrowser = function(user_agent, vendor) { | ||
| const detectBrowser = function(user_agent, vendor, hints) { | ||
| vendor = vendor || ''; | ||
| const fromHints = browserFromHints(hints); | ||
| if (fromHints) return fromHints; | ||
| if (includes(user_agent, ' OPR/') && includes(user_agent, 'Mini')) return OPERA_MINI; | ||
@@ -76,2 +89,6 @@ if (includes(user_agent, ' OPR/')) return OPERA; | ||
| else if (includes(user_agent, EDGE) || includes(user_agent, 'Edg/')) return MICROSOFT_EDGE; | ||
| else if (includes(user_agent, VIVALDI + '/')) return VIVALDI; | ||
| else if (includes(user_agent, 'YaBrowser/')) return YANDEX; | ||
| else if (includes(user_agent, WHALE + '/')) return WHALE; | ||
| else if (includes(user_agent, DUCKDUCKGO + '/') || includes(user_agent, 'Ddg/')) return DUCKDUCKGO; | ||
| else if (includes(user_agent, 'FBIOS')) return FACEBOOK + ' ' + MOBILE; | ||
@@ -85,3 +102,6 @@ else if (includes(user_agent, 'UCWEB') || includes(user_agent, 'UCBrowser')) return 'UC Browser'; | ||
| else if (includes(user_agent.toLowerCase(), KONQUEROR.toLowerCase())) return KONQUEROR; | ||
| else if (includes(user_agent, BRAVE + '/')) return BRAVE; | ||
| else if (safariCheck(user_agent, vendor)) return includes(user_agent, MOBILE) ? MOBILE_SAFARI : SAFARI; | ||
| else if (includes(user_agent, 'PaleMoon/')) return PALE_MOON; | ||
| else if (includes(user_agent, WATERFOX + '/')) return WATERFOX; | ||
| else if (includes(user_agent, FIREFOX)) return FIREFOX; | ||
@@ -139,2 +159,23 @@ else if (includes(user_agent, 'MSIE') || includes(user_agent, 'Trident/')) return INTERNET_EXPLORER; | ||
| ], | ||
| [VIVALDI]: [ | ||
| new RegExp(VIVALDI + '\\/' + BROWSER_VERSION_REGEX_SUFFIX) | ||
| ], | ||
| [YANDEX]: [ | ||
| new RegExp('YaBrowser\\/' + BROWSER_VERSION_REGEX_SUFFIX) | ||
| ], | ||
| [WHALE]: [ | ||
| new RegExp(WHALE + '\\/' + BROWSER_VERSION_REGEX_SUFFIX) | ||
| ], | ||
| [BRAVE]: [ | ||
| new RegExp(BRAVE + '\\/' + BROWSER_VERSION_REGEX_SUFFIX) | ||
| ], | ||
| [DUCKDUCKGO]: [ | ||
| new RegExp('(DuckDuckGo|Ddg)\\/' + BROWSER_VERSION_REGEX_SUFFIX) | ||
| ], | ||
| [PALE_MOON]: [ | ||
| new RegExp('PaleMoon\\/' + BROWSER_VERSION_REGEX_SUFFIX) | ||
| ], | ||
| [WATERFOX]: [ | ||
| new RegExp(WATERFOX + '\\/' + BROWSER_VERSION_REGEX_SUFFIX) | ||
| ], | ||
| [INTERNET_EXPLORER]: [ | ||
@@ -147,4 +188,4 @@ new RegExp('(rv:|MSIE )' + BROWSER_VERSION_REGEX_SUFFIX) | ||
| }; | ||
| const detectBrowserVersion = function(userAgent, vendor) { | ||
| const browser = detectBrowser(userAgent, vendor); | ||
| const detectBrowserVersion = function(userAgent, vendor, hints) { | ||
| const browser = detectBrowser(userAgent, vendor, hints); | ||
| const regexes = versionRegexes[browser]; | ||
@@ -151,0 +192,0 @@ if (isUndefined(regexes)) return null; |
+2
-2
| { | ||
| "name": "@posthog/core", | ||
| "version": "1.29.15", | ||
| "version": "1.30.0", | ||
| "license": "MIT", | ||
@@ -70,3 +70,3 @@ "main": "dist/index.js", | ||
| "dependencies": { | ||
| "@posthog/types": "1.376.6" | ||
| "@posthog/types": "1.377.0" | ||
| }, | ||
@@ -73,0 +73,0 @@ "devDependencies": { |
@@ -53,2 +53,9 @@ import { includes } from './string-utils' | ||
| const OCULUS_BROWSER = 'Oculus Browser' | ||
| const VIVALDI = 'Vivaldi' | ||
| const YANDEX = 'Yandex' | ||
| const WHALE = 'Whale' | ||
| const DUCKDUCKGO = 'DuckDuckGo' | ||
| const PALE_MOON = 'Pale Moon' | ||
| const WATERFOX = 'Waterfox' | ||
| const BRAVE = 'Brave' | ||
@@ -58,2 +65,21 @@ const BROWSER_VERSION_REGEX_SUFFIX = '(\\d+(\\.\\d+)?)' | ||
| /** | ||
| * Hints from sources outside the User-Agent string. These let us identify Brave | ||
| * on desktop / Android — Chromium-based with no UA marker, but it exposes | ||
| * `navigator.brave`. (Brave on iOS is detected via its `Brave/X` UA marker — | ||
| * WebKit doesn't expose `navigator.brave` — so no hint is needed there.) | ||
| */ | ||
| export interface BrowserDetectionHints { | ||
| // Set to `true` when `navigator.brave` exists. This is the sync detection | ||
| // signal Brave recommends. Not available on iOS — see UA fallback below. | ||
| brave?: boolean | ||
| } | ||
| function browserFromHints(hints: BrowserDetectionHints | undefined): string | null { | ||
| if (hints?.brave) { | ||
| return BRAVE | ||
| } | ||
| return null | ||
| } | ||
| const XBOX_REGEX = new RegExp(XBOX, 'i') | ||
@@ -93,6 +119,23 @@ const PLAYSTATION_REGEX = new RegExp(PLAYSTATION + ' \\w+', 'i') | ||
| * include keywords used in later checks. | ||
| * | ||
| * `hints` is an optional bag of out-of-band signals (`navigator.brave`) used to | ||
| * detect browsers that intentionally do not identify themselves in the UA | ||
| * string. When omitted, only UA-string detection runs — preserving the previous | ||
| * behaviour. | ||
| */ | ||
| export const detectBrowser = function (user_agent: string, vendor: string | undefined): string { | ||
| export const detectBrowser = function ( | ||
| user_agent: string, | ||
| vendor: string | undefined, | ||
| hints?: BrowserDetectionHints | ||
| ): string { | ||
| vendor = vendor || '' // vendor is undefined for at least IE9 | ||
| // Out-of-band signals win over UA sniffing because desktop Brave is | ||
| // deliberately invisible in the UA string and would otherwise be | ||
| // misdetected as Chrome. | ||
| const fromHints = browserFromHints(hints) | ||
| if (fromHints) { | ||
| return fromHints | ||
| } | ||
| if (includes(user_agent, ' OPR/') && includes(user_agent, 'Mini')) { | ||
@@ -119,2 +162,13 @@ return OPERA_MINI | ||
| return MICROSOFT_EDGE | ||
| } | ||
| // Chromium forks that DO stamp themselves into the UA. These must be | ||
| // checked before Chrome because their UA also contains `Chrome/`. | ||
| else if (includes(user_agent, VIVALDI + '/')) { | ||
| return VIVALDI | ||
| } else if (includes(user_agent, 'YaBrowser/')) { | ||
| return YANDEX | ||
| } else if (includes(user_agent, WHALE + '/')) { | ||
| return WHALE | ||
| } else if (includes(user_agent, DUCKDUCKGO + '/') || includes(user_agent, 'Ddg/')) { | ||
| return DUCKDUCKGO | ||
| } else if (includes(user_agent, 'FBIOS')) { | ||
@@ -136,4 +190,17 @@ return FACEBOOK + ' ' + MOBILE | ||
| return KONQUEROR | ||
| } | ||
| // Brave on iOS does stamp itself into the UA as `Brave/X` — desktop and | ||
| // Android Brave intentionally do not. Must come before the Safari branch | ||
| // because iOS Brave's UA otherwise looks like Mobile Safari. | ||
| else if (includes(user_agent, BRAVE + '/')) { | ||
| return BRAVE | ||
| } else if (safariCheck(user_agent, vendor)) { | ||
| return includes(user_agent, MOBILE) ? MOBILE_SAFARI : SAFARI | ||
| } | ||
| // Firefox forks that stamp themselves into the UA. Must precede the | ||
| // generic Firefox check because they also include `Firefox/` (or `Gecko`). | ||
| else if (includes(user_agent, 'PaleMoon/')) { | ||
| return PALE_MOON | ||
| } else if (includes(user_agent, WATERFOX + '/')) { | ||
| return WATERFOX | ||
| } else if (includes(user_agent, FIREFOX)) { | ||
@@ -167,2 +234,13 @@ return FIREFOX | ||
| [OCULUS_BROWSER]: [new RegExp('OculusBrowser\\/' + BROWSER_VERSION_REGEX_SUFFIX)], | ||
| [VIVALDI]: [new RegExp(VIVALDI + '\\/' + BROWSER_VERSION_REGEX_SUFFIX)], | ||
| [YANDEX]: [new RegExp('YaBrowser\\/' + BROWSER_VERSION_REGEX_SUFFIX)], | ||
| [WHALE]: [new RegExp(WHALE + '\\/' + BROWSER_VERSION_REGEX_SUFFIX)], | ||
| // Brave on iOS exposes itself as `Brave/X.X` in the UA. Desktop / Android | ||
| // Brave don't, which is why hint-based Brave detection returns a null | ||
| // version: we have no UA marker to parse. | ||
| [BRAVE]: [new RegExp(BRAVE + '\\/' + BROWSER_VERSION_REGEX_SUFFIX)], | ||
| // DuckDuckGo on iOS uses `Ddg/`, on Android/desktop preview it uses `DuckDuckGo/`. | ||
| [DUCKDUCKGO]: [new RegExp('(DuckDuckGo|Ddg)\\/' + BROWSER_VERSION_REGEX_SUFFIX)], | ||
| [PALE_MOON]: [new RegExp('PaleMoon\\/' + BROWSER_VERSION_REGEX_SUFFIX)], | ||
| [WATERFOX]: [new RegExp(WATERFOX + '\\/' + BROWSER_VERSION_REGEX_SUFFIX)], | ||
| [INTERNET_EXPLORER]: [new RegExp('(rv:|MSIE )' + BROWSER_VERSION_REGEX_SUFFIX)], | ||
@@ -180,4 +258,12 @@ Mozilla: [new RegExp('rv:' + BROWSER_VERSION_REGEX_SUFFIX)], | ||
| */ | ||
| export const detectBrowserVersion = function (userAgent: string, vendor: string | undefined): number | null { | ||
| const browser = detectBrowser(userAgent, vendor) | ||
| export const detectBrowserVersion = function ( | ||
| userAgent: string, | ||
| vendor: string | undefined, | ||
| hints?: BrowserDetectionHints | ||
| ): number | null { | ||
| const browser = detectBrowser(userAgent, vendor, hints) | ||
| // Desktop / Android Brave has no parseable UA version, so it returns null | ||
| // below: its `versionRegexes` entry only matches the iOS `Brave/` marker | ||
| // (absent from a desktop Chrome UA). | ||
| const regexes: RegExp[] | undefined = versionRegexes[browser as keyof typeof versionRegexes] | ||
@@ -184,0 +270,0 @@ if (isUndefined(regexes)) { |
URL strings
Supply chain riskPackage contains fragments of external URLs or IP addresses, which the package may be accessing at runtime.
Found 1 instance in 1 package
URL strings
Supply chain riskPackage contains fragments of external URLs or IP addresses, which the package may be accessing at runtime.
Found 1 instance in 1 package
1056519
0.74%24848
0.72%+ Added
- Removed
Updated