Compare commits

..

31 Commits

Author SHA1 Message Date
Faisal Salman
5b5e33681f Merge tag '2.0.5' into pro-personal 2025-09-21 08:59:46 +07:00
Faisal Salman
3ea5721e86 Bump version 2.0.5 2025-09-05 21:43:09 +07:00
Faisal Salman
a4342b01d4 [test] Utilize enum in test cases 2025-09-04 20:59:48 +07:00
Faisal Salman
31bf36c36d [enums] enum names should be singular 2025-09-04 20:58:10 +07:00
Faisal Salman
9bef871e41 [helpers] Update isAIBot() list using Crawlers enum 2025-09-02 22:00:02 +07:00
Faisal Salman
b1d9dcafcd [test] Move UA-CH test data into its own file 2025-09-01 23:13:00 +07:00
Faisal Salman
146f182533 [extensions] Improve bot detection for ByteDance, Google, SB Intuitions, Webzio 2025-08-31 20:04:49 +07:00
Faisal Salman
ce242a362f [extensions][enums] Improve detection for Yandex bots 2025-08-30 17:01:05 +07:00
Faisal Salman
2078b1ec92 [enums] Clean up enum imports & create build script 2025-08-29 17:53:09 +07:00
Faisal Salman
7dcbb8def3 [enums] Enum for CPU architecture should be CPUArch rather than CPUName 2025-08-28 11:14:21 +07:00
Faisal Salman
f810a6d1d9 Fix type mistake 2025-08-27 14:57:09 +07:00
Faisal Salman
0e05332609 [enums] Add enums for extensions submodule 2025-08-27 12:14:56 +07:00
Faisal Salman
48a1f34c28 [enums] Rename & mark as deprecated: Browser->BrowserName, CPU->CPUName, Device->DeviceType, Vendor->DeviceVendor, Engine->EngineName, OS->OSName 2025-08-27 12:13:06 +07:00
Faisal Salman
fb1ed5cf6b Only check for direct properties from the headers object 2025-08-26 22:35:46 +07:00
Faisal Salman
3e65196b57 Normalize all headers into lowercase 2025-08-26 00:18:53 +07:00
Faisal Salman
4e421e72fe Main d.ts: replace hardcoded type def with enum values 2025-08-23 21:14:12 +07:00
Faisal Salman
98cf19c8c5 Main d.ts export type UAParserHeaders 2025-08-23 19:06:07 +07:00
Faisal Salman
c9badeb345 [extensions] Add new crawlers: Algolia, Baidu, BLEXBot, Botify, Freespoke, Marginalia, MSNBot, OnCrawl, SeekportBot, Siteimprove, TwinAgent, YepBot, ZumBot 2025-08-21 21:40:50 +07:00
Faisal Salman
9003fe5724 [extensions] Add new bots: Algolia Crawler, contxbot, HubSpot Page Fetcher, Kagibot 2025-08-15 20:42:41 +07:00
Faisal Salman
975c4860f4 [extensions][helpers] Add some new AI bots: Bravebot, Cotoyogi, FirecrawlAgent, HuggingFace-Bot, Kangaroo Bot, PanguBot, Replicate-Bot, RunPod-Bot, Together-Bot, xAI-Bot 2025-08-14 20:42:17 +07:00
Faisal Salman
647b6232bd [extensions][helpers] Add some bots from Vercel: v0bot, vercel-favicon-bot, vercel-screenshot-bot, vercelflags, verceltracing 2025-08-14 19:34:14 +07:00
Faisal Salman
95485f7b5d [extensions][helpers] Add new bots: cohere-training-data-crawler, Gemini-Deep-Research, kakaotalk-scrap, TikTokSpider 2025-08-11 13:14:45 +07:00
Faisal Salman
74ef71cf63 [extensions][helpers] Add new bots: Asana, bitlybot, Chrome-Lighthouse, DeepSeekBot, DuckDuckGo-Favicons-Bot, Elastic, Zoombot 2025-08-10 00:40:20 +07:00
Harlan Brawer
9e6dff6dc3 replace node fetch types with undici 2025-08-09 23:38:52 +07:00
Faisal Salman
bf5155ec8a Add new vendor: Philips 2025-08-09 23:01:29 +07:00
Aidan Nulman
ecbc0336b6
Fix #797: Iterate over brands as an array (#798) 2025-08-01 18:34:36 +07:00
Suryaansh Chawla
ab299a23b7
Zalo integration in UAParser (#1) (#792) 2025-08-01 18:33:52 +07:00
undefined
3fe137e533
chore: move node-fetch to devDeps (#784) 2025-08-01 18:33:10 +07:00
Faisal Salman
0bb6e24837 [extensions] Add new bots: Blueno, BufferLinkPreviewBot, Claude-SearchBot, Claude-User, Coveobot, CriteoBot 2025-07-22 12:29:01 +07:00
Faisal Salman
a19977ce4c Fix #796: Improve device detection for Pico Neo 3 2025-07-21 11:53:03 +07:00
Faisal Salman
088383b9bd Add new CPU architecture: alpha 2025-07-21 11:43:26 +07:00
34 changed files with 3326 additions and 1119 deletions

View File

@ -65,6 +65,35 @@
---
## Version 2.0.5
- Add new browser: Zalo
- Add new CPU arch: alpha
- Add new device vendor: Philips
- Improve device detection: Pico
- Fix parsing error on pages with modified Array prototypes
- Improve type declarations:
- Replace `node-fetch` dependency with `undici`
- Replace hardcoded string values with enum from `enum` submodule
- `enums` submodule:
- Add `Extension` enum for `extensions` submodule
- Type declaration file now automatically generated using build script
- Naming adjustments:
- `Browser` => `BrowserName`
- `CPU` => `CPUArch`
- `Device` => `DeviceType`
- `Vendor` => `DeviceVendor`
- `Engine` => `EngineName`
- `OS` => `OSName`
- `extensions` submodule:
- Add new crawlers:
APIs-Google, Algolia Crawler, Algolia Crawler Renderscript, Baidu-ADS, BLEXBot, botify, Bravebot, Claude-Web, cohere-training-data-crawler, contxbot, Cotoyogi, Coveobot, CriteoBot, DeepSeekBot, DuckDuckGo-Favicons-Bot, Elastic, FirecrawlAgent, Freespoke, Google-CloudVertexBot, HuggingFace-Bot, Kagibot, Kangaroo Bot, marginalia, msnbot, OnCrawl, Replicate-Bot, RunPod-Bot, SBIntuitionsBot, SeekportBot, Siteimprove, Sogou Pic Spider, TikTokSpider, TwinAgent, v0bot, webzio, Webzio-Extended, xAI-Bot, YandexAccessibilityBot, YandexAdditionalBot, YandexAdNet, YandexBot MirrorDetector, YandexBlogs, YandexComBot, YandexFavicons, YandexImageResizer, YandexImages, YandexMarket, YandexMetrika, YandexMedia, YandexMobileBot, YandexMobileScreenShotBot, YandexNews, YandexOntoDB, YandexOntoDBAPI, YandexPartner, YandexRCA, YandexRenderResourcesBot, YandexScreenshotBot, YandexSpravBot, YandexTracker, YandexVertis, YandexVerticals, YandexVideo, YandexVideoParser, YandexWebmaster, YepBot, ZumBot
- Add new fetchers:
Asana, bitlybot, Blueno, BufferLinkPreviewBot, Chrome-Lighthouse, Gemini-Deep-Research, HubSpot Page Fetcher, kakaotalk-scrap, vercel-favicon-bot, vercel-screenshot-bot, vercelflags, verceltracing, YaDirectFetcher, YandexCalendar, YandexDirect, YandexDirectDyn, YandexForDomain, YandexPagechecker, YandexSearchShop, YandexSitelinks, YandexUserproxy
- `helpers` submodule:
- Add some crawler to `isAIBot()`:
Bravebot, cohere-training-data-crawler, FirecrawlAgent, HuggingFace-Bot, Kangaroo Bot, PanguBot, Replicate-Bot, RunPod-Bot, TikTokSpider, Together-Bot, v0bot, xAI-Bot
## Version 2.0.4
- Add new browser: Edge WebView, Edge WebView2
@ -240,6 +269,16 @@
---
## Version 0.7.41 / 1.0.41
- Add new browser: Daum, Ladybird
- Add new device vendor: HMD
- Add new engine: LibWeb
- Add new os: Windows IoT, Ubuntu Touch
- Improve cpu detection: ARM, x86
- Improve device vendor detection: Apple, Archos, Generic, Google, Honor, Huawei, Infinix, Nvidia, Lenovo, Nokia, OnePlus, Xiaomi
- Improve device type detection: smarttv, wearables
- Improve os detection: Linux, Symbian
## Version 0.7.40 / 1.0.40
- Add new browser: 115, LibreWolf, Slimboat, Slimjet
- Add new device: Advan, Cat, Energizer, IMO, Micromax, Smartfren

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

132
package-lock.json generated
View File

@ -1,12 +1,12 @@
{
"name": "@ua-parser-js/pro-personal",
"version": "2.0.4",
"version": "2.0.5",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "@ua-parser-js/pro-personal",
"version": "2.0.4",
"version": "2.0.5",
"funding": [
{
"type": "opencollective",
@ -23,11 +23,10 @@
],
"license": "SEE LICENSE IN LICENSE.md",
"dependencies": {
"@types/node-fetch": "^2.6.12",
"detect-europe-js": "^0.1.2",
"is-standalone-pwa": "^0.1.1",
"node-fetch": "^2.7.0",
"ua-is-frozen": "^0.1.2"
"ua-is-frozen": "^0.1.2",
"undici": "^7.12.0"
},
"bin": {
"pro-personal": "script/cli.js"
@ -402,23 +401,6 @@
"integrity": "sha512-hov8bUuiLiyFPGyFPE1lwWhmzYbirOXQNNo40+y3zow8aFVTeyn3VWL0VFFfdNddA8S4Vf0Tc062rzyNr7Paag==",
"dev": true
},
"node_modules/@types/node": {
"version": "22.13.1",
"resolved": "https://registry.npmjs.org/@types/node/-/node-22.13.1.tgz",
"integrity": "sha512-jK8uzQlrvXqEU91UxiK5J7pKHyzgnI1Qnl0QDHIgVGuolJhRb9EEl28Cj9b3rGR8B2lhFCtvIm5os8lFnO/1Ew==",
"dependencies": {
"undici-types": "~6.20.0"
}
},
"node_modules/@types/node-fetch": {
"version": "2.6.12",
"resolved": "https://registry.npmjs.org/@types/node-fetch/-/node-fetch-2.6.12.tgz",
"integrity": "sha512-8nneRWKCg3rMtF69nLQJnOYUcbafYeFSjqkw3jCRLsqkWFlHaoQrr5mXmofFGOx3DKn7UfmBMyov8ySvLRVldA==",
"dependencies": {
"@types/node": "*",
"form-data": "^4.0.0"
}
},
"node_modules/@types/normalize-package-data": {
"version": "2.4.4",
"resolved": "https://registry.npmjs.org/@types/normalize-package-data/-/normalize-package-data-2.4.4.tgz",
@ -519,11 +501,6 @@
"node": ">=0.10.0"
}
},
"node_modules/asynckit": {
"version": "0.4.0",
"resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
"integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q=="
},
"node_modules/balanced-match": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
@ -664,17 +641,6 @@
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
"dev": true
},
"node_modules/combined-stream": {
"version": "1.0.8",
"resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
"integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
"dependencies": {
"delayed-stream": "~1.0.0"
},
"engines": {
"node": ">= 0.8"
}
},
"node_modules/concat-map": {
"version": "0.0.1",
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
@ -753,14 +719,6 @@
"node": ">=0.10.0"
}
},
"node_modules/delayed-stream": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
"integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==",
"engines": {
"node": ">=0.4.0"
}
},
"node_modules/detect-europe-js": {
"version": "0.1.2",
"resolved": "https://registry.npmjs.org/detect-europe-js/-/detect-europe-js-0.1.2.tgz",
@ -1011,19 +969,6 @@
"flat": "cli.js"
}
},
"node_modules/form-data": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.1.tgz",
"integrity": "sha512-tzN8e4TX8+kkxGPK8D5u0FNmjPUjw3lwC9lSLxxoB/+GtsJG91CO8bSWy73APlgAZzZbXEYZJuxjkHH2w+Ezhw==",
"dependencies": {
"asynckit": "^0.4.0",
"combined-stream": "^1.0.8",
"mime-types": "^2.1.12"
},
"engines": {
"node": ">= 6"
}
},
"node_modules/fs.realpath": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
@ -1591,25 +1536,6 @@
"node": ">=8.6"
}
},
"node_modules/mime-db": {
"version": "1.52.0",
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
"integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==",
"engines": {
"node": ">= 0.6"
}
},
"node_modules/mime-types": {
"version": "2.1.35",
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz",
"integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
"dependencies": {
"mime-db": "1.52.0"
},
"engines": {
"node": ">= 0.6"
}
},
"node_modules/min-indent": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/min-indent/-/min-indent-1.0.1.tgz",
@ -1963,25 +1889,6 @@
"node": "^10 || ^12 || >=13.7"
}
},
"node_modules/node-fetch": {
"version": "2.7.0",
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz",
"integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==",
"dependencies": {
"whatwg-url": "^5.0.0"
},
"engines": {
"node": "4.x || >=6.0.0"
},
"peerDependencies": {
"encoding": "^0.1.0"
},
"peerDependenciesMeta": {
"encoding": {
"optional": true
}
}
},
"node_modules/normalize-package-data": {
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-3.0.3.tgz",
@ -2713,11 +2620,6 @@
"node": ">=8.0"
}
},
"node_modules/tr46": {
"version": "0.0.3",
"resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz",
"integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw=="
},
"node_modules/trim-newlines": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/trim-newlines/-/trim-newlines-3.0.1.tgz",
@ -2791,10 +2693,14 @@
"node": ">=0.8.0"
}
},
"node_modules/undici-types": {
"version": "6.20.0",
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.20.0.tgz",
"integrity": "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg=="
"node_modules/undici": {
"version": "7.12.0",
"resolved": "https://registry.npmjs.org/undici/-/undici-7.12.0.tgz",
"integrity": "sha512-GrKEsc3ughskmGA9jevVlIOPMiiAHJ4OFUtaAH+NhfTUSiZ1wMPIQqQvAJUrJspFXJt3EBWgpAeoHEDVT1IBug==",
"license": "MIT",
"engines": {
"node": ">=20.18.1"
}
},
"node_modules/validate-npm-package-license": {
"version": "3.0.4",
@ -2806,20 +2712,6 @@
"spdx-expression-parse": "^3.0.0"
}
},
"node_modules/webidl-conversions": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz",
"integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ=="
},
"node_modules/whatwg-url": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz",
"integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==",
"dependencies": {
"tr46": "~0.0.3",
"webidl-conversions": "^3.0.0"
}
},
"node_modules/which": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",

View File

@ -1,7 +1,7 @@
{
"title": "UAParser.js PRO Personal",
"name": "@ua-parser-js/pro-personal",
"version": "2.0.4",
"version": "2.0.5",
"author": "Faisal Salman <f@faisalman.com> (http://faisalman.com)",
"description": "Detect Browser, Engine, OS, CPU, and Device type/model from User-Agent & Client Hints data. Supports browser & node.js environment",
"keywords": [
@ -227,8 +227,7 @@
"detect-europe-js": "^0.1.2",
"is-standalone-pwa": "^0.1.1",
"ua-is-frozen": "^0.1.2",
"node-fetch": "^2.7.0",
"@types/node-fetch": "^2.6.12"
"undici": "^7.12.0"
},
"devDependencies": {
"@babel/parser": "7.15.8",

View File

@ -2,15 +2,18 @@
/* jshint esversion: 6 */
const fs = require('fs');
const generateMJS = (module) => {
let { src, dest, title, replacements } = module;
let text = fs.readFileSync(src, 'utf-8');
replacements.push(
const defaultReplacements = {
mjs: [
[/const (.+?)\s*=\s*require\(\'\.(.+)\'\)/ig, 'import $1 from \'\.$2.mjs\''],
[/const (.+?)\s*=\s*require\(\'(.+)\'\)/ig, 'import $1 from \'$2\''],
[/module\.exports =/ig, 'export']
);
]
}
const generateFile = (module) => {
let { src, dest, title, replacements } = module;
let text = fs.readFileSync(src, 'utf-8');
replacements.forEach(rep => {
text = text.replace(rep[0], rep[1]);
});
@ -18,42 +21,54 @@ const generateMJS = (module) => {
console.log(`Generate ${dest}`);
fs.writeFileSync(dest,
`// Generated ESM version of ${title}
`// ${title}
// DO NOT EDIT THIS FILE!
// Source: /${src}
${text}`, 'utf-8');
};
const modules = [
const files = [
{
src : 'src/main/ua-parser.js',
dest : 'src/main/ua-parser.mjs',
title : 'ua-parser-js',
title : 'Generated ESM version of ua-parser-js',
replacements : [
[/\(func[\s\S]+strict\';/ig, ''],
[/esversion\: 3/ig, 'esversion: 6'],
[/\/[\/\s]+export[\s\S]+/ig,'export {UAParser};']
[/\/[\/\s]+export[\s\S]+/ig,'export {UAParser};'],
...defaultReplacements.mjs
]
},{
},
{
src : 'src/enums/ua-parser-enums.js',
dest :'src/enums/ua-parser-enums.mjs',
title : 'ua-parser-js/enums',
replacements : []
title : 'Generated ESM version of ua-parser-js/enums',
replacements : [...defaultReplacements.mjs]
},
{
src : 'src/enums/ua-parser-enums.js',
dest :'src/enums/ua-parser-enums.d.ts',
title : 'Generated type declarations of ua-parser-js/enums',
replacements : [
[/(const .+) = object\.freeze\(/ig, 'export $1: Readonly<'],
[/(const .+) =( .+;)/ig, 'export $1: typeof$2'],
[/}\);/ig, '}>;'],
[/module\.exports =.+/igs, '']
]
},
{
src : 'src/extensions/ua-parser-extensions.js',
dest : 'src/extensions/ua-parser-extensions.mjs',
title : 'ua-parser-js/extensions',
replacements : []
title : 'Generated ESM version of ua-parser-js/extensions',
replacements : [...defaultReplacements.mjs]
},
{
src : 'src/helpers/ua-parser-helpers.js',
dest : 'src/helpers/ua-parser-helpers.mjs',
title : 'ua-parser-js/helpers',
replacements : []
title : 'Generated ESM version of ua-parser-js/helpers',
replacements : [...defaultReplacements.mjs]
}
];
modules.forEach(module => generateMJS(module));
files.forEach(module => generateFile(module));

File diff suppressed because it is too large Load Diff

View File

@ -1,5 +1,5 @@
///////////////////////////////////////////////
/* Enums for UAParser.js v2.0.4
/* Enums for UAParser.js v2.0.5
https://github.com/faisalman/ua-parser-js
Author: Faisal Salman <f@faisalman.com>
UAParser.js PRO Personal License */
@ -7,7 +7,7 @@
/*jshint esversion: 6 */
const Browser = Object.freeze({
const BrowserName = Object.freeze({
'115': '115',
'2345': '2345',
'360': '360',
@ -158,10 +158,15 @@ const Browser = Object.freeze({
WEIBO: 'Weibo',
WHALE: 'Whale',
WOLVIC: 'Wolvic',
YANDEX: 'Yandex'
YANDEX: 'Yandex',
ZALO: 'Zalo'
// TODO : test!
});
/**
* @deprecated Use `BrowserName` instead
*/
const Browser = BrowserName;
const BrowserType = Object.freeze({
CRAWLER: 'crawler',
@ -173,8 +178,9 @@ const BrowserType = Object.freeze({
LIBRARY: 'library'
});
const CPU = Object.freeze({
const CPUArch = Object.freeze({
'68K': '68k',
ALPHA: 'alpha',
ARM : 'arm',
ARM_64: 'arm64',
ARM_HF: 'armhf',
@ -192,8 +198,12 @@ const CPU = Object.freeze({
X86: 'ia32',
X86_64: 'amd64'
});
/**
* @deprecated Use `CPUArch` instead
*/
const CPU = CPUArch;
const Device = Object.freeze({
const DeviceType = Object.freeze({
CONSOLE: 'console',
DESKTOP: 'desktop',
EMBEDDED: 'embedded',
@ -203,8 +213,12 @@ const Device = Object.freeze({
WEARABLE: 'wearable',
XR: 'xr'
});
/**
* @deprecated Use `DeviceType` instead
*/
const Device = DeviceType;
const Vendor = Object.freeze({
const DeviceVendor = Object.freeze({
ACER: 'Acer',
ADVAN: 'Advan',
ALCATEL: 'Alcatel',
@ -252,6 +266,7 @@ const Vendor = Object.freeze({
PALM: 'Palm',
PANASONIC: 'Panasonic',
PEBBLE: 'Pebble',
PHILIPS: 'Philips',
PICO: 'Pico',
POLYTRON: 'Polytron',
REALME: 'Realme',
@ -266,7 +281,7 @@ const Vendor = Object.freeze({
SPRINT: 'Sprint',
TCL: 'TCL',
TECHNISAT: 'TechniSAT',
TECNO: 'Tecno',
TECNO: 'TECNO',
TESLA: 'Tesla',
ULEFONE: 'Ulefone',
VIVO: 'Vivo',
@ -279,8 +294,12 @@ const Vendor = Object.freeze({
// TODO : test!
});
/**
* @deprecated Use `DeviceVendor` instead
*/
const Vendor = DeviceVendor;
const Engine = Object.freeze({
const EngineName = Object.freeze({
AMAYA: 'Amaya',
ARKWEB: 'ArkWeb',
BLINK: 'Blink',
@ -302,8 +321,12 @@ const Engine = Object.freeze({
W3M: 'w3m',
WEBKIT: 'WebKit'
});
/**
* @deprecated Use `EngineName` instead
*/
const Engine = EngineName;
const OS = Object.freeze({
const OSName = Object.freeze({
AIX: 'AIX',
AMIGA_OS: 'Amiga OS',
ANDROID: 'Android',
@ -399,13 +422,322 @@ const OS = Object.freeze({
// TODO : test!
});
/**
* @deprecated Use `OSName` instead
*/
const OS = OSName;
/*////////////////////////////////
* Enums for Extensions submodule
*///////////////////////////////
const Extension = Object.freeze({
BrowserName: {
CLI: {
CURL: 'curl',
ELINKS: 'ELinks',
HTTPIE: 'HTTPie',
LYNX: 'Lynx',
WGET: 'Wget'
},
Crawler: {
AHREFS_BOT: 'AhrefsBot',
AI2_BOT: 'AI2Bot',
AIHIT_BOT: 'aiHitBot',
ALGOLIA_CRAWLER: 'Algolia Crawler',
APPLE_BOT: 'Applebot',
APPLE_BOT_EXTENDED: 'Applebot-Extended',
ASK_TEOMA: 'Teoma',
AMAZON_BOT: 'Amazonbot',
AMAZON_CONTXBOT: 'contxbot',
ANTHROPIC_AI: 'anthropic-ai',
ANTHROPIC_CLAUDE_BOT: 'ClaudeBot',
ANTHROPIC_CLAUDE_SEARCHBOT: 'Claude-SearchBot',
ANTHROPIC_CLAUDE_WEB: 'Claude-Web',
ARCHIVEORG_BOT: 'archive.org_bot',
BAIDU_ADS: 'Baidu-ADS',
BAIDU_SPIDER: 'Baiduspider',
BAIDU_SPIDER_ADS: 'Baiduspider-ads',
BAIDU_SPIDER_CPRO: 'Baiduspider-cpro',
BAIDU_SPIDER_FAVO: 'Baiduspider-favo',
BAIDU_SPIDER_IMAGE: 'Baiduspider-image',
BAIDU_SPIDER_NEWS: 'Baiduspider-news',
BAIDU_SPIDER_RENDER: 'Baiduspider-render',
BAIDU_SPIDER_VIDEO: 'Baiduspider-video',
BLEX_BOT: 'BLEXBot',
BOTIFY: 'botify',
BRAVE_BOT: 'Bravebot',
BYTEDANCE_BYTESPIDER: 'Bytespider',
BYTEDANCE_TIKTOKSPIDER: 'TikTokSpider',
COMMON_CRAWL_CCBOT: 'CCBot',
COCCOC_BOT_WEB: 'coccocbot-web',
COCCOC_BOT_IMAGE: 'coccocbot-image',
COHERE_TRAINING_DATA_CRAWLER: 'cohere-training-data-crawler',
COTOYOGI: 'Cotoyogi',
COVEO_BOT: 'Coveobot',
CRITEO_BOT: 'CriteoBot',
DATAFORSEO_BOT: 'DataForSeoBot',
DAUM: 'Daum',
DAUM_DAUMOA: 'Daumoa',
DAUM_DAUMOA_IMAGE: 'Daumoa-image',
DEEPSEEK_BOT: 'DeepSeekBot',
DIFFBOT: 'Diffbot',
DUCKDUCKGO_BOT: 'DuckDuckBot',
DUCKDUCKGO_FAVICONS_BOT: 'DuckDuckGo-Favicons-Bot',
ELASTIC: 'Elastic',
EXALEAD_EXABOT: 'Exabot',
FIRECRAWL_AGENT: 'FirecrawlAgent',
FREESPOKE: 'Freespoke',
GOOGLE_ADSBOT: 'AdsBot-Google',
GOOGLE_ADSBOT_MOBILE: 'Adsbot-Google-Mobile',
GOOGLE_ADSENSE: 'AdSense',
GOOGLE_APIS: 'APIs-Google',
GOOGLE_BOT: 'Googlebot',
GOOGLE_BOT_IMAGE: 'Googlebot-Image',
GOOGLE_BOT_NEWS: 'Googlebot-News',
GOOGLE_BOT_VIDEO: 'Googlebot-Video',
GOOGLE_CLOUDVERTEXBOT: 'Google-CloudVertexBot',
GOOGLE_EXTENDED: 'Google-Extended',
GOOGLE_INSPECTIONTOOL: 'Google-InspectionTool',
GOOGLE_OTHER: 'GoogleOther',
GOOGLE_OTHER_IMAGE: 'GoogleOther-Image',
GOOGLE_OTHER_VIDEO: 'GoogleOther-Video',
GOOGLE_SAFETY: 'Google-Safety',
GOOGLE_STOREBOT: 'Storebot-Google',
HIVE_IMAGESIFTBOT: 'ImagesiftBot',
HUAWEI_PANGUBOT: 'PanguBot',
HUAWEI_PETALBOT: 'PetalBot',
HUGGINGFACE_BOT: 'HuggingFace-Bot',
HUNTER_VELENPUBLICWEBCRAWLER: 'VelenPublicWebCrawler',
IA_ARCHIVER: 'ia_archiver',
IASK_BOT: 'iAskBot',
KAGI_BOT: 'Kagibot',
KANGAROO_BOT: 'Kangaroo Bot',
LINE_SPIDER: 'Linespider',
LINKEDIN_BOT: 'LinkedInBot',
MAGPIE_CRAWLER: 'magpie-crawler',
MARGINALIA: 'marginalia',
META_EXTERNALAGENT: 'meta-externalagent',
META_FACEBOOKBOT: 'FacebookBot',
META_FACEBOOKCATALOG: 'facebookcatalog',
META_FACEBOOKEXTERNALHIT: 'facebookexternalhit',
MAJESTIC_MJ12BOT: 'MJ12bot',
MICROSOFT_BINGBOT: 'Bingbot',
MICROSOFT_MSNBOT: 'msnbot',
MICROSOFT_ADIDXBOT: 'adidxbot',
MOJEEK_BOT: 'MojeekBot',
MOZ_DOTBOT: 'DotBot',
ONCRAWL: 'OnCrawl',
ONESPOT_SCRAPERBOT: 'Onespot-ScraperBot',
OPENAI_GPTBOT: 'GPTBot',
OPENAI_SEARCH_BOT: 'OAI-SearchBot',
PERPLEXITY_BOT: 'PerplexityBot',
QIHOO_360_SPIDER: '360Spider',
QWANT_BOT: 'Qwantbot',
REPLICATE_BOT: 'Replicate-Bot',
RUNPOD_BOT: 'RunPod-Bot',
SB_INTUITIONS_BOT: 'SBIntuitionsBot',
SEEKPORT_BOT: 'SeekportBot',
SEMRUSH_BOT: 'SemrushBot',
SEMRUSH_BOT_BACKLINK: 'SemrushBot-BA',
SEMRUSH_BOT_CONTENTSHAKE: 'SemrushBot-OCOB',
SEMRUSH_BOT_SEO_CHECKER: 'SemrushBot-SI',
SEZNAM_BOT: 'SeznamBot',
SITEIMPROVE: 'Siteimprove',
SOGOU_PIC_SPIDER: 'Sogou Pic Spider',
SOGOU_WEB_SPIDER: 'Sogou web spider',
STARTPAGE: 'Startpage',
TIMPI_BOT: 'Timpibot',
TOGETHER_BOT: 'Together-Bot',
TURNITIN_BOT: 'TurnitinBot',
TWIN_AGENT: 'TwinAgent',
VERCEL_V0BOT: 'v0bot',
WEBZIO: 'webzio',
WEBZIO_EXTENDED: 'Webzio-Extended',
WEBZIO_OMGILI: 'omgili',
WEBZIO_OMGILI_BOT: 'omgilibot',
XAI_BOT: 'xAI-Bot',
YAHOO_JAPAN: 'Y!J-BRW',
YAHOO_SLURP: 'Yahoo! Slurp',
YANDEX_ACCESSIBILITY_BOT: 'YandexAccessibilityBot',
YANDEX_ADDITIONAL_BOT: 'YandexAdditionalBot',
YANDEX_ADNET: 'YandexAdNet',
YANDEX_BLOGS: 'YandexBlogs',
YANDEX_BOT: 'YandexBot',
YANDEX_BOT_MIRRORDETECTOR: 'YandexBot MirrorDetector',
YANDEX_COMBOT: 'YandexComBot',
YANDEX_FAVICONS: 'YandexFavicons',
YANDEX_IMAGE_RESIZER: 'YandexImageResizer',
YANDEX_IMAGES: 'YandexImages',
YANDEX_MARKET: 'YandexMarket',
YANDEX_MEDIA: 'YandexMedia',
YANDEX_METRIKA: 'YandexMetrika',
YANDEX_MOBILE_BOT: 'YandexMobileBot',
YANDEX_MOBILE_SCREENSHOT_BOT: 'YandexMobileScreenShotBot',
YANDEX_NEWS: 'YandexNews',
YANDEX_ONTODB: 'YandexOntoDB',
YANDEX_ONTODB_API: 'YandexOntoDBAPI',
YANDEX_PARTNER: 'YandexPartner',
YANDEX_RCA: 'YandexRCA',
YANDEX_RENDERRESOURCES_BOT: 'YandexRenderResourcesBot',
YANDEX_SCREENSHOT_BOT: 'YandexScreenshotBot',
YANDEX_SPRAV_BOT: 'YandexSpravBot',
YANDEX_TRACKER: 'YandexTracker',
YANDEX_VERTICALS: 'YandexVerticals',
YANDEX_VERTIS: 'YandexVertis',
YANDEX_VIDEO: 'YandexVideo',
YANDEX_VIDEO_PARSER: 'YandexVideoParser',
YANDEX_WEBMASTER: 'YandexWebmaster',
YEP_BOT: 'YepBot',
YETI: 'Yeti',
YISOU_SPIDER: 'YisouSpider',
YOU_BOT: 'YouBot',
ZHIPU_CHATGLM_SPIDER: 'ChatGLM-Spider',
ZUM_BOT: 'ZumBot'
},
Email: {
AIRMAIL: 'Airmail',
APPLE_MAIL: 'Mail',
BLUEMAIL: 'BlueMail',
DAUM_MAIL: 'DaumMail',
EVOLUTION: 'Evolution',
EM_CLIENT: 'eM Client',
FOXMAIL: 'Foxmail',
KMAIL: 'KMail',
KMAIL2: 'kmail2',
KONTACT: 'Kontact',
MICROSOFT_OUTLOOK: 'Microsoft Outlook',
MICROSOFT_OUTLOOK_MAC: 'MacOutlook',
NAVER_MAILAPP: 'NaverMailApp',
POLYMAIL: 'Polymail',
PROTON_MAIL: 'ProtonMail',
SPARK_MAIL: 'SparkDesktop',
SPARROW: 'Sparrow',
THUNDERBIRD: 'Thunderbird',
YAHOO_MAIL: 'Yahoo',
ZIMBRA: 'Zimbra',
ZOHO_MAIL: 'ZohoMail-Desktop'
},
Fetcher: {
AHREFS_SITEAUDIT: 'AhrefsSiteAudit',
ANTHROPIC_CLAUDE_USER: 'Claude-User',
ASANA: 'Asana',
BETTER_UPTIME_BOT: 'Better Uptime Bot',
BITLY_BOT: 'bitlybot',
BLUESKY: 'Bluesky',
BUFFER_LINKPREVIEWBOT: 'BufferLinkPreviewBot',
COHERE_AI: 'Cohere-AI',
DUCKDUCKGO_ASSISTBOT: 'DuckAssistBot',
GOOGLE_CHROME_LIGHTHOUSE: 'Chrome-Lighthouse',
GOOGLE_FEEDFETCHER: 'FeedFetcher-Google',
GOOGLE_GEMINI_DEEP_RESEARCH: 'Gemini-Deep-Research',
GOOGLE_IMAGEPROXY: 'GoogleImageProxy',
GOOGLE_PAGERENDERER: 'Google-PageRenderer',
GOOGLE_READ_ALOUD: 'Google-Read-Aloud',
GOOGLE_PRODUCER: 'GoogleProducer',
GOOGLE_SITE_VERIFICATION: 'Google-Site-Verification',
HUBSPOT_PAGE_FETCHER: 'HubSpot Page Fetcher',
IFRAMELY: 'Iframely',
KAKAOTALK_SCRAP: 'kakaotalk-scrap',
META_EXTERNALFETCHER: 'meta-externalfetcher',
META_WHATSAPP: 'WhatsApp',
MICROSOFT_BINGPREVIEW: 'BingPreview',
MICROSOFT_PREVIEW: 'MicrosoftPreview',
MISTRALAI_USER: 'MistralAI-User',
NAVER_BLUENO: 'Blueno',
ONCRAWL_ROGERBOT: 'rogerbot',
OPENAI_CHATGPT_USER: 'ChatGPT-User',
PERPLEXITY_USER: 'Perplexity-User',
PINTEREST_BOT: 'Pinterestbot',
SEMRUSH_SITEAUDITBOT: 'SiteAuditBot',
SNAP_URL_PREVIEW: 'Snap URL Preview',
SKYPE_URIPREVIEW: 'SkypeUriPreview',
TELEGRAM_BOT: 'TelegramBot',
UPTIMEROBOT: 'UptimeRobot',
VERCEL_FAVICON_BOT: 'vercel-favicon-bot',
VERCEL_SCREENSHOT_BOT: 'vercel-screenshot-bot',
VERCEL_BOT: 'Vercelbot',
VERCEL_FLAGS: 'vercelflags',
VERCEL_TRACING: 'verceltracing',
YANDEX_CALENDAR: 'YandexCalendar',
YANDEX_DIRECT: 'YandexDirect',
YANDEX_DIRECTDYN: 'YandexDirectDyn',
YANDEX_DIRECTFETCHER: 'YaDirectFetcher',
YANDEX_FORDOMAIN: 'YandexForDomain',
YANDEX_PAGECHECKER: 'YandexPagechecker',
YANDEX_SEARCHSHOP: 'YandexSearchShop',
YANDEX_SITELINKS: 'YandexSitelinks',
YANDEX_USERPROXY: 'YandexUserproxy',
ZOOMINFO_BOT: 'Zoombot'
},
InApp: {
DISCORD: 'Discord',
EVERNOTE: 'Evernote',
FIGMA: 'Figma',
FLIPBOARD: 'Flipboard',
MATTERMOST: 'Mattermost',
TEAMS: 'Teams',
NOTION: 'Notion',
POSTMAN: 'Postman',
RAMBOX: 'Rambox',
ROCKETCHAT: 'Rocket.Chat',
SLACK: 'Slack',
TIKTOK_LITE: 'TikTok Lite',
VSCODE: 'VS Code',
YAHOO_JAPAN: 'Yahoo! Japan'
},
Library: {
ADOBE_AIR: 'AdobeAIR',
AIOHTTP: 'aiohttp',
APACHE_HTTPCLIENT: 'Apache-HttpClient',
AXIOS: 'axios',
GO_HTTP_CLIENT: 'go-http-client',
GOT: 'got',
GUZZLEHTTP: 'GuzzleHttp',
JAVA: 'Java',
JAVA_HTTPCLIENT: 'Java-http-client',
JSDOM: 'jsdom',
LIBWWW_PERL: 'libwww-perl',
LUA_RESTY_HTTP: 'lua-resty-http',
NEEDLE: 'Needle',
NUTCH: 'Nutch',
OKHTTP: 'OkHttp',
NODE_FETCH: 'node-fetch',
NODE_SUPERAGENT: 'node-superagent',
PHP_SOAP: 'PHP-SOAP',
POSTMAN_RUNTIME: 'PostmanRuntime',
PYTHON_HTTPX: 'python-httpx',
PYTHON_URLLIB: 'python-urllib',
PYTHON_URLLIB3: 'python-urllib3',
PYTHON_REQUESTS: 'python-requests',
SCRAPY: 'Scrapy'
}
},
DeviceVendor: {
Vehicle: {
BMW: 'BMW',
BYD: 'BYD',
JEEP: 'Jeep',
RIVIAN: 'Rivian',
TESLA: 'Tesla',
VOLVO: 'Volvo'
}
}
});
module.exports = {
Browser,
Browser,// deprecated
CPU, // deprecated
Device, // deprecated
Vendor, // deprecated
Engine, // deprecated
OS, // deprecated
BrowserName,
BrowserType,
CPU,
Device,
Vendor,
Engine,
OS
CPUArch,
DeviceType,
DeviceVendor,
EngineName,
OSName,
Extension
};

View File

@ -3,7 +3,7 @@
// Source: /src/enums/ua-parser-enums.js
///////////////////////////////////////////////
/* Enums for UAParser.js v2.0.4
/* Enums for UAParser.js v2.0.5
https://github.com/faisalman/ua-parser-js
Author: Faisal Salman <f@faisalman.com>
UAParser.js PRO Personal License */
@ -11,7 +11,7 @@
/*jshint esversion: 6 */
const Browser = Object.freeze({
const BrowserName = Object.freeze({
'115': '115',
'2345': '2345',
'360': '360',
@ -162,10 +162,15 @@ const Browser = Object.freeze({
WEIBO: 'Weibo',
WHALE: 'Whale',
WOLVIC: 'Wolvic',
YANDEX: 'Yandex'
YANDEX: 'Yandex',
ZALO: 'Zalo'
// TODO : test!
});
/**
* @deprecated Use `BrowserName` instead
*/
const Browser = BrowserName;
const BrowserType = Object.freeze({
CRAWLER: 'crawler',
@ -177,8 +182,9 @@ const BrowserType = Object.freeze({
LIBRARY: 'library'
});
const CPU = Object.freeze({
const CPUArch = Object.freeze({
'68K': '68k',
ALPHA: 'alpha',
ARM : 'arm',
ARM_64: 'arm64',
ARM_HF: 'armhf',
@ -196,8 +202,12 @@ const CPU = Object.freeze({
X86: 'ia32',
X86_64: 'amd64'
});
/**
* @deprecated Use `CPUArch` instead
*/
const CPU = CPUArch;
const Device = Object.freeze({
const DeviceType = Object.freeze({
CONSOLE: 'console',
DESKTOP: 'desktop',
EMBEDDED: 'embedded',
@ -207,8 +217,12 @@ const Device = Object.freeze({
WEARABLE: 'wearable',
XR: 'xr'
});
/**
* @deprecated Use `DeviceType` instead
*/
const Device = DeviceType;
const Vendor = Object.freeze({
const DeviceVendor = Object.freeze({
ACER: 'Acer',
ADVAN: 'Advan',
ALCATEL: 'Alcatel',
@ -256,6 +270,7 @@ const Vendor = Object.freeze({
PALM: 'Palm',
PANASONIC: 'Panasonic',
PEBBLE: 'Pebble',
PHILIPS: 'Philips',
PICO: 'Pico',
POLYTRON: 'Polytron',
REALME: 'Realme',
@ -270,7 +285,7 @@ const Vendor = Object.freeze({
SPRINT: 'Sprint',
TCL: 'TCL',
TECHNISAT: 'TechniSAT',
TECNO: 'Tecno',
TECNO: 'TECNO',
TESLA: 'Tesla',
ULEFONE: 'Ulefone',
VIVO: 'Vivo',
@ -283,8 +298,12 @@ const Vendor = Object.freeze({
// TODO : test!
});
/**
* @deprecated Use `DeviceVendor` instead
*/
const Vendor = DeviceVendor;
const Engine = Object.freeze({
const EngineName = Object.freeze({
AMAYA: 'Amaya',
ARKWEB: 'ArkWeb',
BLINK: 'Blink',
@ -306,8 +325,12 @@ const Engine = Object.freeze({
W3M: 'w3m',
WEBKIT: 'WebKit'
});
/**
* @deprecated Use `EngineName` instead
*/
const Engine = EngineName;
const OS = Object.freeze({
const OSName = Object.freeze({
AIX: 'AIX',
AMIGA_OS: 'Amiga OS',
ANDROID: 'Android',
@ -403,13 +426,322 @@ const OS = Object.freeze({
// TODO : test!
});
/**
* @deprecated Use `OSName` instead
*/
const OS = OSName;
/*////////////////////////////////
* Enums for Extensions submodule
*///////////////////////////////
const Extension = Object.freeze({
BrowserName: {
CLI: {
CURL: 'curl',
ELINKS: 'ELinks',
HTTPIE: 'HTTPie',
LYNX: 'Lynx',
WGET: 'Wget'
},
Crawler: {
AHREFS_BOT: 'AhrefsBot',
AI2_BOT: 'AI2Bot',
AIHIT_BOT: 'aiHitBot',
ALGOLIA_CRAWLER: 'Algolia Crawler',
APPLE_BOT: 'Applebot',
APPLE_BOT_EXTENDED: 'Applebot-Extended',
ASK_TEOMA: 'Teoma',
AMAZON_BOT: 'Amazonbot',
AMAZON_CONTXBOT: 'contxbot',
ANTHROPIC_AI: 'anthropic-ai',
ANTHROPIC_CLAUDE_BOT: 'ClaudeBot',
ANTHROPIC_CLAUDE_SEARCHBOT: 'Claude-SearchBot',
ANTHROPIC_CLAUDE_WEB: 'Claude-Web',
ARCHIVEORG_BOT: 'archive.org_bot',
BAIDU_ADS: 'Baidu-ADS',
BAIDU_SPIDER: 'Baiduspider',
BAIDU_SPIDER_ADS: 'Baiduspider-ads',
BAIDU_SPIDER_CPRO: 'Baiduspider-cpro',
BAIDU_SPIDER_FAVO: 'Baiduspider-favo',
BAIDU_SPIDER_IMAGE: 'Baiduspider-image',
BAIDU_SPIDER_NEWS: 'Baiduspider-news',
BAIDU_SPIDER_RENDER: 'Baiduspider-render',
BAIDU_SPIDER_VIDEO: 'Baiduspider-video',
BLEX_BOT: 'BLEXBot',
BOTIFY: 'botify',
BRAVE_BOT: 'Bravebot',
BYTEDANCE_BYTESPIDER: 'Bytespider',
BYTEDANCE_TIKTOKSPIDER: 'TikTokSpider',
COMMON_CRAWL_CCBOT: 'CCBot',
COCCOC_BOT_WEB: 'coccocbot-web',
COCCOC_BOT_IMAGE: 'coccocbot-image',
COHERE_TRAINING_DATA_CRAWLER: 'cohere-training-data-crawler',
COTOYOGI: 'Cotoyogi',
COVEO_BOT: 'Coveobot',
CRITEO_BOT: 'CriteoBot',
DATAFORSEO_BOT: 'DataForSeoBot',
DAUM: 'Daum',
DAUM_DAUMOA: 'Daumoa',
DAUM_DAUMOA_IMAGE: 'Daumoa-image',
DEEPSEEK_BOT: 'DeepSeekBot',
DIFFBOT: 'Diffbot',
DUCKDUCKGO_BOT: 'DuckDuckBot',
DUCKDUCKGO_FAVICONS_BOT: 'DuckDuckGo-Favicons-Bot',
ELASTIC: 'Elastic',
EXALEAD_EXABOT: 'Exabot',
FIRECRAWL_AGENT: 'FirecrawlAgent',
FREESPOKE: 'Freespoke',
GOOGLE_ADSBOT: 'AdsBot-Google',
GOOGLE_ADSBOT_MOBILE: 'Adsbot-Google-Mobile',
GOOGLE_ADSENSE: 'AdSense',
GOOGLE_APIS: 'APIs-Google',
GOOGLE_BOT: 'Googlebot',
GOOGLE_BOT_IMAGE: 'Googlebot-Image',
GOOGLE_BOT_NEWS: 'Googlebot-News',
GOOGLE_BOT_VIDEO: 'Googlebot-Video',
GOOGLE_CLOUDVERTEXBOT: 'Google-CloudVertexBot',
GOOGLE_EXTENDED: 'Google-Extended',
GOOGLE_INSPECTIONTOOL: 'Google-InspectionTool',
GOOGLE_OTHER: 'GoogleOther',
GOOGLE_OTHER_IMAGE: 'GoogleOther-Image',
GOOGLE_OTHER_VIDEO: 'GoogleOther-Video',
GOOGLE_SAFETY: 'Google-Safety',
GOOGLE_STOREBOT: 'Storebot-Google',
HIVE_IMAGESIFTBOT: 'ImagesiftBot',
HUAWEI_PANGUBOT: 'PanguBot',
HUAWEI_PETALBOT: 'PetalBot',
HUGGINGFACE_BOT: 'HuggingFace-Bot',
HUNTER_VELENPUBLICWEBCRAWLER: 'VelenPublicWebCrawler',
IA_ARCHIVER: 'ia_archiver',
IASK_BOT: 'iAskBot',
KAGI_BOT: 'Kagibot',
KANGAROO_BOT: 'Kangaroo Bot',
LINE_SPIDER: 'Linespider',
LINKEDIN_BOT: 'LinkedInBot',
MAGPIE_CRAWLER: 'magpie-crawler',
MARGINALIA: 'marginalia',
META_EXTERNALAGENT: 'meta-externalagent',
META_FACEBOOKBOT: 'FacebookBot',
META_FACEBOOKCATALOG: 'facebookcatalog',
META_FACEBOOKEXTERNALHIT: 'facebookexternalhit',
MAJESTIC_MJ12BOT: 'MJ12bot',
MICROSOFT_BINGBOT: 'Bingbot',
MICROSOFT_MSNBOT: 'msnbot',
MICROSOFT_ADIDXBOT: 'adidxbot',
MOJEEK_BOT: 'MojeekBot',
MOZ_DOTBOT: 'DotBot',
ONCRAWL: 'OnCrawl',
ONESPOT_SCRAPERBOT: 'Onespot-ScraperBot',
OPENAI_GPTBOT: 'GPTBot',
OPENAI_SEARCH_BOT: 'OAI-SearchBot',
PERPLEXITY_BOT: 'PerplexityBot',
QIHOO_360_SPIDER: '360Spider',
QWANT_BOT: 'Qwantbot',
REPLICATE_BOT: 'Replicate-Bot',
RUNPOD_BOT: 'RunPod-Bot',
SB_INTUITIONS_BOT: 'SBIntuitionsBot',
SEEKPORT_BOT: 'SeekportBot',
SEMRUSH_BOT: 'SemrushBot',
SEMRUSH_BOT_BACKLINK: 'SemrushBot-BA',
SEMRUSH_BOT_CONTENTSHAKE: 'SemrushBot-OCOB',
SEMRUSH_BOT_SEO_CHECKER: 'SemrushBot-SI',
SEZNAM_BOT: 'SeznamBot',
SITEIMPROVE: 'Siteimprove',
SOGOU_PIC_SPIDER: 'Sogou Pic Spider',
SOGOU_WEB_SPIDER: 'Sogou web spider',
STARTPAGE: 'Startpage',
TIMPI_BOT: 'Timpibot',
TOGETHER_BOT: 'Together-Bot',
TURNITIN_BOT: 'TurnitinBot',
TWIN_AGENT: 'TwinAgent',
VERCEL_V0BOT: 'v0bot',
WEBZIO: 'webzio',
WEBZIO_EXTENDED: 'Webzio-Extended',
WEBZIO_OMGILI: 'omgili',
WEBZIO_OMGILI_BOT: 'omgilibot',
XAI_BOT: 'xAI-Bot',
YAHOO_JAPAN: 'Y!J-BRW',
YAHOO_SLURP: 'Yahoo! Slurp',
YANDEX_ACCESSIBILITY_BOT: 'YandexAccessibilityBot',
YANDEX_ADDITIONAL_BOT: 'YandexAdditionalBot',
YANDEX_ADNET: 'YandexAdNet',
YANDEX_BLOGS: 'YandexBlogs',
YANDEX_BOT: 'YandexBot',
YANDEX_BOT_MIRRORDETECTOR: 'YandexBot MirrorDetector',
YANDEX_COMBOT: 'YandexComBot',
YANDEX_FAVICONS: 'YandexFavicons',
YANDEX_IMAGE_RESIZER: 'YandexImageResizer',
YANDEX_IMAGES: 'YandexImages',
YANDEX_MARKET: 'YandexMarket',
YANDEX_MEDIA: 'YandexMedia',
YANDEX_METRIKA: 'YandexMetrika',
YANDEX_MOBILE_BOT: 'YandexMobileBot',
YANDEX_MOBILE_SCREENSHOT_BOT: 'YandexMobileScreenShotBot',
YANDEX_NEWS: 'YandexNews',
YANDEX_ONTODB: 'YandexOntoDB',
YANDEX_ONTODB_API: 'YandexOntoDBAPI',
YANDEX_PARTNER: 'YandexPartner',
YANDEX_RCA: 'YandexRCA',
YANDEX_RENDERRESOURCES_BOT: 'YandexRenderResourcesBot',
YANDEX_SCREENSHOT_BOT: 'YandexScreenshotBot',
YANDEX_SPRAV_BOT: 'YandexSpravBot',
YANDEX_TRACKER: 'YandexTracker',
YANDEX_VERTICALS: 'YandexVerticals',
YANDEX_VERTIS: 'YandexVertis',
YANDEX_VIDEO: 'YandexVideo',
YANDEX_VIDEO_PARSER: 'YandexVideoParser',
YANDEX_WEBMASTER: 'YandexWebmaster',
YEP_BOT: 'YepBot',
YETI: 'Yeti',
YISOU_SPIDER: 'YisouSpider',
YOU_BOT: 'YouBot',
ZHIPU_CHATGLM_SPIDER: 'ChatGLM-Spider',
ZUM_BOT: 'ZumBot'
},
Email: {
AIRMAIL: 'Airmail',
APPLE_MAIL: 'Mail',
BLUEMAIL: 'BlueMail',
DAUM_MAIL: 'DaumMail',
EVOLUTION: 'Evolution',
EM_CLIENT: 'eM Client',
FOXMAIL: 'Foxmail',
KMAIL: 'KMail',
KMAIL2: 'kmail2',
KONTACT: 'Kontact',
MICROSOFT_OUTLOOK: 'Microsoft Outlook',
MICROSOFT_OUTLOOK_MAC: 'MacOutlook',
NAVER_MAILAPP: 'NaverMailApp',
POLYMAIL: 'Polymail',
PROTON_MAIL: 'ProtonMail',
SPARK_MAIL: 'SparkDesktop',
SPARROW: 'Sparrow',
THUNDERBIRD: 'Thunderbird',
YAHOO_MAIL: 'Yahoo',
ZIMBRA: 'Zimbra',
ZOHO_MAIL: 'ZohoMail-Desktop'
},
Fetcher: {
AHREFS_SITEAUDIT: 'AhrefsSiteAudit',
ANTHROPIC_CLAUDE_USER: 'Claude-User',
ASANA: 'Asana',
BETTER_UPTIME_BOT: 'Better Uptime Bot',
BITLY_BOT: 'bitlybot',
BLUESKY: 'Bluesky',
BUFFER_LINKPREVIEWBOT: 'BufferLinkPreviewBot',
COHERE_AI: 'Cohere-AI',
DUCKDUCKGO_ASSISTBOT: 'DuckAssistBot',
GOOGLE_CHROME_LIGHTHOUSE: 'Chrome-Lighthouse',
GOOGLE_FEEDFETCHER: 'FeedFetcher-Google',
GOOGLE_GEMINI_DEEP_RESEARCH: 'Gemini-Deep-Research',
GOOGLE_IMAGEPROXY: 'GoogleImageProxy',
GOOGLE_PAGERENDERER: 'Google-PageRenderer',
GOOGLE_READ_ALOUD: 'Google-Read-Aloud',
GOOGLE_PRODUCER: 'GoogleProducer',
GOOGLE_SITE_VERIFICATION: 'Google-Site-Verification',
HUBSPOT_PAGE_FETCHER: 'HubSpot Page Fetcher',
IFRAMELY: 'Iframely',
KAKAOTALK_SCRAP: 'kakaotalk-scrap',
META_EXTERNALFETCHER: 'meta-externalfetcher',
META_WHATSAPP: 'WhatsApp',
MICROSOFT_BINGPREVIEW: 'BingPreview',
MICROSOFT_PREVIEW: 'MicrosoftPreview',
MISTRALAI_USER: 'MistralAI-User',
NAVER_BLUENO: 'Blueno',
ONCRAWL_ROGERBOT: 'rogerbot',
OPENAI_CHATGPT_USER: 'ChatGPT-User',
PERPLEXITY_USER: 'Perplexity-User',
PINTEREST_BOT: 'Pinterestbot',
SEMRUSH_SITEAUDITBOT: 'SiteAuditBot',
SNAP_URL_PREVIEW: 'Snap URL Preview',
SKYPE_URIPREVIEW: 'SkypeUriPreview',
TELEGRAM_BOT: 'TelegramBot',
UPTIMEROBOT: 'UptimeRobot',
VERCEL_FAVICON_BOT: 'vercel-favicon-bot',
VERCEL_SCREENSHOT_BOT: 'vercel-screenshot-bot',
VERCEL_BOT: 'Vercelbot',
VERCEL_FLAGS: 'vercelflags',
VERCEL_TRACING: 'verceltracing',
YANDEX_CALENDAR: 'YandexCalendar',
YANDEX_DIRECT: 'YandexDirect',
YANDEX_DIRECTDYN: 'YandexDirectDyn',
YANDEX_DIRECTFETCHER: 'YaDirectFetcher',
YANDEX_FORDOMAIN: 'YandexForDomain',
YANDEX_PAGECHECKER: 'YandexPagechecker',
YANDEX_SEARCHSHOP: 'YandexSearchShop',
YANDEX_SITELINKS: 'YandexSitelinks',
YANDEX_USERPROXY: 'YandexUserproxy',
ZOOMINFO_BOT: 'Zoombot'
},
InApp: {
DISCORD: 'Discord',
EVERNOTE: 'Evernote',
FIGMA: 'Figma',
FLIPBOARD: 'Flipboard',
MATTERMOST: 'Mattermost',
TEAMS: 'Teams',
NOTION: 'Notion',
POSTMAN: 'Postman',
RAMBOX: 'Rambox',
ROCKETCHAT: 'Rocket.Chat',
SLACK: 'Slack',
TIKTOK_LITE: 'TikTok Lite',
VSCODE: 'VS Code',
YAHOO_JAPAN: 'Yahoo! Japan'
},
Library: {
ADOBE_AIR: 'AdobeAIR',
AIOHTTP: 'aiohttp',
APACHE_HTTPCLIENT: 'Apache-HttpClient',
AXIOS: 'axios',
GO_HTTP_CLIENT: 'go-http-client',
GOT: 'got',
GUZZLEHTTP: 'GuzzleHttp',
JAVA: 'Java',
JAVA_HTTPCLIENT: 'Java-http-client',
JSDOM: 'jsdom',
LIBWWW_PERL: 'libwww-perl',
LUA_RESTY_HTTP: 'lua-resty-http',
NEEDLE: 'Needle',
NUTCH: 'Nutch',
OKHTTP: 'OkHttp',
NODE_FETCH: 'node-fetch',
NODE_SUPERAGENT: 'node-superagent',
PHP_SOAP: 'PHP-SOAP',
POSTMAN_RUNTIME: 'PostmanRuntime',
PYTHON_HTTPX: 'python-httpx',
PYTHON_URLLIB: 'python-urllib',
PYTHON_URLLIB3: 'python-urllib3',
PYTHON_REQUESTS: 'python-requests',
SCRAPY: 'Scrapy'
}
},
DeviceVendor: {
Vehicle: {
BMW: 'BMW',
BYD: 'BYD',
JEEP: 'Jeep',
RIVIAN: 'Rivian',
TESLA: 'Tesla',
VOLVO: 'Volvo'
}
}
});
export {
Browser,
Browser,// deprecated
CPU, // deprecated
Device, // deprecated
Vendor, // deprecated
Engine, // deprecated
OS, // deprecated
BrowserName,
BrowserType,
CPU,
Device,
Vendor,
Engine,
OS
CPUArch,
DeviceType,
DeviceVendor,
EngineName,
OSName,
Extension
};

View File

@ -1,4 +1,4 @@
// Type definitions for Helpers submodule of UAParser.js v2.0.4
// Type definitions for Helpers submodule of UAParser.js v2.0.5
// Project: https://github.com/faisalman/ua-parser-js
// Definitions by: Faisal Salman <https://github.com/faisalman>

View File

@ -1,5 +1,5 @@
///////////////////////////////////////////////
/* Extensions for UAParser.js v2.0.4
/* Extensions for UAParser.js v2.0.5
https://github.com/faisalman/ua-parser-js
Author: Faisal Salman <f@faisalman.com>
UAParser.js PRO Personal License */
@ -43,20 +43,31 @@ const Crawlers = Object.freeze({
// AhrefsBot - https://ahrefs.com/robot
// Amazonbot - https://developer.amazon.com/amazonbot
// Bingbot / AdIdxBot - https://www.bing.com/webmasters/help/which-crawlers-does-bing-use-8c184ec0
// Bravebot - https://search.brave.com/help/brave-search-crawler
// CCBot - https://commoncrawl.org/faq
// contxbot - https://affiliate-program.amazon.com/help/node/topic/GT98G5PPRERNVZ2C
// Coveobot - https://connect.coveo.com/s/article/19648
// CriteoBot - https://www.criteo.com/criteo-crawler/
// Dotbot - https://moz.com/help/moz-procedures/crawlers/dotbot
// DuckDuckBot - http://duckduckgo.com/duckduckbot.html
// FacebookBot - https://developers.facebook.com/docs/sharing/bot/
// GPTBot - https://platform.openai.com/docs/gptbot
// iAskBot - https://iask.ai
// Kagibot - https://kagi.com/bot
// Kangaroo Bot - https://kangaroollm.com.au/kangaroo-bot/
// LinkedInBot - http://www.linkedin.com
// MJ12bot - https://mj12bot.com/
// MojeekBot - https://www.mojeek.com/bot.html
// Onespot - https://www.onespot.com/identifying-traffic.html
// OpenAI's SearchGPT - https://platform.openai.com/docs/bots
// PerplexityBot - https://perplexity.ai/perplexitybot
// SBIntuitionsBot - https://www.sbintuitions.co.jp/bot/
// SeznamBot - http://napoveda.seznam.cz/seznambot-intro
/((?:adidx|ahrefs|amazon|bing|cc|dot|duckduck|exa|facebook|gpt|iask|linkedin|mj12|mojeek|oai-search|onespot-scraper|perplexity|semrush|seznam)bot)\/([\w\.-]+)/i,
// YepBot - https://yep.com/yepbot/
/((?:adidx|ahrefs|amazon|bing|brave|cc|contx|coveo|criteo|dot|duckduck(?:go-favicons-)?|exa|facebook|gpt|iask|kagi|kangaroo |linkedin|mj12|mojeek|oai-search|onespot-scraper|perplexity|sbintuitions|semrush|seznam|yep)bot)\/([\w\.-]+)/i,
// Algolia Crawler
/(algolia crawler(?: renderscript)?)\/?([\w\.]*)/i,
// Applebot - http://apple.com/go/applebot
/(applebot(?:-extended)?)\/?([\w\.]*)/i,
@ -65,7 +76,7 @@ const Crawlers = Object.freeze({
/(baiduspider[-imagevdonwsfcpr]{0,7})\/?([\w\.]*)/i,
// ClaudeBot (Anthropic)
/(claude(?:bot|-web)|anthropic-ai)\/?([\w\.]*)/i,
/(claude(?:bot|-searchbot|-web)|anthropic-ai)\/?([\w\.]*)/i,
// Coc Coc Bot - https://help.coccoc.com/en/search-engine
/(coccocbot-(?:image|web))\/([\w\.]+)/i,
@ -83,6 +94,9 @@ const Crawlers = Object.freeze({
// Internet Archive (archive.org)
/(ia_archiver|archive\.org_bot)\/?([\w\.]*)/i,
// OnCrawl
/(oncrawl) mobile\/([\w\.]+)/i,
// Qwantbot - https://help.qwant.com/bot
/(qwantbot)[-\w]*\/?([\w\.]*)/i,
@ -96,30 +110,38 @@ const Crawlers = Object.freeze({
/(y!?j-(?:asr|br[uw]|dscv|mmp|vsidx|wsc))\/([\w\.]+)/i,
// Yandex Bots - https://yandex.com/bots
/(yandex(?:(?:mobile)?(?:accessibility|additional|renderresources|screenshot|sprav)?bot|image(?:s|resizer)|video(?:parser)?|blogs|adnet|favicons|fordomain|market|media|metrika|news|ontodb(?:api)?|pagechecker|partner|rca|tracker|turbo|vertis|webmaster|antivirus))\/([\w\.]+)/i,
/(yandex(?:(?:mobile)?(?:accessibility|additional|com|renderresources|screenshot|sprav)?bot(?!.+mirror)|image(?:s|resizer)|adnet|blogs|favicons|market|media|metrika|news|ontodb(?:api)?|partner|rca|tracker|turbo|verti(?:cal)?s|webmaster|video(?:parser)?))\/([\w\.]+)/i,
// Yeti (Naver)
/(yeti)\/([\w\.]+)/i,
// aiHitBot / Diffbot / Linespider / Magpie-Crawler / Omgilibot / OpenAI Image Downloader / Webzio-Extended / Screaming Frog SEO Spider / Startpage / Timpibot / VelenPublicWebCrawler / YisouSpider / YouBot
/((?:aihit|diff|timpi|you)bot|omgili(?:bot)?|openai image downloader|(?:magpie-|velenpublicweb)crawler|startpageprivateimageproxy|webzio-extended|(?:chatglm-|line|screaming frog seo |yisou)spider)\/?([\w\.]*)/i
// aiHitBot / Algolia Crawler / BLEXBot / Diffbot / FirecrawlAgent / HuggingFace-Bot / Linespider / MSNBot / Magpie-Crawler / Omgilibot / OpenAI Image Downloader / PanguBot / Replicate-Bot / RunPod-Bot / Webzio-Extended / Screaming Frog SEO Spider / Startpage / Timpibot / Together-Bot / VelenPublicWebCrawler / xAI-Bot / YisouSpider / YouBot / ZumBot
// Cotoyogi - https://ds.rois.ac.jp/en_center8/en_crawler/
// Freespoke - https://docs.freespoke.com/search/bot/
/((?:aihit|blex|diff|huggingface-|msn|pangu|replicate-|runpod-|timpi|together-|xai-|you|zum)bot|(?:magpie-|velenpublicweb)crawler|(?:chatglm-|line|screaming frog seo |yisou)spider|cotoyogi|firecrawlagent|freespoke|omgili(?:bot)?|openai image downloader|startpageprivateimageproxy|twinagent|webzio-extended)\/?([\w\.]*)/i
],
[NAME, VERSION, [TYPE, CRAWLER]],
[
// YandexBot MirrorDetector
/(yandexbot\/([\w\.]+); mirrordetector)/i
],
[[NAME, /\/.+;/ig, ''], VERSION, [TYPE, CRAWLER]],
[
// Google Bots
/((?:adsbot|apis|mediapartners)-google(?:-mobile)?|google-?(?:other|cloudvertexbot|extended|safety))/i,
// AI2Bot - https://allenai.org/crawler
// Bytespider
// DataForSeoBot - https://dataforseo.com/dataforseo-bot
// Huawei AspiegelBot / PetalBot https://aspiegel.com/petalbot
// ImagesiftBot - https://imagesift.com/about
// Qihoo 360Spider
// Siteimprove - https://help.siteimprove.com/support/solutions/articles/80000448553
// TurnitinBot - https://www.turnitin.com/robot/crawlerinfo.html
// v0bot - https://vercel.com/docs/bot-management
// Yahoo! Slurp - http://help.yahoo.com/help/us/ysearch/slurp
/\b(360spider-?(?:image|video)?|bytespider|(?:ai2|aspiegel|dataforseo|imagesift|petal|turnitin)bot|teoma|yahoo! slurp)/i
// Botify / Bytespider / DeepSeekBot / Qihoo 360Spider / SeekportBot / TikTokSpider
/\b((ai2|aspiegel|dataforseo|deepseek|imagesift|petal|seekport|turnitin|v0)bot|360spider-?(image|video)?|baidu-ads|botify|(byte|tiktok)spider|cohere-training-data-crawler|elastic(?=\/s)|marginalia|siteimprove(?=bot|\.com)|teoma|webzio|yahoo! slurp)/i
],
[NAME, [TYPE, CRAWLER]]
]
@ -234,16 +256,17 @@ const Emails = Object.freeze({
const Fetchers = Object.freeze({
browser : [
[
// Asana / Bitlybot / Better Uptime / BingPreview / Blueno / Cohere-AI / HubSpot Page Fetcher / kakaotalk-scrap / Mastodon / MicrosoftPreview / Pinterestbot / Redditbot / Rogerbot / SiteAuditBot / Telegrambot / Twitterbot / UptimeRobot
// AhrefsSiteAudit - https://ahrefs.com/robot/site-audit
// Buffer Link Preview Bot - https://scraper.buffer.com/about/bots/link-preview-bot
// ChatGPT-User - https://platform.openai.com/docs/plugins/bot
// DuckAssistBot - https://duckduckgo.com/duckassistbot/
// Better Uptime / BingPreview / Mastodon / MicrosoftPreview / Pinterestbot / Redditbot / Rogerbot / SiteAuditBot / Telegrambot / Twitterbot / UptimeRobot
// Google Site Verifier / Meta / Yahoo! Japan
// Iframely - https://iframely.com/docs/about
// Perplexity-User - https://docs.perplexity.ai/guides/bots
// MistralAI-User - https://docs.mistral.ai/robots/
// Yandex Bots - https://yandex.com/bots
/(ahrefssiteaudit|(?:bing|microsoft)preview|(?:chatgpt|mistralai|perplexity)-user|mastodon|(?:discord|duckassist|linkedin|pinterest|reddit|roger|siteaudit|twitter|uptimero)bot|google-site-verification|iframely|meta-externalfetcher|y!?j-dlc|yandex(?:calendar|direct(?:dyn)?|searchshop)|yadirectfetcher)\/([\w\.]+)/i,
/(asana|ahrefssiteaudit|(?:bing|microsoft)preview|blueno|(?:chatgpt|claude|mistralai|perplexity)-user|cohere-ai|hubspot page fetcher|mastodon|(?:bitly|bufferlinkpreview|discord|duckassist|linkedin|pinterest|reddit|roger|siteaudit|twitter|uptimero|zoom)bot|google-site-verification|iframely|kakaotalk-scrap|meta-externalfetcher|y!?j-dlc|yandex(?:calendar|direct(?:dyn)?|fordomain|pagechecker|searchshop)|yadirectfetcher)\/([\w\.]+)/i,
// Bluesky
/(bluesky) cardyb\/([\w\.]+)/i,
@ -260,8 +283,8 @@ const Fetchers = Object.freeze({
[NAME, VERSION, [TYPE, FETCHER]],
[
// Google Bots / Cohere / Snapchat / Vercelbot / Yandex Bots
/((?:better uptime |telegram|vercel)bot|cohere-ai|feedfetcher-google|google(?:imageproxy|-read-aloud|-pagerenderer|producer)|snap url preview|yandex(?:sitelinks|userproxy))/i
// Google Bots / Chrome-Lighthouse / Gemini-Deep-Research / Snapchat / Vercelbot / Yandex Bots
/((?:better uptime |telegram|vercel)bot|chrome-lighthouse|feedfetcher-google|gemini-deep-research|google(?:imageproxy|-read-aloud|-pagerenderer|producer)|snap url preview|vercel(flags|tracing|-(favicon|screenshot)-bot)|yandex(?:sitelinks|userproxy))/i
],
[NAME, [TYPE, FETCHER]],
],
@ -404,8 +427,8 @@ const Vehicles = Object.freeze({
const Bots = Object.freeze({
browser : [
...CLIs.browser,
...Crawlers.browser,
...Fetchers.browser,
...Crawlers.browser,
...Libraries.browser
],
os : [

View File

@ -3,7 +3,7 @@
// Source: /src/extensions/ua-parser-extensions.js
///////////////////////////////////////////////
/* Extensions for UAParser.js v2.0.4
/* Extensions for UAParser.js v2.0.5
https://github.com/faisalman/ua-parser-js
Author: Faisal Salman <f@faisalman.com>
UAParser.js PRO Personal License */
@ -47,20 +47,31 @@ const Crawlers = Object.freeze({
// AhrefsBot - https://ahrefs.com/robot
// Amazonbot - https://developer.amazon.com/amazonbot
// Bingbot / AdIdxBot - https://www.bing.com/webmasters/help/which-crawlers-does-bing-use-8c184ec0
// Bravebot - https://search.brave.com/help/brave-search-crawler
// CCBot - https://commoncrawl.org/faq
// contxbot - https://affiliate-program.amazon.com/help/node/topic/GT98G5PPRERNVZ2C
// Coveobot - https://connect.coveo.com/s/article/19648
// CriteoBot - https://www.criteo.com/criteo-crawler/
// Dotbot - https://moz.com/help/moz-procedures/crawlers/dotbot
// DuckDuckBot - http://duckduckgo.com/duckduckbot.html
// FacebookBot - https://developers.facebook.com/docs/sharing/bot/
// GPTBot - https://platform.openai.com/docs/gptbot
// iAskBot - https://iask.ai
// Kagibot - https://kagi.com/bot
// Kangaroo Bot - https://kangaroollm.com.au/kangaroo-bot/
// LinkedInBot - http://www.linkedin.com
// MJ12bot - https://mj12bot.com/
// MojeekBot - https://www.mojeek.com/bot.html
// Onespot - https://www.onespot.com/identifying-traffic.html
// OpenAI's SearchGPT - https://platform.openai.com/docs/bots
// PerplexityBot - https://perplexity.ai/perplexitybot
// SBIntuitionsBot - https://www.sbintuitions.co.jp/bot/
// SeznamBot - http://napoveda.seznam.cz/seznambot-intro
/((?:adidx|ahrefs|amazon|bing|cc|dot|duckduck|exa|facebook|gpt|iask|linkedin|mj12|mojeek|oai-search|onespot-scraper|perplexity|semrush|seznam)bot)\/([\w\.-]+)/i,
// YepBot - https://yep.com/yepbot/
/((?:adidx|ahrefs|amazon|bing|brave|cc|contx|coveo|criteo|dot|duckduck(?:go-favicons-)?|exa|facebook|gpt|iask|kagi|kangaroo |linkedin|mj12|mojeek|oai-search|onespot-scraper|perplexity|sbintuitions|semrush|seznam|yep)bot)\/([\w\.-]+)/i,
// Algolia Crawler
/(algolia crawler(?: renderscript)?)\/?([\w\.]*)/i,
// Applebot - http://apple.com/go/applebot
/(applebot(?:-extended)?)\/?([\w\.]*)/i,
@ -69,7 +80,7 @@ const Crawlers = Object.freeze({
/(baiduspider[-imagevdonwsfcpr]{0,7})\/?([\w\.]*)/i,
// ClaudeBot (Anthropic)
/(claude(?:bot|-web)|anthropic-ai)\/?([\w\.]*)/i,
/(claude(?:bot|-searchbot|-web)|anthropic-ai)\/?([\w\.]*)/i,
// Coc Coc Bot - https://help.coccoc.com/en/search-engine
/(coccocbot-(?:image|web))\/([\w\.]+)/i,
@ -87,6 +98,9 @@ const Crawlers = Object.freeze({
// Internet Archive (archive.org)
/(ia_archiver|archive\.org_bot)\/?([\w\.]*)/i,
// OnCrawl
/(oncrawl) mobile\/([\w\.]+)/i,
// Qwantbot - https://help.qwant.com/bot
/(qwantbot)[-\w]*\/?([\w\.]*)/i,
@ -100,30 +114,38 @@ const Crawlers = Object.freeze({
/(y!?j-(?:asr|br[uw]|dscv|mmp|vsidx|wsc))\/([\w\.]+)/i,
// Yandex Bots - https://yandex.com/bots
/(yandex(?:(?:mobile)?(?:accessibility|additional|renderresources|screenshot|sprav)?bot|image(?:s|resizer)|video(?:parser)?|blogs|adnet|favicons|fordomain|market|media|metrika|news|ontodb(?:api)?|pagechecker|partner|rca|tracker|turbo|vertis|webmaster|antivirus))\/([\w\.]+)/i,
/(yandex(?:(?:mobile)?(?:accessibility|additional|com|renderresources|screenshot|sprav)?bot(?!.+mirror)|image(?:s|resizer)|adnet|blogs|favicons|market|media|metrika|news|ontodb(?:api)?|partner|rca|tracker|turbo|verti(?:cal)?s|webmaster|video(?:parser)?))\/([\w\.]+)/i,
// Yeti (Naver)
/(yeti)\/([\w\.]+)/i,
// aiHitBot / Diffbot / Linespider / Magpie-Crawler / Omgilibot / OpenAI Image Downloader / Webzio-Extended / Screaming Frog SEO Spider / Startpage / Timpibot / VelenPublicWebCrawler / YisouSpider / YouBot
/((?:aihit|diff|timpi|you)bot|omgili(?:bot)?|openai image downloader|(?:magpie-|velenpublicweb)crawler|startpageprivateimageproxy|webzio-extended|(?:chatglm-|line|screaming frog seo |yisou)spider)\/?([\w\.]*)/i
// aiHitBot / Algolia Crawler / BLEXBot / Diffbot / FirecrawlAgent / HuggingFace-Bot / Linespider / MSNBot / Magpie-Crawler / Omgilibot / OpenAI Image Downloader / PanguBot / Replicate-Bot / RunPod-Bot / Webzio-Extended / Screaming Frog SEO Spider / Startpage / Timpibot / Together-Bot / VelenPublicWebCrawler / xAI-Bot / YisouSpider / YouBot / ZumBot
// Cotoyogi - https://ds.rois.ac.jp/en_center8/en_crawler/
// Freespoke - https://docs.freespoke.com/search/bot/
/((?:aihit|blex|diff|huggingface-|msn|pangu|replicate-|runpod-|timpi|together-|xai-|you|zum)bot|(?:magpie-|velenpublicweb)crawler|(?:chatglm-|line|screaming frog seo |yisou)spider|cotoyogi|firecrawlagent|freespoke|omgili(?:bot)?|openai image downloader|startpageprivateimageproxy|twinagent|webzio-extended)\/?([\w\.]*)/i
],
[NAME, VERSION, [TYPE, CRAWLER]],
[
// YandexBot MirrorDetector
/(yandexbot\/([\w\.]+); mirrordetector)/i
],
[[NAME, /\/.+;/ig, ''], VERSION, [TYPE, CRAWLER]],
[
// Google Bots
/((?:adsbot|apis|mediapartners)-google(?:-mobile)?|google-?(?:other|cloudvertexbot|extended|safety))/i,
// AI2Bot - https://allenai.org/crawler
// Bytespider
// DataForSeoBot - https://dataforseo.com/dataforseo-bot
// Huawei AspiegelBot / PetalBot https://aspiegel.com/petalbot
// ImagesiftBot - https://imagesift.com/about
// Qihoo 360Spider
// Siteimprove - https://help.siteimprove.com/support/solutions/articles/80000448553
// TurnitinBot - https://www.turnitin.com/robot/crawlerinfo.html
// v0bot - https://vercel.com/docs/bot-management
// Yahoo! Slurp - http://help.yahoo.com/help/us/ysearch/slurp
/\b(360spider-?(?:image|video)?|bytespider|(?:ai2|aspiegel|dataforseo|imagesift|petal|turnitin)bot|teoma|yahoo! slurp)/i
// Botify / Bytespider / DeepSeekBot / Qihoo 360Spider / SeekportBot / TikTokSpider
/\b((ai2|aspiegel|dataforseo|deepseek|imagesift|petal|seekport|turnitin|v0)bot|360spider-?(image|video)?|baidu-ads|botify|(byte|tiktok)spider|cohere-training-data-crawler|elastic(?=\/s)|marginalia|siteimprove(?=bot|\.com)|teoma|webzio|yahoo! slurp)/i
],
[NAME, [TYPE, CRAWLER]]
]
@ -238,16 +260,17 @@ const Emails = Object.freeze({
const Fetchers = Object.freeze({
browser : [
[
// Asana / Bitlybot / Better Uptime / BingPreview / Blueno / Cohere-AI / HubSpot Page Fetcher / kakaotalk-scrap / Mastodon / MicrosoftPreview / Pinterestbot / Redditbot / Rogerbot / SiteAuditBot / Telegrambot / Twitterbot / UptimeRobot
// AhrefsSiteAudit - https://ahrefs.com/robot/site-audit
// Buffer Link Preview Bot - https://scraper.buffer.com/about/bots/link-preview-bot
// ChatGPT-User - https://platform.openai.com/docs/plugins/bot
// DuckAssistBot - https://duckduckgo.com/duckassistbot/
// Better Uptime / BingPreview / Mastodon / MicrosoftPreview / Pinterestbot / Redditbot / Rogerbot / SiteAuditBot / Telegrambot / Twitterbot / UptimeRobot
// Google Site Verifier / Meta / Yahoo! Japan
// Iframely - https://iframely.com/docs/about
// Perplexity-User - https://docs.perplexity.ai/guides/bots
// MistralAI-User - https://docs.mistral.ai/robots/
// Yandex Bots - https://yandex.com/bots
/(ahrefssiteaudit|(?:bing|microsoft)preview|(?:chatgpt|mistralai|perplexity)-user|mastodon|(?:discord|duckassist|linkedin|pinterest|reddit|roger|siteaudit|twitter|uptimero)bot|google-site-verification|iframely|meta-externalfetcher|y!?j-dlc|yandex(?:calendar|direct(?:dyn)?|searchshop)|yadirectfetcher)\/([\w\.]+)/i,
/(asana|ahrefssiteaudit|(?:bing|microsoft)preview|blueno|(?:chatgpt|claude|mistralai|perplexity)-user|cohere-ai|hubspot page fetcher|mastodon|(?:bitly|bufferlinkpreview|discord|duckassist|linkedin|pinterest|reddit|roger|siteaudit|twitter|uptimero|zoom)bot|google-site-verification|iframely|kakaotalk-scrap|meta-externalfetcher|y!?j-dlc|yandex(?:calendar|direct(?:dyn)?|fordomain|pagechecker|searchshop)|yadirectfetcher)\/([\w\.]+)/i,
// Bluesky
/(bluesky) cardyb\/([\w\.]+)/i,
@ -264,8 +287,8 @@ const Fetchers = Object.freeze({
[NAME, VERSION, [TYPE, FETCHER]],
[
// Google Bots / Cohere / Snapchat / Vercelbot / Yandex Bots
/((?:better uptime |telegram|vercel)bot|cohere-ai|feedfetcher-google|google(?:imageproxy|-read-aloud|-pagerenderer|producer)|snap url preview|yandex(?:sitelinks|userproxy))/i
// Google Bots / Chrome-Lighthouse / Gemini-Deep-Research / Snapchat / Vercelbot / Yandex Bots
/((?:better uptime |telegram|vercel)bot|chrome-lighthouse|feedfetcher-google|gemini-deep-research|google(?:imageproxy|-read-aloud|-pagerenderer|producer)|snap url preview|vercel(flags|tracing|-(favicon|screenshot)-bot)|yandex(?:sitelinks|userproxy))/i
],
[NAME, [TYPE, FETCHER]],
],
@ -408,8 +431,8 @@ const Vehicles = Object.freeze({
const Bots = Object.freeze({
browser : [
...CLIs.browser,
...Crawlers.browser,
...Fetchers.browser,
...Crawlers.browser,
...Libraries.browser
],
os : [

View File

@ -1,27 +1,15 @@
// Type definitions for Helpers submodule of UAParser.js v2.0.4
// Type definitions for Helpers submodule of UAParser.js v2.0.5
// Project: https://github.com/faisalman/ua-parser-js
// Definitions by: Faisal Salman <https://github.com/faisalman>
import type { IResult } from "../main/ua-parser";
declare function getDeviceVendor(model: string): string | undefined;
declare function isAppleSilicon(resultOrUA: IResult | string): boolean;
declare function isAIBot(resultOrUA: IResult | string): boolean;
declare function isBot(resultOrUA: IResult | string): boolean;
declare function isChromeFamily(resultOrUA: IResult | string): boolean;
declare function isElectron(): boolean;
declare function isFromEU(): boolean;
declare function isFrozenUA(ua: string): boolean;
declare function isStandalonePWA(): boolean;
export {
getDeviceVendor,
isAppleSilicon,
isAIBot,
isBot,
isChromeFamily,
isElectron,
isFromEU,
isFrozenUA,
isStandalonePWA
}
export function getDeviceVendor(model: string): string | undefined;
export function isAppleSilicon(resultOrUA: IResult | string): boolean;
export function isAIBot(resultOrUA: IResult | string): boolean;
export function isBot(resultOrUA: IResult | string): boolean;
export function isChromeFamily(resultOrUA: IResult | string): boolean;
export function isElectron(): boolean;
export function isFromEU(): boolean;
export function isFrozenUA(ua: string): boolean;
export function isStandalonePWA(): boolean;

View File

@ -1,5 +1,5 @@
///////////////////////////////////////////////
/* Helpers for UAParser.js v2.0.4
/* Helpers for UAParser.js v2.0.5
https://github.com/faisalman/ua-parser-js
Author: Faisal Salman <f@faisalman.com>
UAParser.js PRO Personal License */
@ -8,11 +8,12 @@
/*jshint esversion: 6 */
const { UAParser } = require('../main/ua-parser');
const { CPU, OS, Engine } = require('../enums/ua-parser-enums');
const { Bots } = require('../extensions/ua-parser-extensions');
const { CPUArch, OSName, EngineName, Extension, BrowserType } = require('../enums/ua-parser-enums');
const { Bots, Crawlers } = require('../extensions/ua-parser-extensions');
const { isFromEU } = require('detect-europe-js');
const { isFrozenUA } = require('ua-is-frozen');
const { isStandalonePWA } = require('is-standalone-pwa');
const { Crawler } = Extension.BrowserName;
const toResult = (value, head, ext) => typeof value === 'string' ? UAParser(value, head, ext) : value;
@ -20,8 +21,8 @@ const getDeviceVendor = (model) => UAParser(`Mozilla/5.0 (Linux; Android 10; ${m
const isAppleSilicon = (resultOrUA) => {
const res = toResult(resultOrUA);
if (res.os.is(OS.MACOS)) {
if (res.cpu.is(CPU.ARM)) {
if (res.os.is(OSName.MACOS)) {
if (res.cpu.is(CPUArch.ARM)) {
return true;
}
if (typeof resultOrUA !== 'string' && typeof window !== 'undefined') {
@ -44,88 +45,129 @@ const isAppleSilicon = (resultOrUA) => {
const isAIBot = (resultOrUA) => [
// AI2
'ai2bot',
Crawler.AI2_BOT,
// Amazon
'amazonbot',
Crawler.AMAZON_BOT,
// Anthropic
'anthropic-ai',
'claude-web',
'claudebot',
Crawler.ANTHROPIC_AI,
Crawler.ANTHROPIC_CLAUDE_BOT,
Crawler.ANTHROPIC_CLAUDE_SEARCHBOT,
Crawler.ANTHROPIC_CLAUDE_WEB,
// Apple
'applebot',
'applebot-extended',
Crawler.APPLE_BOT,
Crawler.APPLE_BOT_EXTENDED,
// Brave
Crawler.BRAVE_BOT,
// ByteDance
'bytespider',
Crawler.BYTEDANCE_BYTESPIDER,
Crawler.BYTEDANCE_TIKTOKSPIDER,
// Cohere
Crawler.COHERE_TRAINING_DATA_CRAWLER,
// Common Crawl
'ccbot',
Crawler.COMMON_CRAWL_CCBOT,
// Coveo
Crawler.COVEO_BOT,
// DataForSeo
'dataforseobot',
Crawler.DATAFORSEO_BOT,
// DeepSeek
Crawler.DEEPSEEK_BOT,
// Diffbot
'diffbot',
Crawler.DIFFBOT,
// Google
'googleother',
'googleother-image',
'googleother-video',
'google-extended',
Crawler.GOOGLE_EXTENDED,
Crawler.GOOGLE_OTHER,
Crawler.GOOGLE_OTHER_IMAGE,
Crawler.GOOGLE_OTHER_VIDEO,
Crawler.GOOGLE_CLOUDVERTEXBOT,
// Hive AI
'imagesiftbot',
Crawler.HIVE_IMAGESIFTBOT,
// Huawei
'petalbot',
Crawler.HUAWEI_PETALBOT,
Crawler.HUAWEI_PANGUBOT,
// Hugging Face
Crawler.HUGGINGFACE_BOT,
// Kangaroo
Crawler.KANGAROO_BOT,
// Mendable.ai
Crawler.FIRECRAWL_AGENT,
// Meta
'facebookbot',
'meta-externalagent',
Crawler.META_FACEBOOKBOT,
Crawler.META_EXTERNALAGENT,
// OpenAI
'gptbot',
'oai-searchbot',
Crawler.OPENAI_GPTBOT,
Crawler.OPENAI_SEARCH_BOT,
// Perplexity
'perplexitybot',
Crawler.PERPLEXITY_BOT,
// Replicate
Crawler.REPLICATE_BOT,
// Runpod
Crawler.RUNPOD_BOT,
// SB Intuitions
Crawler.SB_INTUITIONS_BOT,
// Semrush
'semrushbot-ocob',
Crawler.SEMRUSH_BOT_CONTENTSHAKE,
// Timpi
'timpibot',
Crawler.TIMPI_BOT,
// Together AI
Crawler.TOGETHER_BOT,
// Velen.io
'velenpublicwebcrawler',
Crawler.HUNTER_VELENPUBLICWEBCRAWLER,
// Vercel
Crawler.VERCEL_V0BOT,
// Webz.io
'omgili',
'omgilibot',
'webzio-extended',
Crawler.WEBZIO_OMGILI,
Crawler.WEBZIO_OMGILI_BOT,
Crawler.WEBZIO_EXTENDED,
// X
Crawler.XAI_BOT,
// You.com
'youbot',
Crawler.YOU_BOT,
// Zhipu AI
'chatglm-spider',
// Zyte
'scrapy'
].includes(String(toResult(resultOrUA, Bots).browser.name).toLowerCase());
Crawler.ZHIPU_CHATGLM_SPIDER
]
.map((s) => s.toLowerCase())
.includes(String(toResult(resultOrUA, Crawlers).browser.name).toLowerCase());
const isBot = (resultOrUA) => [
'cli',
'crawler',
'fetcher',
'library'
BrowserType.CLI,
BrowserType.CRAWLER,
BrowserType.FETCHER,
BrowserType.LIBRARY
].includes(toResult(resultOrUA, Bots).browser.type);
const isChromeFamily = (resultOrUA) => toResult(resultOrUA).engine.is(Engine.BLINK);
const isChromeFamily = (resultOrUA) => toResult(resultOrUA).engine.is(EngineName.BLINK);
const isElectron = () => !!(process?.versions?.hasOwnProperty('electron') || // node.js
/ electron\//i.test(navigator?.userAgent)); // browser

View File

@ -3,7 +3,7 @@
// Source: /src/helpers/ua-parser-helpers.js
///////////////////////////////////////////////
/* Helpers for UAParser.js v2.0.4
/* Helpers for UAParser.js v2.0.5
https://github.com/faisalman/ua-parser-js
Author: Faisal Salman <f@faisalman.com>
UAParser.js PRO Personal License */
@ -12,11 +12,12 @@
/*jshint esversion: 6 */
import { UAParser } from '../main/ua-parser.mjs';
import { CPU, OS, Engine } from '../enums/ua-parser-enums.mjs';
import { Bots } from '../extensions/ua-parser-extensions.mjs';
import { CPUArch, OSName, EngineName, Extension, BrowserType } from '../enums/ua-parser-enums.mjs';
import { Bots, Crawlers } from '../extensions/ua-parser-extensions.mjs';
import { isFromEU } from 'detect-europe-js';
import { isFrozenUA } from 'ua-is-frozen';
import { isStandalonePWA } from 'is-standalone-pwa';
const { Crawler } = Extension.BrowserName;
const toResult = (value, head, ext) => typeof value === 'string' ? UAParser(value, head, ext) : value;
@ -24,8 +25,8 @@ const getDeviceVendor = (model) => UAParser(`Mozilla/5.0 (Linux; Android 10; ${m
const isAppleSilicon = (resultOrUA) => {
const res = toResult(resultOrUA);
if (res.os.is(OS.MACOS)) {
if (res.cpu.is(CPU.ARM)) {
if (res.os.is(OSName.MACOS)) {
if (res.cpu.is(CPUArch.ARM)) {
return true;
}
if (typeof resultOrUA !== 'string' && typeof window !== 'undefined') {
@ -48,88 +49,129 @@ const isAppleSilicon = (resultOrUA) => {
const isAIBot = (resultOrUA) => [
// AI2
'ai2bot',
Crawler.AI2_BOT,
// Amazon
'amazonbot',
Crawler.AMAZON_BOT,
// Anthropic
'anthropic-ai',
'claude-web',
'claudebot',
Crawler.ANTHROPIC_AI,
Crawler.ANTHROPIC_CLAUDE_BOT,
Crawler.ANTHROPIC_CLAUDE_SEARCHBOT,
Crawler.ANTHROPIC_CLAUDE_WEB,
// Apple
'applebot',
'applebot-extended',
Crawler.APPLE_BOT,
Crawler.APPLE_BOT_EXTENDED,
// Brave
Crawler.BRAVE_BOT,
// ByteDance
'bytespider',
Crawler.BYTEDANCE_BYTESPIDER,
Crawler.BYTEDANCE_TIKTOKSPIDER,
// Cohere
Crawler.COHERE_TRAINING_DATA_CRAWLER,
// Common Crawl
'ccbot',
Crawler.COMMON_CRAWL_CCBOT,
// Coveo
Crawler.COVEO_BOT,
// DataForSeo
'dataforseobot',
Crawler.DATAFORSEO_BOT,
// DeepSeek
Crawler.DEEPSEEK_BOT,
// Diffbot
'diffbot',
Crawler.DIFFBOT,
// Google
'googleother',
'googleother-image',
'googleother-video',
'google-extended',
Crawler.GOOGLE_EXTENDED,
Crawler.GOOGLE_OTHER,
Crawler.GOOGLE_OTHER_IMAGE,
Crawler.GOOGLE_OTHER_VIDEO,
Crawler.GOOGLE_CLOUDVERTEXBOT,
// Hive AI
'imagesiftbot',
Crawler.HIVE_IMAGESIFTBOT,
// Huawei
'petalbot',
Crawler.HUAWEI_PETALBOT,
Crawler.HUAWEI_PANGUBOT,
// Hugging Face
Crawler.HUGGINGFACE_BOT,
// Kangaroo
Crawler.KANGAROO_BOT,
// Mendable.ai
Crawler.FIRECRAWL_AGENT,
// Meta
'facebookbot',
'meta-externalagent',
Crawler.META_FACEBOOKBOT,
Crawler.META_EXTERNALAGENT,
// OpenAI
'gptbot',
'oai-searchbot',
Crawler.OPENAI_GPTBOT,
Crawler.OPENAI_SEARCH_BOT,
// Perplexity
'perplexitybot',
Crawler.PERPLEXITY_BOT,
// Replicate
Crawler.REPLICATE_BOT,
// Runpod
Crawler.RUNPOD_BOT,
// SB Intuitions
Crawler.SB_INTUITIONS_BOT,
// Semrush
'semrushbot-ocob',
Crawler.SEMRUSH_BOT_CONTENTSHAKE,
// Timpi
'timpibot',
Crawler.TIMPI_BOT,
// Together AI
Crawler.TOGETHER_BOT,
// Velen.io
'velenpublicwebcrawler',
Crawler.HUNTER_VELENPUBLICWEBCRAWLER,
// Vercel
Crawler.VERCEL_V0BOT,
// Webz.io
'omgili',
'omgilibot',
'webzio-extended',
Crawler.WEBZIO_OMGILI,
Crawler.WEBZIO_OMGILI_BOT,
Crawler.WEBZIO_EXTENDED,
// X
Crawler.XAI_BOT,
// You.com
'youbot',
Crawler.YOU_BOT,
// Zhipu AI
'chatglm-spider',
// Zyte
'scrapy'
].includes(String(toResult(resultOrUA, Bots).browser.name).toLowerCase());
Crawler.ZHIPU_CHATGLM_SPIDER
]
.map((s) => s.toLowerCase())
.includes(String(toResult(resultOrUA, Crawlers).browser.name).toLowerCase());
const isBot = (resultOrUA) => [
'cli',
'crawler',
'fetcher',
'library'
BrowserType.CLI,
BrowserType.CRAWLER,
BrowserType.FETCHER,
BrowserType.LIBRARY
].includes(toResult(resultOrUA, Bots).browser.type);
const isChromeFamily = (resultOrUA) => toResult(resultOrUA).engine.is(Engine.BLINK);
const isChromeFamily = (resultOrUA) => toResult(resultOrUA).engine.is(EngineName.BLINK);
const isElectron = () => !!(process?.versions?.hasOwnProperty('electron') || // node.js
/ electron\//i.test(navigator?.userAgent)); // browser

View File

@ -1,9 +1,9 @@
// Type definitions for UAParser.js v2.0.4
// Type definitions for UAParser.js v2.0.5
// Project: https://github.com/faisalman/ua-parser-js
// Definitions by: Faisal Salman <https://github.com/faisalman>
import type { IncomingHttpHeaders } from 'http';
import type { Headers as FetchAPIHeaders } from 'node-fetch';
import type { Headers } from "undici";
import { BrowserType, CPUArch, DeviceType, EngineName } from "../enums/ua-parser-enums";
declare namespace UAParser {
@ -18,21 +18,21 @@ declare namespace UAParser {
name?: string;
version?: string;
major?: string;
type?: 'crawler' | 'cli' | 'email' | 'fetcher' | 'inapp' | 'mediaplayer' | 'library';
type?: typeof BrowserType[keyof typeof BrowserType];
}
interface ICPU extends IData<ICPU> {
architecture?: 'ia32' | 'ia64' | 'amd64' | 'arm' | 'arm64' | 'armhf' | 'avr' | 'avr32' | 'irix' | 'irix64' | 'mips' | 'mips64' | '68k' | 'pa-risc' | 'ppc' | 'sparc' | 'sparc64';
architecture?: typeof CPUArch[keyof typeof CPUArch];
}
interface IDevice extends IData<IDevice> {
type?: 'mobile' | 'tablet' | 'console' | 'smarttv' | 'wearable' | 'xr' | 'embedded';
type?: typeof DeviceType[keyof typeof DeviceType];
vendor?: string;
model?: string;
}
interface IEngine extends IData<IEngine> {
name?: 'Amaya' | 'ArkWeb' | 'Blink' | 'EdgeHTML' | 'Flow' | 'Gecko' | 'Goanna' | 'iCab' | 'KHTML' | 'LibWeb' | 'Links' | 'Lynx' | 'NetFront' | 'NetSurf' | 'Presto' | 'Servo' | 'Tasman' | 'Trident' | 'w3m' | 'WebKit';
name?: typeof EngineName[keyof typeof EngineName];
version?: string;
}
@ -53,7 +53,7 @@ declare namespace UAParser {
type RegexMap = ((RegExp | string | (string | RegExp | Function)[])[])[];
type UAParserProps = 'browser' | 'cpu' | 'device' | 'engine' | 'os';
type UAParserExt = Partial<Record<UAParserProps, RegexMap>> | Partial<Record<UAParserProps, RegexMap>>[];
type UAParserHeaders = Record<string, string> | IncomingHttpHeaders | FetchAPIHeaders;
export type UAParserHeaders = Record<string, string | string[] | undefined> | Headers;
export function UAParser(uastring?: string, extensions?: UAParserExt, headers?: UAParserHeaders): IResult;
export function UAParser(uastring?: string, headers?: UAParserHeaders): IResult;

View File

@ -1,5 +1,5 @@
/////////////////////////////////////////////////////////////////////////////////
/* UAParser.js v2.0.4
/* UAParser.js v2.0.5
Copyright © 2012-2025 Faisal Salman <f@faisalman.com>
UAParser.js PRO Personal License *//*
Detect Browser, Engine, OS, CPU, and Device type/model from User-Agent data.
@ -19,7 +19,7 @@
// Constants
/////////////
var LIBVERSION = '2.0.4',
var LIBVERSION = '2.0.5',
UA_MAX_LENGTH = 500,
USER_AGENT = 'user-agent',
EMPTY = '',
@ -188,6 +188,8 @@
},
setProps = function (arr) {
for (var i in arr) {
if (!arr.hasOwnProperty(i)) continue;
var propName = arr[i];
if (typeof propName == OBJ_TYPE && propName.length == 2) {
this[propName[0]] = propName[1];
@ -455,6 +457,8 @@
], [VERSION, [NAME, 'TikTok'], [TYPE, INAPP]], [
/\[(linkedin)app\]/i // LinkedIn App for iOS & Android
], [NAME, [TYPE, INAPP]], [
/(zalo(?:app)?)[\/\sa-z]*([\w\.-]+)/i // Zalo
], [[NAME, /(.+)/, 'Zalo'], VERSION, [TYPE, INAPP]], [
/(chromium)[\/ ]([-\w\.]+)/i // Chromium
], [NAME, VERSION], [
@ -536,15 +540,15 @@
/( (ce|mobile); ppc;|\/[\w\.]+arm\b)/i
], [[ARCHITECTURE, 'arm']], [
/((ppc|powerpc)(64)?)( mac|;|\))/i // PowerPC
], [[ARCHITECTURE, /ower/, EMPTY, lowerize]], [
/ sun4\w[;\)]/i // SPARC
], [[ARCHITECTURE, 'sparc']], [
/\b(avr32|ia64(?=;)|68k(?=\))|\barm(?=v([1-7]|[5-7]1)l?|;|eabi)|(irix|mips|sparc)(64)?\b|pa-risc)/i
// IA64, 68K, ARM/64, AVR/32, IRIX/64, MIPS/64, SPARC/64, PA-RISC
], [[ARCHITECTURE, lowerize]]
/\b(avr32|ia64(?=;)|68k(?=\))|\barm(?=v([1-7]|[5-7]1)l?|;|eabi)|(irix|mips|sparc)(64)?\b|pa-risc)/i,
/((ppc|powerpc)(64)?)( mac|;|\))/i, // PowerPC
/(?:osf1|[freopnt]{3,4}bsd) (alpha)/i // Alpha
], [[ARCHITECTURE, /ower/, EMPTY, lowerize]], [
/winnt.+\[axp/i
], [[ARCHITECTURE, 'alpha']]
],
device : [[
@ -768,7 +772,8 @@
/; (blu|hmd|imo|infinix|lava|oneplus|tcl)[_ ]([\w\+ ]+?)(?: bui|\)|; r)/i, // BLU/HMD/IMO/Infinix/Lava/OnePlus/TCL
/(hp) ([\w ]+\w)/i, // HP iPAQ
/(microsoft); (lumia[\w ]+)/i, // Microsoft Lumia
/(oppo) ?([\w ]+) bui/i // OPPO
/(oppo) ?([\w ]+) bui/i, // OPPO
/droid[^;]+; (philips)[_ ]([sv-x][\d]{3,4}[xz]?)/i // Philips
], [VENDOR, MODEL, [TYPE, MOBILE]], [
/(kobo)\s(ereader|touch)/i, // Kobo
@ -795,6 +800,7 @@
// SMARTTVS
///////////////////
/(philips)[\w ]+tv/i, // Philips
/smart-tv.+(samsung)/i // Samsung
], [VENDOR, [TYPE, SMARTTV]], [
/hbbtv.+maple;(\d+)/i
@ -832,11 +838,6 @@
/\b(roku)[\dx]*[\)\/]((?:dvp-)?[\d\.]*)/i, // Roku
/hbbtv\/\d+\.\d+\.\d+ +\([\w\+ ]*; *([\w\d][^;]*);([^;]*)/i // HbbTV devices
], [[VENDOR, /.+\/(\w+)/, '$1', strMapper, {'LG':'lge'}], [MODEL, trim], [TYPE, SMARTTV]], [
// SmartTV from Unidentified Vendors
/droid.+; ([\w- ]+) (?:android tv|smart[- ]?tv)/i
], [MODEL, [TYPE, SMARTTV]], [
/\b(android tv|smart[- ]?tv|opera tv|tv; rv:|large screen[\w ]+safari)\b/i
], [[TYPE, SMARTTV]], [
///////////////////
// CONSOLES
@ -883,7 +884,7 @@
/droid.+; (glass) \d/i // Google Glass
], [MODEL, [VENDOR, GOOGLE], [TYPE, XR]], [
/(pico) (4|neo3(?: link|pro)?)/i // Pico
/(pico) ([\w ]+) os\d/i // Pico
], [VENDOR, MODEL, [TYPE, XR]], [
/(quest( \d| pro)?s?).+vr/i // Meta Quest
], [MODEL, [VENDOR, FACEBOOK], [TYPE, XR]], [
@ -907,6 +908,10 @@
// MIXED (GENERIC)
///////////////////
/droid.+; ([\w- ]+) (4k|android|smart|google)[- ]?tv/i // Unidentifiable SmartTV
], [MODEL, [TYPE, SMARTTV]], [
/\b((4k|android|smart|opera)[- ]?tv|tv; rv:|large screen[\w ]+safari)\b/i
], [[TYPE, SMARTTV]], [
/droid .+?; ([^;]+?)(?: bui|; wv\)|\) applew).+?(mobile|vr|\d) safari/i
], [MODEL, [TYPE, strMapper, { 'mobile' : 'Mobile', 'xr' : 'VR', '*' : TABLET }]], [
/\b((tablet|tab)[;\/]|focus\/\d(?!.+mobile))/i // Unidentifiable Tablet
@ -1263,7 +1268,7 @@
case UA_ENGINE:
var brands = uaCH[FULLVERLIST] || uaCH[BRANDS], prevName;
if (brands) {
for (var i in brands) {
for (var i=0; i<brands.length; i++) {
var brandName = brands[i].brand || brands[i],
brandVersion = brands[i].version;
if (this.itemType == UA_BROWSER &&
@ -1385,11 +1390,22 @@
extensions = undefined;
}
if (headers) {
if (typeof headers.append === FUNC_TYPE) {
// Convert Headers object into a plain object
if (headers && typeof headers.append === FUNC_TYPE) {
var kv = {};
headers.forEach(function (v, k) { kv[k] = v; });
headers.forEach(function (v, k) { kv[String(k).toLowerCase()] = v; });
headers = kv;
} else {
// Normalize headers field name into lowercase
var normalized = {};
for (var header in headers) {
if (headers.hasOwnProperty(header)) {
normalized[String(header).toLowerCase()] = headers[header];
}
}
headers = normalized;
}
}
if (!(this instanceof UAParser)) {

View File

@ -3,7 +3,7 @@
// Source: /src/main/ua-parser.js
/////////////////////////////////////////////////////////////////////////////////
/* UAParser.js v2.0.4
/* UAParser.js v2.0.5
Copyright © 2012-2025 Faisal Salman <f@faisalman.com>
UAParser.js PRO Personal License *//*
Detect Browser, Engine, OS, CPU, and Device type/model from User-Agent data.
@ -21,7 +21,7 @@
// Constants
/////////////
var LIBVERSION = '2.0.4',
var LIBVERSION = '2.0.5',
UA_MAX_LENGTH = 500,
USER_AGENT = 'user-agent',
EMPTY = '',
@ -190,6 +190,8 @@
},
setProps = function (arr) {
for (var i in arr) {
if (!arr.hasOwnProperty(i)) continue;
var propName = arr[i];
if (typeof propName == OBJ_TYPE && propName.length == 2) {
this[propName[0]] = propName[1];
@ -457,6 +459,8 @@
], [VERSION, [NAME, 'TikTok'], [TYPE, INAPP]], [
/\[(linkedin)app\]/i // LinkedIn App for iOS & Android
], [NAME, [TYPE, INAPP]], [
/(zalo(?:app)?)[\/\sa-z]*([\w\.-]+)/i // Zalo
], [[NAME, /(.+)/, 'Zalo'], VERSION, [TYPE, INAPP]], [
/(chromium)[\/ ]([-\w\.]+)/i // Chromium
], [NAME, VERSION], [
@ -538,15 +542,15 @@
/( (ce|mobile); ppc;|\/[\w\.]+arm\b)/i
], [[ARCHITECTURE, 'arm']], [
/((ppc|powerpc)(64)?)( mac|;|\))/i // PowerPC
], [[ARCHITECTURE, /ower/, EMPTY, lowerize]], [
/ sun4\w[;\)]/i // SPARC
], [[ARCHITECTURE, 'sparc']], [
/\b(avr32|ia64(?=;)|68k(?=\))|\barm(?=v([1-7]|[5-7]1)l?|;|eabi)|(irix|mips|sparc)(64)?\b|pa-risc)/i
// IA64, 68K, ARM/64, AVR/32, IRIX/64, MIPS/64, SPARC/64, PA-RISC
], [[ARCHITECTURE, lowerize]]
/\b(avr32|ia64(?=;)|68k(?=\))|\barm(?=v([1-7]|[5-7]1)l?|;|eabi)|(irix|mips|sparc)(64)?\b|pa-risc)/i,
/((ppc|powerpc)(64)?)( mac|;|\))/i, // PowerPC
/(?:osf1|[freopnt]{3,4}bsd) (alpha)/i // Alpha
], [[ARCHITECTURE, /ower/, EMPTY, lowerize]], [
/winnt.+\[axp/i
], [[ARCHITECTURE, 'alpha']]
],
device : [[
@ -770,7 +774,8 @@
/; (blu|hmd|imo|infinix|lava|oneplus|tcl)[_ ]([\w\+ ]+?)(?: bui|\)|; r)/i, // BLU/HMD/IMO/Infinix/Lava/OnePlus/TCL
/(hp) ([\w ]+\w)/i, // HP iPAQ
/(microsoft); (lumia[\w ]+)/i, // Microsoft Lumia
/(oppo) ?([\w ]+) bui/i // OPPO
/(oppo) ?([\w ]+) bui/i, // OPPO
/droid[^;]+; (philips)[_ ]([sv-x][\d]{3,4}[xz]?)/i // Philips
], [VENDOR, MODEL, [TYPE, MOBILE]], [
/(kobo)\s(ereader|touch)/i, // Kobo
@ -797,6 +802,7 @@
// SMARTTVS
///////////////////
/(philips)[\w ]+tv/i, // Philips
/smart-tv.+(samsung)/i // Samsung
], [VENDOR, [TYPE, SMARTTV]], [
/hbbtv.+maple;(\d+)/i
@ -834,11 +840,6 @@
/\b(roku)[\dx]*[\)\/]((?:dvp-)?[\d\.]*)/i, // Roku
/hbbtv\/\d+\.\d+\.\d+ +\([\w\+ ]*; *([\w\d][^;]*);([^;]*)/i // HbbTV devices
], [[VENDOR, /.+\/(\w+)/, '$1', strMapper, {'LG':'lge'}], [MODEL, trim], [TYPE, SMARTTV]], [
// SmartTV from Unidentified Vendors
/droid.+; ([\w- ]+) (?:android tv|smart[- ]?tv)/i
], [MODEL, [TYPE, SMARTTV]], [
/\b(android tv|smart[- ]?tv|opera tv|tv; rv:|large screen[\w ]+safari)\b/i
], [[TYPE, SMARTTV]], [
///////////////////
// CONSOLES
@ -885,7 +886,7 @@
/droid.+; (glass) \d/i // Google Glass
], [MODEL, [VENDOR, GOOGLE], [TYPE, XR]], [
/(pico) (4|neo3(?: link|pro)?)/i // Pico
/(pico) ([\w ]+) os\d/i // Pico
], [VENDOR, MODEL, [TYPE, XR]], [
/(quest( \d| pro)?s?).+vr/i // Meta Quest
], [MODEL, [VENDOR, FACEBOOK], [TYPE, XR]], [
@ -909,6 +910,10 @@
// MIXED (GENERIC)
///////////////////
/droid.+; ([\w- ]+) (4k|android|smart|google)[- ]?tv/i // Unidentifiable SmartTV
], [MODEL, [TYPE, SMARTTV]], [
/\b((4k|android|smart|opera)[- ]?tv|tv; rv:|large screen[\w ]+safari)\b/i
], [[TYPE, SMARTTV]], [
/droid .+?; ([^;]+?)(?: bui|; wv\)|\) applew).+?(mobile|vr|\d) safari/i
], [MODEL, [TYPE, strMapper, { 'mobile' : 'Mobile', 'xr' : 'VR', '*' : TABLET }]], [
/\b((tablet|tab)[;\/]|focus\/\d(?!.+mobile))/i // Unidentifiable Tablet
@ -1265,7 +1270,7 @@
case UA_ENGINE:
var brands = uaCH[FULLVERLIST] || uaCH[BRANDS], prevName;
if (brands) {
for (var i in brands) {
for (var i=0; i<brands.length; i++) {
var brandName = brands[i].brand || brands[i],
brandVersion = brands[i].version;
if (this.itemType == UA_BROWSER &&
@ -1387,11 +1392,22 @@
extensions = undefined;
}
if (headers) {
if (typeof headers.append === FUNC_TYPE) {
// Convert Headers object into a plain object
if (headers && typeof headers.append === FUNC_TYPE) {
var kv = {};
headers.forEach(function (v, k) { kv[k] = v; });
headers.forEach(function (v, k) { kv[String(k).toLowerCase()] = v; });
headers = kv;
} else {
// Normalize headers field name into lowercase
var normalized = {};
for (var header in headers) {
if (headers.hasOwnProperty(header)) {
normalized[String(header).toLowerCase()] = headers[header];
}
}
headers = normalized;
}
}
if (!(this instanceof UAParser)) {

242
test/data/ua-ch/headers.js Normal file
View File

@ -0,0 +1,242 @@
const UACHTests = [
{
desc: 'Avast Secure Browser',
headers : {
'sec-ch-ua': '"Avast Secure Browser";v="131", "Chromium";v="131", "Not_A Brand";v="24"'
},
expect: {
browser : {
name : 'Avast Secure Browser',
version : '131',
major : '131',
type : undefined
}
}
},
{
desc: 'Brave',
headers : {
'sec-ch-ua': '"Not A(Brand";v="8", "Chromium";v="132", "Brave";v="132"'
},
expect: {
browser : {
name : 'Brave',
version : '132',
major : '132',
type : undefined
}
}
},
{
desc: 'Chrome',
headers : {
'sec-ch-ua': '"Google Chrome";v="111", "Not(A:Brand";v="8", "Chromium";v="111"'
},
expect: {
browser : {
name : 'Chrome',
version : '111',
major : '111',
type : undefined
}
}
},
{
desc: 'Chrome Headless',
headers : {
'sec-ch-ua': '"Chromium";v="124", "HeadlessChrome";v="124", "Not-A.Brand";v="99"'
},
expect: {
browser : {
name : 'Chrome Headless',
version : '124',
major : '124',
type : undefined
}
}
},
{
desc: 'Chrome WebView',
headers : {
'sec-ch-ua': '"Android WebView";v="123", "Not:A-Brand";v="8", "Chromium";v="123"'
},
expect: {
browser : {
name : 'Chrome WebView',
version : '123',
major : '123',
type : undefined
}
}
},
{
desc: 'DuckDuckGo',
headers : {
'sec-ch-ua': '"DuckDuckGo";v="131", "Chromium";v="131", "Not_A Brand";v="24"'
},
expect : {
browser : {
name : 'DuckDuckGo',
version : '131',
major : '131',
type : undefined
}
}
},
{
desc: 'Edge',
headers : {
'sec-ch-ua': '"Not_A Brand";v="8", "Chromium";v="120", "Microsoft Edge";v="120"'
},
expect: {
browser : {
name : 'Edge',
version : '120',
major : '120',
type : undefined
}
}
},
{
desc: 'Edge WebView2',
headers : {
'sec-ch-ua': '" Not;A Brand";v="99", "Microsoft Edge";v="103", "Chromium";v="103", "Microsoft Edge WebView2";v="104"'
},
expect: {
browser : {
name : 'Edge WebView2',
version : '104',
major : '104',
type : undefined
}
}
},
{
desc: 'Huawei Browser',
headers : {
'sec-ch-ua': '"Not.A/Brand";v="8", "Chromium";v="114", "HuaweiBrowser";v="114"'
},
expect: {
browser : {
name : 'Huawei Browser',
version : '114',
major : '114',
type : undefined
}
}
},
{
desc: 'MIUI Browser',
headers : {
'sec-ch-ua': '"Miui Browser";v="123", "Not:A-Brand";v="8", "Chromium";v="123"'
},
expect: {
browser : {
name : 'MIUI Browser',
version : '123',
major : '123',
type : undefined
}
}
},
{
desc: 'Oculus Browser',
headers : {
'sec-ch-ua': '"Chromium";v="130", "Oculus Browser";v="36", "Not?A_Brand";v="99"'
},
expect: {
browser : {
name : 'Oculus Browser',
version : '36',
major : '36',
type : undefined
}
}
},
{
desc: 'Opera',
headers : {
'sec-ch-ua': '"Opera";v="116", "Chromium";v="131", "Not_A Brand";v="24"'
},
expect: {
browser : {
name : 'Opera',
version : '116',
major : '116',
type : undefined
}
}
},
{
desc: 'Opera GX',
headers : {
'sec-ch-ua': '"Chromium";v="128", "Not;A=Brand";v="24", "Opera GX";v="114"'
},
expect: {
browser : {
name : 'Opera GX',
version : '114',
major : '114',
type : undefined
}
}
},
{
desc: 'Opera Mobi',
headers : {
'sec-ch-ua': '"OperaMobile";v="86", ";Not A Brand";v="99", "Opera";v="115", "Chromium";v="130"'
},
expect: {
browser : {
name : 'Opera Mobi',
version : '86',
major : '86',
type : undefined
}
}
},
{
desc: 'Opera Mobi',
headers : {
'sec-ch-ua': '"Chromium";v="132", "OperaMobile";v="87", "Opera";v="117", " Not A;Brand";v="99"'
},
expect: {
browser : {
name : 'Opera Mobi',
version : '87',
major : '87',
type : undefined
}
}
},
{
desc: 'Samsung Internet',
headers : {
'sec-ch-ua': '"Chromium";v="125", "Not.A/Brand";v="24", "Samsung Internet";v="27.0"'
},
expect: {
browser : {
name : 'Samsung Internet',
version : '27.0',
major : '27',
type : undefined
}
}
},
{
desc: 'Yandex',
headers : {
'sec-ch-ua': '"Chromium";v="130", "YaBrowser";v="24.12", "Not?A_Brand";v="99", "Yowser";v="2.5"'
},
expect: {
browser : {
name : 'Yandex',
version : '24.12',
major : '24',
type : undefined
}
}
}
];
module.exports = UACHTests;

View File

@ -2695,5 +2695,27 @@
"major" : "10",
"type" : "inapp"
}
},
{
"desc" : "Zalo on iOS",
"ua" : "Mozilla/5.0 (iPhone; CPU iPhone OS 13_5_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Zalo/20.05.01 Mobile/15E148",
"expect" :
{
"name" : "Zalo",
"version" : "20.05.01",
"major" : "20",
"type" : "inapp"
}
},
{
"desc" : "Zalo on Android",
"ua" : "Mozilla/5.0 (Linux; Android 10; Vsmart Live Build/QKQ1.190918.001; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/78.0.3904.108 Mobile Safari/537.36 Zalo/20.04.02.r1",
"expect" :
{
"name" : "Zalo",
"version" : "20.04.02.r1",
"major" : "20",
"type" : "inapp"
}
}
]

View File

@ -87,6 +87,22 @@
"architecture" : "amd64"
}
},
{
"desc" : "Alpha",
"ua" : "Mozilla/3.01 (WinNT; I) [AXP]",
"expect" :
{
"architecture" : "alpha"
}
},
{
"desc" : "Alpha",
"ua" : "Mozilla/5.0 (X11; OpenBSD alpha; rv:78.0) Gecko/20100101 Firefox/78.0",
"expect" :
{
"architecture" : "alpha"
}
},
{
"desc" : "ARM",
"ua" : "Mozilla/5.0 (Mobile; Windows Phone 8.1; Android 4.0; ARM; Trident/7.0; Touch; rv:11.0; IEMobile/11.0; NOKIA; Lumia 635) like iPhone OS 7_0_3 Mac OS X AppleWebKit/537 (KHTML, like Gecko) Mobile Safari/537",

View File

@ -122,42 +122,6 @@
"type": "undefined"
}
},
{
"desc": "Philips SmartTV",
"ua": "Opera/9.80 HbbTV/1.1.1 (; Philips; ; ; ; ) NETTV/4.0.2; en) Version/11.60",
"expect": {
"vendor": "Philips",
"model": "",
"type": "smarttv"
}
},
{
"desc": "Philips 32PFL6606K/02 SmartTV (2011)",
"ua": "Opera/9.80 (Linux mips ; U; HbbTV/1.1.1 (; Philips; ; ; ; ) CE-HTML/1.0 NETTV/3.1.0; en) Presto/2.6.33 Version/10.70",
"expect": {
"vendor": "Philips",
"model": "",
"type": "smarttv"
}
},
{
"desc": "Philips 32PFL6606K/02 SmartTV (2013)",
"ua": "Opera/9.80 (Linux mips ; U; HbbTV/1.1.1 (; Philips; ; ; ; ) CE-HTML/1.0 NETTV/3.1.0; en) Presto/2.6.33 Version/10.70",
"expect": {
"vendor": "Philips",
"model": "",
"type": "smarttv"
}
},
{
"desc": "Philips 32PHS5301/12 SmartTV (2016)",
"ua": "Mozilla/5.0 (Linux armv7l) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/42.0.2311.152 Safari/537.36 OPR/29.0.1803.0 OMI/4.5.23.37.MOT2.13 HbbTV/1.2.1 (;Philips;32PHS5301/12;;_TV_MT5800;) Firmware/TPM161E_012.002.045.001 en",
"expect": {
"vendor": "Philips",
"model": "32PHS5301/12",
"type": "smarttv"
}
},
{
"desc": "Samsung SmartTV",
"ua": "Mozilla/5.0 (SMART-TV; X11; Linux armv7l) AppleWebkit/537.42 (KHTML, like Gecko) Safari/537.42",

View File

@ -0,0 +1,83 @@
[
{
"desc": "Philips S616",
"ua": "Mozilla/5.0 (Linux; Android 5.1; Philips S616 Build/LMY47D) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.109 Mobile Safari/537.36",
"expect": {
"vendor": "Philips",
"model": "S616",
"type": "mobile"
}
},
{
"desc": "Philips W8510",
"ua": "Mozilla/5.0 (Linux; Android 4.2.2; Philips W8510 Build/JDQ39) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.68 Mobile Safari/537.36",
"expect": {
"vendor": "Philips",
"model": "W8510",
"type": "mobile"
}
},
{
"desc": "Philips SmartTV",
"ua": "Mozilla/5.0 (Linux; Android 11; PHILIPS 4k TV Build/RTXC.231010.082.A1; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/126.0.6478.71 Mobile Safari/537.36",
"expect": {
"vendor": "PHILIPS",
"model": "undefined",
"type": "smarttv"
}
},
{
"desc": "Philips SmartTV",
"ua": "Opera/9.80 HbbTV/1.1.1 (; Philips; ; ; ; ) NETTV/4.0.2; en) Version/11.60",
"expect": {
"vendor": "Philips",
"model": "",
"type": "smarttv"
}
},
{
"desc": "Philips 32PFL6606K/02 SmartTV (2011)",
"ua": "Opera/9.80 (Linux mips ; U; HbbTV/1.1.1 (; Philips; ; ; ; ) CE-HTML/1.0 NETTV/3.1.0; en) Presto/2.6.33 Version/10.70",
"expect": {
"vendor": "Philips",
"model": "",
"type": "smarttv"
}
},
{
"desc": "Philips 32PFL6606K/02 SmartTV (2013)",
"ua": "Opera/9.80 (Linux mips ; U; HbbTV/1.1.1 (; Philips; ; ; ; ) CE-HTML/1.0 NETTV/3.1.0; en) Presto/2.6.33 Version/10.70",
"expect": {
"vendor": "Philips",
"model": "",
"type": "smarttv"
}
},
{
"desc": "Philips 32PHS5301/12 SmartTV (2016)",
"ua": "Mozilla/5.0 (Linux armv7l) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/42.0.2311.152 Safari/537.36 OPR/29.0.1803.0 OMI/4.5.23.37.MOT2.13 HbbTV/1.2.1 (;Philips;32PHS5301/12;;_TV_MT5800;) Firmware/TPM161E_012.002.045.001 en",
"expect": {
"vendor": "Philips",
"model": "32PHS5301/12",
"type": "smarttv"
}
},
{
"desc": "Philips PH0M_EA_T32",
"ua": "Mozilla/5.0 (Linux; Android 10; Philips FHD Android TV Build/QTG3.201102.001; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/125.0.6422.186 Mobile Safari/537.36",
"expect": {
"vendor": "Philips",
"model": "undefined",
"type": "smarttv"
}
},
{
"desc": "Philips PH3M_AL_T32",
"ua": "Mozilla/5.0 (Linux; Android 11; Philips Google TV TA7 Build/RTM5.220609.199; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/111.0.5563.58 Mobile Safari/537.36",
"expect": {
"vendor": "Philips",
"model": "undefined",
"type": "smarttv"
}
}
]

View File

@ -25,5 +25,23 @@
"model": "Neo3 Link",
"type": "xr"
}
},
{
"desc": "Pico Neo 3",
"ua": "Mozilla/5.0 (X11; Linux x86_64; Pico Neo 3 OS5.12.2 like Quest) AppleWebKit/537.36 (KHTML, like Gecko) PicoBrowser/3.3.48 Chrome/105.0.5195.68 VR Safari/537.36 OculusBrowser/7.0",
"expect": {
"vendor": "Pico",
"model": "Neo 3",
"type": "xr"
}
},
{
"desc": "Pico Neo 3 Pro",
"ua": "Mozilla/5.0 (X11; Linux x86_64; Pico Neo 3 Pro OS5.9.9.0 like Quest) AppleWebKit/537.36 (KHTML, like Gecko) PicoBrowser/3.3.46 Chrome/105.0.5195.68 VR Safari/537.36 OculusBrowser/7.0",
"expect": {
"vendor": "Pico",
"model": "Neo 3 Pro",
"type": "xr"
}
}
]

View File

@ -79,6 +79,26 @@
"type" : "crawler"
}
},
{
"desc" : "Algolia Crawler",
"ua" : "Algolia Crawler/v2.183.0",
"expect" :
{
"name" : "Algolia Crawler",
"version" : "v2.183.0",
"type" : "crawler"
}
},
{
"desc" : "Algolia Crawler Renderscript",
"ua" : "Algolia Crawler Renderscript",
"expect" :
{
"name" : "Algolia Crawler Renderscript",
"version" : "undefined",
"type" : "crawler"
}
},
{
"desc" : "Applebot",
"ua" : "Mozilla/5.0 (iPhone; CPU iPhone OS 8_1 like Mac OS X) AppleWebKit/600.1.4 (KHTML, like Gecko) Version/8.0 Mobile/12B410 Safari/600.1.4 (Applebot/0.1;+http://www.apple.com/go/applebot)",
@ -139,6 +159,16 @@
"type" : "crawler"
}
},
{
"desc" : "Baidu ADS",
"ua" : "Baidu-ADS",
"expect" :
{
"name" : "Baidu-ADS",
"version" : "undefined",
"type" : "crawler"
}
},
{
"desc" : "Baiduspider",
"ua" : "Mozilla/5.0 (compatible; Baiduspider/2.0; +http://www.baidu.com/search/spider.html)",
@ -229,6 +259,36 @@
"type" : "crawler"
}
},
{
"desc" : "BLEXBot",
"ua" : "Mozilla/5.0 (compatible; BLEXBot/1.0; +http://webmeup-crawler.com/)",
"expect" :
{
"name" : "BLEXBot",
"version" : "1.0",
"type" : "crawler"
}
},
{
"desc" : "botify",
"ua" : "Desktop: Mozilla/5.0 (compatible; botify; http://botify.com)",
"expect" :
{
"name" : "botify",
"version" : "undefined",
"type" : "crawler"
}
},
{
"desc" : "Bravebot",
"ua" : "Mozilla/5.0 AppleWebKit/537.36 (KHTML, like Gecko; compatible; Bravebot/1.0; +https://search.brave.com/help/brave-search-crawler) Chrome/W.X.Y.Z Safari/537.36",
"expect" :
{
"name" : "Bravebot",
"version" : "1.0",
"type" : "crawler"
}
},
{
"desc" : "Bytespider",
"ua" : "Mozilla/5.0 (Linux; Android 8.0; Pixel 2 Build/OPD3.170816.012) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.1511.1269 Mobile Safari/537.36; Bytespider",
@ -269,6 +329,26 @@
"type" : "crawler"
}
},
{
"desc" : "Claude-SearchBot",
"ua" : "Mozilla/5.0 AppleWebKit/537.36 (KHTML, like Gecko; compatible; Claude-SearchBot/1.0; +Claude-SearchBot@anthropic.com)",
"expect" :
{
"name" : "Claude-SearchBot",
"version" : "1.0",
"type" : "crawler"
}
},
{
"desc" : "ClaudeWeb",
"ua" : "Claude-Web/1.0 (web crawler; +https://www.anthropic.com/; bots@anthropic.com)",
"expect" :
{
"name" : "Claude-Web",
"version" : "1.0",
"type" : "crawler"
}
},
{
"desc" : "Coc Coc Bot (web)",
"ua" : "Mozilla/5.0 (compatible; coccocbot-web/1.0; +http://help.coccoc.com/searchengine)",
@ -290,15 +370,55 @@
}
},
{
"desc" : "ClaudeWeb",
"ua" : "Claude-Web/1.0 (web crawler; +https://www.anthropic.com/; bots@anthropic.com)",
"desc" : "cohere-training-data-crawler",
"ua" : "cohere-training-data-crawler (+crawler@cohere.ai)",
"expect" :
{
"name" : "Claude-Web",
"name" : "cohere-training-data-crawler",
"version" : "undefined",
"type" : "crawler"
}
},
{
"desc" : "contxbot",
"ua" : "Mozilla/5.0 (compatible;contxbot/1.0)",
"expect" :
{
"name" : "contxbot",
"version" : "1.0",
"type" : "crawler"
}
},
{
"desc" : "Cotoyogi",
"ua" : "Mozilla/5.0 (compatible; Cotoyogi/4.0; +https://ds.rois.ac.jp/center8/crawler/)",
"expect" :
{
"name" : "Cotoyogi",
"version" : "4.0",
"type" : "crawler"
}
},
{
"desc" : "Coveobot",
"ua" : "Mozilla/5.0 AppleWebKit/537.36 (KHTML, like Gecko) (compatible; Coveobot/2.0;+http://www.coveo.com/bot.html)",
"expect" :
{
"name" : "Coveobot",
"version" : "2.0",
"type" : "crawler"
}
},
{
"desc" : "CriteoBot",
"ua" : "CriteoBot/0.1 (+https://www.criteo.com/criteo-crawler/)",
"expect" :
{
"name" : "CriteoBot",
"version" : "0.1",
"type" : "crawler"
}
},
{
"desc" : "DataForSEO",
"ua" : "Mozilla/5.0 (compatible; DataForSeoBot; +https://dataforseo.com/dataforseo-bot)",
@ -339,6 +459,16 @@
"type" : "crawler"
}
},
{
"desc" : "DeepSeekBot",
"ua" : "DeepSeekBot",
"expect" :
{
"name" : "DeepSeekBot",
"version" : "undefined",
"type" : "crawler"
}
},
{
"desc" : "Diffbot",
"ua" : "Diffbot/0.1",
@ -369,6 +499,26 @@
"type" : "crawler"
}
},
{
"desc" : "DuckDuckGo-Favicons-Bot",
"ua" : "DuckDuckGo-Favicons-Bot/1.0",
"expect" :
{
"name" : "DuckDuckGo-Favicons-Bot",
"version" : "1.0",
"type" : "crawler"
}
},
{
"desc" : "Elastic",
"ua" : "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/124.0.6367.29 Safari/537.36 Elastic/Synthetics",
"expect" :
{
"name" : "Elastic",
"version" : "undefined",
"type" : "crawler"
}
},
{
"desc" : "Exabot",
"ua" : "Mozilla/5.0 (compatible; Exabot/3.0; +http://www.exabot.com/go/robot)",
@ -409,6 +559,36 @@
"type" : "crawler"
}
},
{
"desc" : "FirecrawlAgent",
"ua" : "Mozilla/5.0 (compatible; FirecrawlAgent/1.0)",
"expect" :
{
"name" : "FirecrawlAgent",
"version" : "1.0",
"type" : "crawler"
}
},
{
"desc" : "Freespoke",
"ua" : "Mozilla/5.0 (compatible; Freespoke/2.0; +https://docs.freespoke.com/search/bot)",
"expect" :
{
"name" : "Freespoke",
"version" : "2.0",
"type" : "crawler"
}
},
{
"desc" : "APIs-Google",
"ua" : "APIs-Google (+https://developers.google.com/webmasters/APIs-Google.html)",
"expect" :
{
"name" : "APIs-Google",
"version" : "undefined",
"type" : "crawler"
}
},
{
"desc" : "Googlebot-Video",
"ua" : "Googlebot-Video/1.0",
@ -509,6 +689,16 @@
"type" : "crawler"
}
},
{
"desc" : "Google-CloudVertexBot",
"ua" : "Mozilla/5.0 (Linux; Android 6.0.1; Nexus 5X Build/MMB29P) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/138.0.7204.183 Mobile Safari/537.36 (compatible; Google-CloudVertexBot; +https://cloud.google.com/enterprise-search)",
"expect" :
{
"name" : "Google-CloudVertexBot",
"version" : "undefined",
"type" : "crawler"
}
},
{
"desc" : "Google-Safety",
"ua" : "Google-Safety",
@ -529,6 +719,16 @@
"type" : "crawler"
}
},
{
"desc" : "HuggingFace-Bot",
"ua" : "Mozilla/5.0 (compatible; HuggingFace-Bot/1.0; +https://huggingface.co/)",
"expect" :
{
"name" : "HuggingFace-Bot",
"version" : "1.0",
"type" : "crawler"
}
},
{
"desc" : "iAskBot",
"ua" : "Mozilla/5.0 AppleWebKit/605.1.15 (KHTML, like Gecko; compatible; iAskBot/1.0; +https://iask.ai/) Chrome/120.0.6099.119 Safari/605.1.15",
@ -549,6 +749,26 @@
"type" : "crawler"
}
},
{
"desc" : "Kagibot",
"ua" : "Mozilla/5.0 (compatible; Kagibot/1.0; +https://kagi.com/bot)",
"expect" :
{
"name" : "Kagibot",
"version" : "1.0",
"type" : "crawler"
}
},
{
"desc" : "Kangaroo Bot",
"ua" : "Mozilla/5.0 (compatible; Kangaroo Bot/1.0)",
"expect" :
{
"name" : "Kangaroo Bot",
"version" : "1.0",
"type" : "crawler"
}
},
{
"desc" : "Linespider",
"ua" : "Mozilla/5.0 (compatible; Linespider/1.1; +https://lin.ee/4dwXkTH)",
@ -579,6 +799,16 @@
"type" : "crawler"
}
},
{
"desc" : "Marginalia Search",
"ua" : "search.marginalia.nu",
"expect" :
{
"name" : "marginalia",
"version" : "undefined",
"type" : "crawler"
}
},
{
"desc" : "Meta-ExternalAgent",
"ua" : "meta-externalagent/1.1 (+https://developers.facebook.com/docs/sharing/webmasters/crawler)",
@ -610,6 +840,16 @@
"type" : "crawler"
}
},
{
"desc" : "msnbot",
"ua" : "msnbot/2.0b (+http://search.msn.com/msnbot.htm)",
"expect" :
{
"name" : "msnbot",
"version" : "2.0b",
"type" : "crawler"
}
},
{
"desc" : "Omgili",
"ua" : "omgili/0.5 +https://omgili.com",
@ -630,6 +870,16 @@
"type" : "crawler"
}
},
{
"desc" : "OnCrawl",
"ua" : "Mozilla/5.0 (iPhone; CPU iPhone OS 8_3 like Mac OS X) AppleWebKit/600.1.4 (KHTML, like Gecko) Version/8.0 Mobile/12F70 Safari/600.1.4 (compatible; OnCrawl Mobile/1.0; +http://www.oncrawl.com/)",
"expect" :
{
"name" : "OnCrawl",
"version" : "1.0",
"type" : "crawler"
}
},
{
"desc" : "Onespot",
"ua" : "Mozilla/5.0 (compatible; Onespot-ScraperBot/1.0; +https://www.onespot.com/identifying-traffic.html)",
@ -650,6 +900,16 @@
"type" : "crawler"
}
},
{
"desc" : "PanguBot",
"ua" : "Mozilla/5.0 (compatible; PanguBot/1.0)",
"expect" :
{
"name" : "PanguBot",
"version" : "1.0",
"type" : "crawler"
}
},
{
"desc" : "PerplexityBot",
"ua" : "Mozilla/5.0 AppleWebKit/537.36 (KHTML, like Gecko; compatible; PerplexityBot/1.0; +https://perplexity.ai/perplexitybot)",
@ -710,6 +970,46 @@
"type" : "crawler"
}
},
{
"desc" : "Replicate-Bot",
"ua" : "Mozilla/5.0 (compatible; Replicate-Bot/1.0; +https://replicate.com/)",
"expect" :
{
"name" : "Replicate-Bot",
"version" : "1.0",
"type" : "crawler"
}
},
{
"desc" : "RunPod-Bot",
"ua" : "Mozilla/5.0 (compatible; RunPod-Bot/1.0; +https://runpod.io/)",
"expect" :
{
"name" : "RunPod-Bot",
"version" : "1.0",
"type" : "crawler"
}
},
{
"desc" : "SBIntuitionsBot",
"ua" : "Mozilla/5.0 (compatible; SBIntuitionsBot/0.1;+https://www.sbintuitions.co.jp/bot/)",
"expect" :
{
"name" : "SBIntuitionsBot",
"version" : "0.1",
"type" : "crawler"
}
},
{
"desc" : "SeekportBot",
"ua" : "Mozilla/5.0 (compatible; SeekportBot; +https://bot.seekport.com)",
"expect" :
{
"name" : "SeekportBot",
"version" : "undefined",
"type" : "crawler"
}
},
{
"desc" : "SemrushBot",
"ua" : "Mozilla/5.0 (compatible; SemrushBot/7~bl; +http://www.semrush.com/bot.html)",
@ -761,7 +1061,27 @@
}
},
{
"desc" : "Sogou",
"desc" : "Siteimprove",
"ua" : "Mozilla/5.0 AppleWebKit/537.36 (KHTML, like Gecko; compatible; SiteCheck-sitecrawl by Siteimprove.com; +https://siteimprove.com/bots) Chrome/[VERSION] Safari/537.36",
"expect" :
{
"name" : "Siteimprove",
"version" : "undefined",
"type" : "crawler"
}
},
{
"desc" : "Sogou Pic Spider",
"ua" : "Sogou Pic Spider/3.0( http://www.sogou.com/docs/help/webmasters.htm#07)",
"expect" :
{
"name" : "Sogou Pic Spider",
"version" : "3.0",
"type" : "crawler"
}
},
{
"desc" : "Sogou web spider",
"ua" : "Sogou web spider/4.0(+http://www.sogou.com/docs/help/webmasters.htm#07)",
"expect" :
{
@ -790,6 +1110,16 @@
"type" : "crawler"
}
},
{
"desc" : "TikTokSpider",
"ua" : "Mozilla/5.0 (Linux; Android 5.0) AppleWebKit/537.36 (KHTML, like Gecko) Mobile Safari/537.36 (compatible; TikTokSpider; ttspider-feedback@tiktok.com)",
"expect" :
{
"name" : "TikTokSpider",
"version" : "undefined",
"type" : "crawler"
}
},
{
"desc" : "Timpibot",
"ua" : "Timpibot/0.8 (+http://www.timpi.io)",
@ -800,6 +1130,16 @@
"type" : "crawler"
}
},
{
"desc" : "Together-Bot",
"ua" : "Mozilla/5.0 (compatible; Together-Bot/1.0; +https://together.ai/)",
"expect" :
{
"name" : "Together-Bot",
"version" : "1.0",
"type" : "crawler"
}
},
{
"desc" : "TurnitinBot",
"ua" : "TurnitinBot (https://turnitin.com/robot/crawlerinfo.html)",
@ -810,6 +1150,26 @@
"type" : "crawler"
}
},
{
"desc" : "TwinAgent",
"ua" : "TwinAgent/1.0",
"expect" :
{
"name" : "TwinAgent",
"version" : "1.0",
"type" : "crawler"
}
},
{
"desc" : "xAI-Bot",
"ua" : "Mozilla/5.0 (compatible; xAI-Bot/1.0; +https://x.ai/)",
"expect" :
{
"name" : "xAI-Bot",
"version" : "1.0",
"type" : "crawler"
}
},
{
"desc" : "VelenPublicWebCrawler",
"ua" : "Mozilla/5.0 (compatible; VelenPublicWebCrawler/1.0; +https://velen.io)",
@ -820,6 +1180,36 @@
"type" : "crawler"
}
},
{
"desc" : "v0bot",
"ua" : "v0bot",
"expect" :
{
"name" : "v0bot",
"version" : "undefined",
"type" : "crawler"
}
},
{
"desc" : "webzio",
"ua" : "webzio (+https://webz.io/bot.html)",
"expect" :
{
"name" : "webzio",
"version" : "undefined",
"type" : "crawler"
}
},
{
"desc" : "Webzio-Extended",
"ua" : "Mozilla/5.0 (compatible; Webzio-Extended/1.0; +https://www.webzio.com/bot.html)",
"expect" :
{
"name" : "Webzio-Extended",
"version" : "1.0",
"type" : "crawler"
}
},
{
"desc" : "Yahoo! Japan",
"ua" : "Y!J-BRW/1.0 (https://www.yahoo-help.jp/app/answers/detail/p/595/a_id/42716)",
@ -840,6 +1230,46 @@
"type" : "crawler"
}
},
{
"desc" : "YandexAccessibilityBot",
"ua" : "Mozilla/5.0 (compatible; YandexAccessibilityBot/3.0; +http://yandex.com/bots)",
"expect" :
{
"name" : "YandexAccessibilityBot",
"version" : "3.0",
"type" : "crawler"
}
},
{
"desc" : "YandexAdditionalBot",
"ua" : "Mozilla/5.0 (compatible; YandexAdditionalBot/3.0; +http://yandex.com/bots)",
"expect" :
{
"name" : "YandexAdditionalBot",
"version" : "3.0",
"type" : "crawler"
}
},
{
"desc" : "YandexAdNet",
"ua" : "Mozilla/5.0 (compatible; YandexAdNet/1.0; +http://yandex.com/bots)",
"expect" :
{
"name" : "YandexAdNet",
"version" : "1.0",
"type" : "crawler"
}
},
{
"desc" : "YandexBlogs",
"ua" : "Mozilla/5.0 (compatible; YandexBlogs/0.99; robot; +http://yandex.com/bots)",
"expect" :
{
"name" : "YandexBlogs",
"version" : "0.99",
"type" : "crawler"
}
},
{
"desc" : "YandexBot",
"ua" : "Mozilla/5.0 (compatible; YandexBot/3.0; +http://yandex.com/bots)",
@ -850,6 +1280,256 @@
"type" : "crawler"
}
},
{
"desc" : "YandexBot MirrorDetector",
"ua" : "Mozilla/5.0 (compatible; YandexBot/3.0; MirrorDetector; +http://yandex.com/bots)",
"expect" :
{
"name" : "YandexBot MirrorDetector",
"version" : "3.0",
"type" : "crawler"
}
},
{
"desc" : "YandexComBot",
"ua" : "Mozilla/5.0 (compatible; YandexComBot/3.0; +http://yandex.com/bots)",
"expect" :
{
"name" : "YandexComBot",
"version" : "3.0",
"type" : "crawler"
}
},
{
"desc" : "YandexFavicons",
"ua" : "Mozilla/5.0 (compatible; YandexFavicons/1.0; +http://yandex.com/bots)",
"expect" :
{
"name" : "YandexFavicons",
"version" : "1.0",
"type" : "crawler"
}
},
{
"desc" : "YandexImageResizer",
"ua" : "Mozilla/5.0 (compatible; YandexImageResizer/2.0; +http://yandex.com/bots)",
"expect" :
{
"name" : "YandexImageResizer",
"version" : "2.0",
"type" : "crawler"
}
},
{
"desc" : "YandexImages",
"ua" : "Mozilla/5.0 (compatible; YandexImages/3.0; +http://yandex.com/bots)",
"expect" :
{
"name" : "YandexImages",
"version" : "3.0",
"type" : "crawler"
}
},
{
"desc" : "YandexMarket",
"ua" : "Mozilla/5.0 (compatible; YandexMarket/1.0; +http://yandex.com/bots)",
"expect" :
{
"name" : "YandexMarket",
"version" : "1.0",
"type" : "crawler"
}
},
{
"desc" : "YandexMetrika",
"ua" : "Mozilla/5.0 (compatible; YandexMetrika/2.0; +http://yandex.com/bots)",
"expect" :
{
"name" : "YandexMetrika",
"version" : "2.0",
"type" : "crawler"
}
},
{
"desc" : "YandexMedia",
"ua" : "Mozilla/5.0 (compatible; YandexMedia/3.0; +http://yandex.com/bots)",
"expect" :
{
"name" : "YandexMedia",
"version" : "3.0",
"type" : "crawler"
}
},
{
"desc" : "YandexMobileBot",
"ua" : "Mozilla/5.0 (iPhone; CPU iPhone OS 8_1 like Mac OS X) AppleWebKit/600.1.4 (KHTML, like Gecko) Version/8.0 Mobile/12B411 Safari/600.1.4 (compatible; YandexMobileBot/3.0; +http://yandex.com/bots)",
"expect" :
{
"name" : "YandexMobileBot",
"version" : "3.0",
"type" : "crawler"
}
},
{
"desc" : "YandexMobileScreenShotBot",
"ua" : "Mozilla/5.0 (compatible; YandexMobileScreenShotBot/1.0; +http://yandex.com/bots)",
"expect" :
{
"name" : "YandexMobileScreenShotBot",
"version" : "1.0",
"type" : "crawler"
}
},
{
"desc" : "YandexNews",
"ua" : "Mozilla/5.0 (compatible; YandexNews/4.0; +http://yandex.com/bots)",
"expect" :
{
"name" : "YandexNews",
"version" : "4.0",
"type" : "crawler"
}
},
{
"desc" : "YandexOntoDB",
"ua" : "Mozilla/5.0 (compatible; YandexOntoDB/1.0; +http://yandex.com/bots)",
"expect" :
{
"name" : "YandexOntoDB",
"version" : "1.0",
"type" : "crawler"
}
},
{
"desc" : "YandexOntoDBAPI",
"ua" : "Mozilla/5.0 (compatible; YandexOntoDBAPI/1.0; +http://yandex.com/bots)",
"expect" :
{
"name" : "YandexOntoDBAPI",
"version" : "1.0",
"type" : "crawler"
}
},
{
"desc" : "YandexPartner",
"ua" : "Mozilla/5.0 (compatible; YandexPartner/3.0; +http://yandex.com/bots)",
"expect" :
{
"name" : "YandexPartner",
"version" : "3.0",
"type" : "crawler"
}
},
{
"desc" : "YandexRCA",
"ua" : "Mozilla/5.0 (compatible; YandexRCA/1.0; +http://yandex.com/bots)",
"expect" :
{
"name" : "YandexRCA",
"version" : "1.0",
"type" : "crawler"
}
},
{
"desc" : "YandexRenderResourcesBot",
"ua" : "Mozilla/5.0 (compatible; YandexRenderResourcesBot/1.0; +http://yandex.com/bots)",
"expect" :
{
"name" : "YandexRenderResourcesBot",
"version" : "1.0",
"type" : "crawler"
}
},
{
"desc" : "YandexScreenshotBot",
"ua" : "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2272.96 Safari/537.36 (compatible; YandexScreenshotBot/3.0; +http://yandex.com/bots)",
"expect" :
{
"name" : "YandexScreenshotBot",
"version" : "3.0",
"type" : "crawler"
}
},
{
"desc" : "YandexSpravBot",
"ua" : "Mozilla/5.0 (compatible; YandexSpravBot/1.0; +http://yandex.com/bots)",
"expect" :
{
"name" : "YandexSpravBot",
"version" : "1.0",
"type" : "crawler"
}
},
{
"desc" : "YandexTracker",
"ua" : "Mozilla/5.0 (compatible; YandexTracker/1.0; +http://yandex.com/bots)",
"expect" :
{
"name" : "YandexTracker",
"version" : "1.0",
"type" : "crawler"
}
},
{
"desc" : "YandexVertis",
"ua" : "Mozilla/5.0 (compatible; YandexVertis/3.0; +http://yandex.com/bots)",
"expect" :
{
"name" : "YandexVertis",
"version" : "3.0",
"type" : "crawler"
}
},
{
"desc" : "YandexVerticals",
"ua" : "Mozilla/5.0 (compatible; YandexVerticals/1.0; +http://yandex.com/bots)",
"expect" :
{
"name" : "YandexVerticals",
"version" : "1.0",
"type" : "crawler"
}
},
{
"desc" : "YandexVideo",
"ua" : "Mozilla/5.0 (compatible; YandexVideo/3.0; +http://yandex.com/bots)",
"expect" :
{
"name" : "YandexVideo",
"version" : "3.0",
"type" : "crawler"
}
},
{
"desc" : "YandexVideoParser",
"ua" : "Mozilla/5.0 (compatible; YandexVideoParser/1.0; +http://yandex.com/bots)",
"expect" :
{
"name" : "YandexVideoParser",
"version" : "1.0",
"type" : "crawler"
}
},
{
"desc" : "YandexWebmaster",
"ua" : "Mozilla/5.0 (compatible; YandexWebmaster/2.0; +http://yandex.com/bots)",
"expect" :
{
"name" : "YandexWebmaster",
"version" : "2.0",
"type" : "crawler"
}
},
{
"desc" : "YepBot",
"ua" : "Mozilla/5.0 (compatible; YepBot/1.0; +http://yep.com/yepbot/)",
"expect" :
{
"name" : "YepBot",
"version" : "1.0",
"type" : "crawler"
}
},
{
"desc" : "Yeti",
"ua" : "Mozilla/5.0 (compatible; Yeti/1.1; +http://naver.me/spd)",
@ -889,5 +1569,15 @@
"version" : "undefined",
"type" : "crawler"
}
},
{
"desc" : "ZumBot",
"ua" : "Mozilla/5.0 (compatible; ZumBot/1.0; http://help.zum.com/inquiry)",
"expect" :
{
"name" : "ZumBot",
"version" : "1.0",
"type" : "crawler"
}
}
]

View File

@ -9,6 +9,16 @@
"type" : "fetcher"
}
},
{
"desc" : "Asana",
"ua" : "Asana/1.4.0 WebsiteMetadataRetriever",
"expect" :
{
"name" : "Asana",
"version" : "1.4.0",
"type" : "fetcher"
}
},
{
"desc" : "Better Uptime Bot",
"ua" : "Better Uptime Bot Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.169 Safari/537.36",
@ -29,6 +39,26 @@
"type" : "fetcher"
}
},
{
"desc" : "Bit.ly",
"ua" : "bitlybot/3.0 (+http://bit.ly/)",
"expect" :
{
"name" : "bitlybot",
"version" : "3.0",
"type" : "fetcher"
}
},
{
"desc" : "Blueno",
"ua" : "acebookexternalhit/1.1 (compatible; Blueno/1.0; +http://naver.me/scrap)",
"expect" :
{
"name" : "Blueno",
"version" : "1.0",
"type" : "fetcher"
}
},
{
"desc" : "Bluesky",
"ua" : "Mozilla/5.0 AppleWebKit/537.36 (KHTML, like Gecko; compatible; Bluesky Cardyb/1.1; +mailto:support@bsky.app) Chrome/100.0.0.0 Safari/537.36",
@ -39,6 +69,16 @@
"type" : "fetcher"
}
},
{
"desc" : "BufferLinkPreviewBot",
"ua" : "BufferLinkPreviewBot/1.0 (+https://scraper.buffer.com/about/bots/link-preview-bot)",
"expect" :
{
"name" : "BufferLinkPreviewBot",
"version" : "1.0",
"type" : "fetcher"
}
},
{
"desc" : "ChatGPT-User",
"ua" : "Mozilla/5.0 AppleWebKit/537.36 (KHTML, like Gecko); compatible; ChatGPT-User/1.0; +https://openai.com/bot",
@ -49,6 +89,36 @@
"type" : "fetcher"
}
},
{
"desc" : "Chrome-Lighthouse",
"ua" : "Mozilla/5.0 (Linux; Android 7.0; Moto G (4)) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/94.0.4590.2 Mobile Safari/537.36 Chrome-Lighthouse",
"expect" :
{
"name" : "Chrome-Lighthouse",
"version" : "undefined",
"type" : "fetcher"
}
},
{
"desc" : "Claude-User",
"ua" : "Mozilla/5.0 AppleWebKit/537.36 (KHTML, like Gecko; compatible; Claude-User/1.0; +Claude-User@anthropic.com)",
"expect" :
{
"name" : "Claude-User",
"version" : "1.0",
"type" : "fetcher"
}
},
{
"desc" : "Cohere-AI",
"ua" : "Mozilla/5.0 (compatible; Cohere-AI/1.0; +https://cohere.com/)",
"expect" :
{
"name" : "Cohere-AI",
"version" : "1.0",
"type" : "fetcher"
}
},
{
"desc" : "DuckAssistBot",
"ua" : "DuckAssistBot/1.2; (+http://duckduckgo.com/duckassistbot.html)",
@ -59,6 +129,16 @@
"type" : "fetcher"
}
},
{
"desc" : "Gemini-Deep-Research",
"ua" : "Mozilla/5.0 AppleWebKit/537.36 (KHTML, like Gecko; compatible; Gemini-Deep-Research; +https://gemini.google/overview/deep-research/) Chrome/135.0.0.0 Safari/537.36",
"expect" :
{
"name" : "Gemini-Deep-Research",
"version" : "undefined",
"type" : "fetcher"
}
},
{
"desc" : "Google FeedFetcher",
"ua" : "FeedFetcher-Google; (+http://www.google.com/feedfetcher.html)",
@ -129,6 +209,16 @@
"type" : "fetcher"
}
},
{
"desc" : "HubSpot Page Fetcher",
"ua" : "HubSpot Page Fetcher/1.0 http://www.hubspot.com/ web-crawlers@hubspot.com",
"expect" :
{
"name" : "HubSpot Page Fetcher",
"version" : "1.0",
"type" : "fetcher"
}
},
{
"desc" : "Iframely",
"ua" : "Iframely/1.3.1 (+https://iframely.com/docs/about)",
@ -139,6 +229,16 @@
"type" : "fetcher"
}
},
{
"desc" : "kakaotalk-scrap",
"ua" : "facebookexternalhit/1.1; kakaotalk-scrap/1.0; +https://devtalk.kakao.com/t/scrap/33984",
"expect" :
{
"name" : "kakaotalk-scrap",
"version" : "1.0",
"type" : "fetcher"
}
},
{
"desc" : "Meta-ExternalFetcher",
"ua" : "meta-externalfetcher/1.1 (+https://developers.facebook.com/docs/sharing/webmasters/crawler)",
@ -249,6 +349,26 @@
"type" : "fetcher"
}
},
{
"desc" : "vercel-favicon-bot",
"ua" : "vercel-favicon-bot",
"expect" :
{
"name" : "vercel-favicon-bot",
"version" : "undefined",
"type" : "fetcher"
}
},
{
"desc" : "vercel-screenshot-bot",
"ua" : "vercel-screenshot-bot",
"expect" :
{
"name" : "vercel-screenshot-bot",
"version" : "undefined",
"type" : "fetcher"
}
},
{
"desc" : "Vercelbot",
"ua" : "Vercelbot (+https://vercel.com)",
@ -259,6 +379,26 @@
"type" : "fetcher"
}
},
{
"desc" : "vercelflags",
"ua" : "vercelflags",
"expect" :
{
"name" : "vercelflags",
"version" : "undefined",
"type" : "fetcher"
}
},
{
"desc" : "verceltracing",
"ua" : "verceltracing",
"expect" :
{
"name" : "verceltracing",
"version" : "undefined",
"type" : "fetcher"
}
},
{
"desc" : "WhatsApp",
"ua" : "WhatsApp/2.23.20.0",
@ -268,5 +408,105 @@
"version" : "2.23.20.0",
"type" : "fetcher"
}
},
{
"desc" : "YaDirectFetcher",
"ua" : "Mozilla/5.0 (compatible; YaDirectFetcher/1.0; Dyatel; +http://yandex.com/bots)",
"expect" :
{
"name" : "YaDirectFetcher",
"version" : "1.0",
"type" : "fetcher"
}
},
{
"desc" : "YandexCalendar",
"ua" : "Mozilla/5.0 (compatible; YandexCalendar/1.0; +http://yandex.com/bots)",
"expect" :
{
"name" : "YandexCalendar",
"version" : "1.0",
"type" : "fetcher"
}
},
{
"desc" : "YandexDirect",
"ua" : "Mozilla/5.0 (compatible; YandexDirect/3.0; +http://yandex.com/bots)",
"expect" :
{
"name" : "YandexDirect",
"version" : "3.0",
"type" : "fetcher"
}
},
{
"desc" : "YandexDirectDyn",
"ua" : "Mozilla/5.0 (compatible; YandexDirectDyn/1.0; +http://yandex.com/bots",
"expect" :
{
"name" : "YandexDirectDyn",
"version" : "1.0",
"type" : "fetcher"
}
},
{
"desc" : "YandexForDomain",
"ua" : "Mozilla/5.0 (compatible; YandexForDomain/1.0; +http://yandex.com/bots)",
"expect" :
{
"name" : "YandexForDomain",
"version" : "1.0",
"type" : "fetcher"
}
},
{
"desc" : "YandexPagechecker",
"ua" : "Mozilla/5.0 (compatible; YandexPagechecker/1.0; +http://yandex.com/bots)",
"expect" :
{
"name" : "YandexPagechecker",
"version" : "1.0",
"type" : "fetcher"
}
},
{
"desc" : "YandexSearchShop",
"ua" : "Mozilla/5.0 (compatible; YandexSearchShop/1.0; +http://yandex.com/bots)",
"expect" :
{
"name" : "YandexSearchShop",
"version" : "1.0",
"type" : "fetcher"
}
},
{
"desc" : "YandexSitelinks",
"ua" : "Mozilla/5.0 (compatible; YandexSitelinks; Dyatel; +http://yandex.com/bots)",
"expect" :
{
"name" : "YandexSitelinks",
"version" : "undefined",
"type" : "fetcher"
}
},
{
"desc" : "YandexUserproxy",
"ua" : "Mozilla/5.0 (compatible; YandexUserproxy; robot; +http://yandex.com/bots)",
"expect" :
{
"name" : "YandexUserproxy",
"version" : "undefined",
"type" : "fetcher"
}
},
{
"desc" : "Zoombot",
"ua" : "Mozilla/5.0 (compatible; Zoombot/1.0; +https://zoom.us; crawler@domain.com)",
"expect" :
{
"name" : "Zoombot",
"version" : "1.0",
"type" : "fetcher"
}
}
]

View File

@ -1,5 +1,5 @@
import { UAParser } from '../../src/main/ua-parser.mjs';
import { CPU, Device, Engine } from '../../src/enums/ua-parser-enums.mjs';
import { CPUArch, DeviceType, EngineName } from '../../src/enums/ua-parser-enums.mjs';
import * as assert from 'assert';
describe('Returns', () => {
@ -19,8 +19,8 @@ describe('Returns', () => {
describe('Enums', () => {
it('Can use enum', () => {
const { cpu, device, engine } = UAParser('Mozilla/5.0 (X11; U; Linux armv7l; en-GB; rv:1.9.2a1pre) Gecko/20090928 Firefox/3.5 Maemo Browser 1.4.1.22 RX-51 N900');
assert.strictEqual(cpu.is(CPU.ARM), true);
assert.strictEqual(device.is(Device.MOBILE), true);
assert.strictEqual(engine.is(Engine.GECKO), true);
assert.strictEqual(cpu.is(CPUArch.ARM), true);
assert.strictEqual(device.is(DeviceType.MOBILE), true);
assert.strictEqual(engine.is(EngineName.GECKO), true);
});
});

View File

@ -5,6 +5,8 @@ const traverse = require('@babel/traverse').default;
const safe = require('safe-regex');
const { UAParser } = require('../../src/main/ua-parser');
const { Bots, CLIs, Crawlers, Emails, Fetchers, InApps, Libraries, Vehicles } = require('../../src/extensions/ua-parser-extensions');
const { BrowserType, OSName, Extension } = require('../../src/enums/ua-parser-enums');
const { CLI, Crawler, Email, Fetcher, Library } = Extension.BrowserName;
describe('Extensions', () => {
[
@ -42,29 +44,29 @@ describe('Extensions', () => {
const jsdom = 'Mozilla/5.0 (darwin) AppleWebKit/537.36 (KHTML, like Gecko) jsdom/20.0.3';
const scrapy = 'Scrapy/1.5.0 (+https://scrapy.org)';
assert.equal(UAParser(scrapy, Bots).browser.name, 'Scrapy');
assert.equal(UAParser(scrapy, Bots).browser.name, Library.SCRAPY);
const emailParser = new UAParser(Emails);
assert.deepEqual(emailParser.setUA(outlook).getBrowser(), {name: "Microsoft Outlook", version: "16.0.9126", major: "16", type: "email"});
assert.deepEqual(emailParser.setUA(thunderbird).getBrowser(), {name: "Thunderbird", version: "78.13.0", major: "78", type: "email"});
assert.deepEqual(emailParser.setUA(outlook).getBrowser(), {name: Email.MICROSOFT_OUTLOOK, version: "16.0.9126", major: "16", type: BrowserType.EMAIL});
assert.deepEqual(emailParser.setUA(thunderbird).getBrowser(), {name: Email.THUNDERBIRD, version: "78.13.0", major: "78", type: BrowserType.EMAIL});
const libraryParser = new UAParser(Libraries);
assert.deepEqual(libraryParser.setUA(axios).getBrowser(), {name: "axios", version: "1.3.5", major: "1", type: "library"});
assert.deepEqual(libraryParser.setUA(jsdom).getBrowser(), {name: "jsdom", version: "20.0.3", major: "20", type: "library"});
assert.deepEqual(libraryParser.setUA(scrapy).getBrowser(), {name: "Scrapy", version: "1.5.0", major: "1", type: "library"});
assert.deepEqual(libraryParser.setUA(axios).getBrowser(), {name: Library.AXIOS, version: "1.3.5", major: "1", type: BrowserType.LIBRARY});
assert.deepEqual(libraryParser.setUA(jsdom).getBrowser(), {name: Library.JSDOM, version: "20.0.3", major: "20", type: BrowserType.LIBRARY});
assert.deepEqual(libraryParser.setUA(scrapy).getBrowser(), {name: Library.SCRAPY, version: "1.5.0", major: "1", type: BrowserType.LIBRARY});
// Bluesky
const bluesky = 'Mozilla/5.0 (compatible; Bluesky Cardyb/1.1; +mailto:support@bsky.app)';
assert.deepEqual(new UAParser(bluesky, Bots).getBrowser(), {
name: 'Bluesky',
name: Fetcher.BLUESKY,
version: '1.1',
major: '1',
type: 'fetcher'
type: BrowserType.FETCHER
});
const whatsapp = "WhatsApp/2.0 A";
assert.deepEqual(new UAParser(whatsapp, Fetchers).getOS(), {
name : 'Android',
name : OSName.ANDROID,
version : undefined
});
});
@ -77,14 +79,14 @@ describe('Merge', () => {
// try merging crawlers & CLIs
const crawlersAndCLIs = { browser : [...Crawlers.browser, ...CLIs.browser]};
const crawlersAndCLIsParser = new UAParser(crawlersAndCLIs);
assert.deepEqual(crawlersAndCLIsParser.setUA(wget).getBrowser(), {name: "Wget", version: "1.21.1", major: "1", type:"cli"});
assert.deepEqual(crawlersAndCLIsParser.setUA(facebookBot).getBrowser(), {name: "FacebookBot", version: "1.0", major: "1", type:"crawler"});
assert.deepEqual(crawlersAndCLIsParser.setUA(wget).getBrowser(), {name: CLI.WGET, version: "1.21.1", major: "1", type: BrowserType.CLI});
assert.deepEqual(crawlersAndCLIsParser.setUA(facebookBot).getBrowser(), {name: Crawler.META_FACEBOOKBOT, version: "1.0", major: "1", type: BrowserType.CRAWLER});
// alternative merge options
const crawlersAndCLIsParser2 = new UAParser([Crawlers, CLIs]);
const crawlersAndCLIsParser3 = new UAParser(facebookBot, [Crawlers, CLIs]);
assert.deepEqual(crawlersAndCLIsParser2.setUA(wget).getBrowser(), {name: "Wget", version: "1.21.1", major: "1", type:"cli"});
assert.deepEqual(crawlersAndCLIsParser3.getBrowser(), {name: "FacebookBot", version: "1.0", major: "1", type:"crawler"});
assert.deepEqual(crawlersAndCLIsParser2.setUA(wget).getBrowser(), {name: CLI.WGET, version: "1.21.1", major: "1", type: BrowserType.CLI});
assert.deepEqual(crawlersAndCLIsParser3.getBrowser(), {name: Crawler.META_FACEBOOKBOT, version: "1.0", major: "1", type: BrowserType.CRAWLER});
});
});

View File

@ -2,6 +2,7 @@ const assert = require('assert');
const { UAParser } = require('../../src/main/ua-parser');
const { getDeviceVendor, isAppleSilicon, isAIBot, isBot, isChromeFamily } = require('../../src/helpers/ua-parser-helpers');
const { Bots, Emails } = require('../../src/extensions/ua-parser-extensions');
const { DeviceVendor } = require('../../src/enums/ua-parser-enums');
describe('getDeviceVendor', () => {
it('Can guess the device vendor from a model name', () => {
@ -11,10 +12,10 @@ describe('getDeviceVendor', () => {
const modelNexus = 'Nexus 6P';
const modelAquos = 'AQUOS-TVX19B';
assert.equal(getDeviceVendor(modelSM), 'Samsung');
assert.equal(getDeviceVendor(modelRedmi), 'Xiaomi');
assert.equal(getDeviceVendor(modelNexus), 'Huawei');
assert.equal(getDeviceVendor(modelAquos), 'Sharp');
assert.equal(getDeviceVendor(modelSM), DeviceVendor.SAMSUNG);
assert.equal(getDeviceVendor(modelRedmi), DeviceVendor.XIAOMI);
assert.equal(getDeviceVendor(modelNexus), DeviceVendor.HUAWEI);
assert.equal(getDeviceVendor(modelAquos), DeviceVendor.SHARP);
});
});

View File

@ -10,7 +10,7 @@ var cpus = require('../data/ua/cpu/cpu-all.json');
var devices = readJsonFiles('test/data/ua/device');
var engines = require('../data/ua/engine/engine-all.json');
var os = readJsonFiles('test/data/ua/os');
var { Headers } = require('node-fetch');
var { Headers } = require('undici');
function readJsonFiles(dir) {
var list = [];
@ -91,6 +91,34 @@ describe('Returns', function () {
});
done();
});
it('works even when Array.prototype has been mangled', function(done) {
const result = withMangledArrayProto(() => new UAParser('').getResult());
function withMangledArrayProto(fn, key = 'isEmpty', value = function() { return this.length === 0; }) {
const originalValue = Array.prototype[key];
const restore = Object.hasOwnProperty.call(Array.prototype, key)
? () => Array.prototype[key] = originalValue
: () => delete Array.prototype[key];
Array.prototype[key] = value;
const result = fn();
restore();
return result;
}
assert.deepEqual(result,
{
ua : '',
browser: { name: undefined, version: undefined, major: undefined, type: undefined },
cpu: { architecture: undefined },
device: { vendor: undefined, model: undefined, type: undefined },
engine: { name: undefined, version: undefined},
os: { name: undefined, version: undefined }
});
done();
});
});
describe('Extending Regex', function () {
@ -353,4 +381,18 @@ describe('Read user-agent data from req.headers', function () {
const { browser } = UAParser(reqHeaders);
assert.strictEqual(browser.is('Midori'), true);
});
it('Headers field name should be case insensitive', function () {
const hEaDeRs = {
'uSeR-aGenT' : 'Midori/0.2.2 (X11; Linux i686; U; en-us) WebKit/531.2+'
};
const { browser } = UAParser(hEaDeRs);
assert.strictEqual(browser.toString(), "Midori 0.2.2");
});
it('Empty headers should not raise any error', function () {
const emptyHeaders = {};
const { browser } = UAParser(emptyHeaders);
assert.strictEqual(browser.toString(), "undefined");
});
});

View File

@ -1,5 +1,7 @@
const assert = require('assert');
const { UAParser } = require('../../src/main/ua-parser');
const { BrowserName, CPUArch, DeviceType, DeviceVendor, EngineName, OSName } = require('../../src/enums/ua-parser-enums');
const UACHTests = require('../data/ua-ch/headers');
describe('Map UA-CH headers', () => {
@ -25,27 +27,27 @@ describe('Map UA-CH headers', () => {
it('Can read from client-hints headers using `withClientHints()`', () => {
assert.strictEqual(uap.ua, "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/110.0.0.0 Safari/537.36");
assert.strictEqual(uap.browser.name, "Chrome");
assert.strictEqual(uap.browser.name, BrowserName.CHROME);
assert.strictEqual(uap.browser.version, "93.0.1.2");
assert.strictEqual(uap.browser.major, "93");
assert.strictEqual(browser.name, "Chrome");
assert.strictEqual(browser.name, BrowserName.CHROME);
assert.strictEqual(browser.version, "93.0.1.2");
assert.strictEqual(browser.major, "93");
assert.strictEqual(uap.cpu.architecture, "arm64");
assert.strictEqual(cpu.architecture, "arm64");
assert.strictEqual(uap.device.type, "mobile");
assert.strictEqual(uap.cpu.architecture, CPUArch.ARM_64);
assert.strictEqual(cpu.architecture, CPUArch.ARM_64);
assert.strictEqual(uap.device.type, DeviceType.MOBILE);
assert.strictEqual(uap.device.model, "Pixel 99");
assert.strictEqual(uap.device.vendor, "Google");
assert.strictEqual(device.type, "mobile");
assert.strictEqual(uap.device.vendor, DeviceVendor.GOOGLE);
assert.strictEqual(device.type, DeviceType.MOBILE);
assert.strictEqual(device.model, "Pixel 99");
assert.strictEqual(device.vendor, "Google");
assert.strictEqual(uap.engine.name, 'Blink');
assert.strictEqual(device.vendor, DeviceVendor.GOOGLE);
assert.strictEqual(uap.engine.name, EngineName.BLINK);
assert.strictEqual(uap.engine.version, '93.0.1.2');
assert.strictEqual(engine.name, 'Blink');
assert.strictEqual(engine.name, EngineName.BLINK);
assert.strictEqual(engine.version, '93.0.1.2');
assert.strictEqual(uap.os.name, "Windows");
assert.strictEqual(uap.os.name, OSName.WINDOWS);
assert.strictEqual(uap.os.version, "11");
assert.strictEqual(os.name, "Windows");
assert.strictEqual(os.name, OSName.WINDOWS);
assert.strictEqual(os.version, "11");
});
@ -58,16 +60,16 @@ describe('Map UA-CH headers', () => {
engine = new UAParser(headers).getEngine();
os = new UAParser(headers).getOS();
assert.strictEqual(uap.browser.name, "Chrome");
assert.strictEqual(uap.browser.name, BrowserName.CHROME);
assert.strictEqual(uap.browser.version, "110.0.0.0");
assert.strictEqual(uap.browser.major, "110");
assert.strictEqual(uap.cpu.architecture, "amd64");
assert.strictEqual(uap.cpu.architecture, CPUArch.X86_64);
assert.strictEqual(uap.device.type, undefined);
assert.strictEqual(uap.device.model, undefined);
assert.strictEqual(uap.device.vendor, undefined);
assert.strictEqual(uap.engine.name, 'Blink');
assert.strictEqual(uap.engine.name, EngineName.BLINK);
assert.strictEqual(uap.engine.version, '110.0.0.0');
assert.strictEqual(uap.os.name, "Linux");
assert.strictEqual(uap.os.name, OSName.LINUX);
assert.strictEqual(uap.os.version, undefined);
});
@ -80,16 +82,16 @@ describe('Map UA-CH headers', () => {
uap = UAParser(headers2).withClientHints();
assert.strictEqual(uap.browser.name, "Chrome");
assert.strictEqual(uap.browser.name, BrowserName.CHROME);
assert.strictEqual(uap.browser.version, "110.0.0.0");
assert.strictEqual(uap.browser.major, "110");
assert.strictEqual(uap.cpu.architecture, "amd64");
assert.strictEqual(uap.device.type, "mobile");
assert.strictEqual(uap.cpu.architecture, CPUArch.X86_64);
assert.strictEqual(uap.device.type, DeviceType.MOBILE);
assert.strictEqual(uap.device.model, undefined);
assert.strictEqual(uap.device.vendor, undefined);
assert.strictEqual(uap.engine.name, 'Blink');
assert.strictEqual(uap.engine.name, EngineName.BLINK);
assert.strictEqual(uap.engine.version, '110.0.0.0');
assert.strictEqual(uap.os.name, "Linux");
assert.strictEqual(uap.os.name, OSName.LINUX);
assert.strictEqual(uap.os.version, undefined);
});
@ -116,10 +118,10 @@ describe('Map UA-CH headers', () => {
}
*/
assert.strictEqual(ua.os.is("macOS"), true);
assert.strictEqual(ua.cpu.is("arm"), true);
assert.strictEqual(ua.device.is("mobile"), false);
assert.strictEqual(ua.device.is("tablet"), false);
assert.strictEqual(ua.os.is(OSName.MACOS), true);
assert.strictEqual(ua.cpu.is(CPUArch.ARM), true);
assert.strictEqual(ua.device.is(DeviceType.MOBILE), false);
assert.strictEqual(ua.device.is(DeviceType.TABLET), false);
});
});
@ -138,11 +140,11 @@ describe('Map UA-CH headers', () => {
};
UAParser(FFVR).withClientHints().then(ua => {
assert.strictEqual(ua.device.type, 'xr');
assert.strictEqual(ua.device.type, DeviceType.XR);
});
UAParser(FFEInk).withClientHints().then(ua => {
assert.strictEqual(ua.device.type, 'tablet');
assert.strictEqual(ua.device.type, DeviceType.TABLET);
});
@ -168,7 +170,7 @@ describe('Map UA-CH headers', () => {
uap = UAParser(headers2).withClientHints();
assert.strictEqual(uap.browser.name, "Chrome");
assert.strictEqual(uap.browser.name, BrowserName.CHROME);
assert.strictEqual(uap.browser.version, undefined);
assert.strictEqual(uap.browser.major, undefined);
});
@ -195,259 +197,38 @@ describe('Map UA-CH headers', () => {
};
uap = UAParser(headers3a).withClientHints();
assert.strictEqual(uap.browser.name, "Chrome");
assert.strictEqual(uap.browser.name, BrowserName.CHROME);
assert.strictEqual(uap.browser.version, "120.0.6099.132");
uap = UAParser(headers3b).withClientHints();
assert.strictEqual(uap.browser.name, "Chrome");
assert.strictEqual(uap.browser.name, BrowserName.CHROME);
assert.strictEqual(uap.browser.version, "120.0.6099.132");
uap = UAParser(headers3c).withClientHints();
assert.strictEqual(uap.browser.name, "Chrome");
assert.strictEqual(uap.browser.name, BrowserName.CHROME);
assert.strictEqual(uap.browser.version, "120.0.6099.132");
uap = UAParser(headers3d).withClientHints();
assert.strictEqual(uap.browser.name, "Edge");
assert.strictEqual(uap.browser.name, BrowserName.EDGE);
assert.strictEqual(uap.browser.version, "120.0.6099.133");
uap = UAParser(headers3e).withClientHints();
assert.strictEqual(uap.browser.name, "Edge");
assert.strictEqual(uap.browser.name, BrowserName.EDGE);
assert.strictEqual(uap.browser.version, "120.0.6099.133");
uap = UAParser(headers3f).withClientHints();
assert.strictEqual(uap.browser.name, "Edge");
assert.strictEqual(uap.browser.name, BrowserName.EDGE);
assert.strictEqual(uap.browser.version, "120.0.6099.133");
});
});
describe('UA-CH Headers tests', () => {
[
{
headers : {
'sec-ch-ua': '"Avast Secure Browser";v="131", "Chromium";v="131", "Not_A Brand";v="24"'
},
expect: {
browser : {
name : 'Avast Secure Browser',
version : '131',
major : '131',
type : undefined
}
}
},
{
headers : {
'sec-ch-ua': '"Not A(Brand";v="8", "Chromium";v="132", "Brave";v="132"'
},
expect: {
browser : {
name : 'Brave',
version : '132',
major : '132',
type : undefined
}
}
},
{
headers : {
'sec-ch-ua': '"Google Chrome";v="111", "Not(A:Brand";v="8", "Chromium";v="111"'
},
expect: {
browser : {
name : 'Chrome',
version : '111',
major : '111',
type : undefined
}
}
},
{
headers : {
'sec-ch-ua': '"Chromium";v="124", "HeadlessChrome";v="124", "Not-A.Brand";v="99"'
},
expect: {
browser : {
name : 'Chrome Headless',
version : '124',
major : '124',
type : undefined
}
}
},
{
headers : {
'sec-ch-ua': '"Android WebView";v="123", "Not:A-Brand";v="8", "Chromium";v="123"'
},
expect: {
browser : {
name : 'Chrome WebView',
version : '123',
major : '123',
type : undefined
}
}
},
{
headers : {
'sec-ch-ua': '"DuckDuckGo";v="131", "Chromium";v="131", "Not_A Brand";v="24"'
},
expect : {
browser : {
name : 'DuckDuckGo',
version : '131',
major : '131',
type : undefined
}
}
},
{
headers : {
'sec-ch-ua': '"Not_A Brand";v="8", "Chromium";v="120", "Microsoft Edge";v="120"'
},
expect: {
browser : {
name : 'Edge',
version : '120',
major : '120',
type : undefined
}
}
},
{
headers : {
'sec-ch-ua': '" Not;A Brand";v="99", "Microsoft Edge";v="103", "Chromium";v="103", "Microsoft Edge WebView2";v="104"'
},
expect: {
browser : {
name : 'Edge WebView2',
version : '104',
major : '104',
type : undefined
}
}
},
{
headers : {
'sec-ch-ua': '"Not.A/Brand";v="8", "Chromium";v="114", "HuaweiBrowser";v="114"'
},
expect: {
browser : {
name : 'Huawei Browser',
version : '114',
major : '114',
type : undefined
}
}
},
{
headers : {
'sec-ch-ua': '"Miui Browser";v="123", "Not:A-Brand";v="8", "Chromium";v="123"'
},
expect: {
browser : {
name : 'MIUI Browser',
version : '123',
major : '123',
type : undefined
}
}
},
{
headers : {
'sec-ch-ua': '"Chromium";v="130", "Oculus Browser";v="36", "Not?A_Brand";v="99"'
},
expect: {
browser : {
name : 'Oculus Browser',
version : '36',
major : '36',
type : undefined
}
}
},
{
headers : {
'sec-ch-ua': '"Opera";v="116", "Chromium";v="131", "Not_A Brand";v="24"'
},
expect: {
browser : {
name : 'Opera',
version : '116',
major : '116',
type : undefined
}
}
},
{
headers : {
'sec-ch-ua': '"Chromium";v="128", "Not;A=Brand";v="24", "Opera GX";v="114"'
},
expect: {
browser : {
name : 'Opera GX',
version : '114',
major : '114',
type : undefined
}
}
},
{
headers : {
'sec-ch-ua': '"OperaMobile";v="86", ";Not A Brand";v="99", "Opera";v="115", "Chromium";v="130"'
},
expect: {
browser : {
name : 'Opera Mobi',
version : '86',
major : '86',
type : undefined
}
}
},
{
headers : {
'sec-ch-ua': '"Chromium";v="132", "OperaMobile";v="87", "Opera";v="117", " Not A;Brand";v="99"'
},
expect: {
browser : {
name : 'Opera Mobi',
version : '87',
major : '87',
type : undefined
}
}
},
{
headers : {
'sec-ch-ua': '"Chromium";v="125", "Not.A/Brand";v="24", "Samsung Internet";v="27.0"'
},
expect: {
browser : {
name : 'Samsung Internet',
version : '27.0',
major : '27',
type : undefined
}
}
},
{
headers : {
'sec-ch-ua': '"Chromium";v="130", "YaBrowser";v="24.12", "Not?A_Brand";v="99", "Yowser";v="2.5"'
},
expect: {
browser : {
name : 'Yandex',
version : '24.12',
major : '24',
type : undefined
}
}
},
]
.forEach(test => {
UACHTests.forEach(test => {
it(`Test for ${test.desc}`, () => {
const { browser } = UAParser(test.headers).withClientHints();
assert.deepEqual(browser, test.expect.browser);
});
});
});
describe('Identify vendor & type of device from given model name', () => {
@ -455,169 +236,169 @@ describe('Identify vendor & type of device from given model name', () => {
{
model: '220733SG',
expect: {
vendor : 'Xiaomi',
type : 'mobile'
vendor : DeviceVendor.XIAOMI,
type : DeviceType.MOBILE
}
},
{
model: '5087Z',
expect: {
vendor : 'TCL',
type : 'mobile'
vendor : DeviceVendor.TCL,
type : DeviceType.MOBILE
}
},
{
model: '9137W',
expect: {
vendor : 'TCL',
type : 'tablet'
vendor : DeviceVendor.TCL,
type : DeviceType.TABLET
}
},
{
model: 'BE2015',
expect: {
vendor : 'OnePlus',
type : 'mobile'
vendor : DeviceVendor.ONEPLUS,
type : DeviceType.MOBILE
}
},
{
model: 'CPH2389',
expect: {
vendor : 'OnePlus',
type : 'mobile'
vendor : DeviceVendor.ONEPLUS,
type : DeviceType.MOBILE
}
},
{
model: 'Infinix X669C',
expect: {
vendor : 'Infinix',
type : 'mobile'
vendor : DeviceVendor.INFINIX,
type : DeviceType.MOBILE
}
},
{
model: 'itel L6502',
expect: {
vendor : 'itel',
type : 'mobile'
vendor : DeviceVendor.ITEL,
type : DeviceType.MOBILE
}
},
{
model: 'Lenovo TB-X606F',
expect: {
vendor : 'Lenovo',
type : 'tablet'
vendor : DeviceVendor.LENOVO,
type : DeviceType.TABLET
}
},
{
model: 'LM-Q720',
expect: {
vendor : 'LG',
type : 'mobile'
vendor : DeviceVendor.LG,
type : DeviceType.MOBILE
}
},
{
model: 'M2003J15SC',
expect: {
vendor : 'Xiaomi',
type : 'mobile'
vendor : DeviceVendor.XIAOMI,
type : DeviceType.MOBILE
}
},
{
model: 'MAR-LX1A',
expect: {
vendor : 'Huawei',
type : 'mobile'
vendor : DeviceVendor.HUAWEI,
type : DeviceType.MOBILE
}
},
{
model: 'moto g(20)',
expect: {
vendor : 'Motorola',
type : 'mobile'
vendor : DeviceVendor.MOTOROLA,
type : DeviceType.MOBILE
}
},
{
model: 'Nokia C210',
expect: {
vendor : 'Nokia',
type : 'mobile'
vendor : DeviceVendor.NOKIA,
type : DeviceType.MOBILE
}
},
{
model: 'Pixel 8',
expect: {
vendor : 'Google',
type : 'mobile'
vendor : DeviceVendor.GOOGLE,
type : DeviceType.MOBILE
}
},
{
model: 'Redmi Note 9S',
expect: {
vendor : 'Xiaomi',
type : 'mobile'
vendor : DeviceVendor.XIAOMI,
type : DeviceType.MOBILE
}
},
{
model: 'RMX3830',
expect: {
vendor : 'Realme',
type : 'mobile'
vendor : DeviceVendor.REALME,
type : DeviceType.MOBILE
}
},
{
model: 'SM-S536DL',
expect: {
vendor : 'Samsung',
type : 'mobile'
vendor : DeviceVendor.SAMSUNG,
type : DeviceType.MOBILE
}
},
{
model: 'SM-S546VL',
expect: {
vendor : 'Samsung',
type : 'mobile'
vendor : DeviceVendor.SAMSUNG,
type : DeviceType.MOBILE
}
},
{
model: 'SM-T875',
expect: {
vendor : 'Samsung',
type : 'tablet'
vendor : DeviceVendor.SAMSUNG,
type : DeviceType.TABLET
}
},
{
model: 'STK-L21',
expect: {
vendor : 'Huawei',
type : 'mobile'
vendor : DeviceVendor.HUAWEI,
type : DeviceType.MOBILE
}
},
{
model: 'T430W',
expect: {
vendor : 'TCL',
type : 'mobile'
vendor : DeviceVendor.TCL,
type : DeviceType.MOBILE
}
},
{
model: 'TECNO KI5k',
expect: {
vendor : 'TECNO',
type : 'mobile'
vendor : DeviceVendor.TECNO,
type : DeviceType.MOBILE
}
},
{
model: 'vivo 1820',
expect: {
vendor : 'Vivo',
type : 'mobile'
vendor : DeviceVendor.VIVO,
type : DeviceType.MOBILE
}
},
{
model: 'Xbox',
expect: {
vendor : 'Microsoft',
type : 'console'
vendor : DeviceVendor.MICROSOFT,
type : DeviceType.CONSOLE
}
}
]