Compare commits

...

30 Commits

Author SHA1 Message Date
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 3372 additions and 1142 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 ## Version 2.0.4
- Add new browser: Edge WebView, Edge WebView2 - 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 ## Version 0.7.40 / 1.0.40
- Add new browser: 115, LibreWolf, Slimboat, Slimjet - Add new browser: 115, LibreWolf, Slimboat, Slimjet
- Add new device: Advan, Cat, Energizer, IMO, Micromax, Smartfren - Add new device: Advan, Cat, Energizer, IMO, Micromax, Smartfren

View File

@ -12,13 +12,12 @@
<a href="https://www.npmjs.com/package/ua-parser-js"><img src="https://img.shields.io/npm/v/ua-parser-js.svg?logo=npm&color=red&style=for-the-badge"></a> <a href="https://www.npmjs.com/package/ua-parser-js"><img src="https://img.shields.io/npm/v/ua-parser-js.svg?logo=npm&color=red&style=for-the-badge"></a>
<a href="https://cdnjs.com/libraries/UAParser.js"><img src="https://img.shields.io/cdnjs/v/UAParser.js.svg?color=orange&style=for-the-badge"></a> <a href="https://cdnjs.com/libraries/UAParser.js"><img src="https://img.shields.io/cdnjs/v/UAParser.js.svg?color=orange&style=for-the-badge"></a>
<img src="https://img.shields.io/ossf-scorecard/github.com/faisalman/ua-parser-js?label=openssf%20scorecard&style=for-the-badge"> <img src="https://img.shields.io/ossf-scorecard/github.com/faisalman/ua-parser-js?label=openssf%20scorecard&style=for-the-badge">
<a target="_blank" href="https://discord.gg/stt86vmr"><img alt="Discord invite" src="https://dcbadge.limes.pink/api/server/https://discord.gg/stt86vmr"></a>
</p> </p>
# UAParser.js # UAParser.js
The most comprehensive, compact, & up-to-date isomorphic JavaScript library to detect The most comprehensive, compact, and up-to-date JavaScript library to detect user's browser, OS, CPU, and device type/model. Also detect bots, apps, and more. Runs seamlessly in the browser (client-side) or Node.js (server-side).
user's Browser, Engine, OS, CPU, and Device type/model. Runs either in browser
(client-side) or node.js (server-side).
# Demo # Demo
@ -33,7 +32,7 @@ user's Browser, Engine, OS, CPU, and Device type/model. Runs either in browser
Before upgrading from `v0.7` / `v1.0`, please read [CHANGELOG](CHANGELOG.md) to Before upgrading from `v0.7` / `v1.0`, please read [CHANGELOG](CHANGELOG.md) to
see what's new & breaking. see what's new & breaking.
# License Options # Package & Pricing
<table> <table>
<thead> <thead>
@ -46,8 +45,8 @@ see what's new & breaking.
<tbody> <tbody>
<tr> <tr>
<td>License options</td> <td>License options</td>
<td>MIT (v0.7~v1.0)</td> <td>MIT (v1.x)</td>
<td>AGPL (&gt;=v2.0)</td> <td>AGPL (v2.x)</td>
<td>PRO Personal</td> <td>PRO Personal</td>
<td>PRO Business</td> <td>PRO Business</td>
<td>PRO Enterprise</td> <td>PRO Enterprise</td>
@ -148,14 +147,6 @@ see what's new & breaking.
<td></td> <td></td>
<td></td> <td></td>
</tr> </tr>
<tr>
<td>npm module</td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr> <tr>
<td>TypeScript declarations</td> <td>TypeScript declarations</td>
<td><a href="#demo" title="Community version">⚠️</a></td> <td><a href="#demo" title="Community version">⚠️</a></td>
@ -165,7 +156,23 @@ see what's new & breaking.
<td></td> <td></td>
</tr> </tr>
<tr> <tr>
<td>Allows commercial use</td> <td>npm module available</td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td>Direct downloads available</td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td>Allows commercial usage</td>
<td></td> <td></td>
<td></td> <td></td>
<td></td> <td></td>
@ -181,11 +188,27 @@ see what's new & breaking.
<td></td> <td></td>
</tr> </tr>
<tr> <tr>
<td>Unlimited use per 1 license</td> <td>No open-source obligations</td>
<td></td>
<td><strong title="Copyleft license"></strong></td>
<td></td> <td></td>
<td></td> <td></td>
<td></td> <td></td>
<td><strong title="1 project per 1 license"></strong></td> </tr>
<tr>
<td>Unlimited end-products</td>
<td></td>
<td></td>
<td></td>
<td><strong title="1 end-product per license"></strong></td>
<td></td>
</tr>
<tr>
<td>Unlimited deployments</td>
<td></td>
<td></td>
<td></td>
<td><strong title="1 TLD or deliverable per license"></strong></td>
<td></td> <td></td>
</tr> </tr>
<tr> <tr>
@ -206,8 +229,8 @@ see what's new & breaking.
</tr> </tr>
<tr> <tr>
<td>Price</td> <td>Price</td>
<td><strong title="Pay as you want">FREE (<a target="_blank" href="https://raw.githubusercontent.com/faisalman/ua-parser-js/1.0.x/license.md">License</a>)</strong></td> <td><strong title="Pay as you want">FREE<sup>*</sup> (<a target="_blank" href="https://raw.githubusercontent.com/faisalman/ua-parser-js/1.0.x/license.md">License</a>)</strong></td>
<td><strong title="Pay as you want">FREE (<a target="_blank" href="https://raw.githubusercontent.com/faisalman/ua-parser-js/master/LICENSE.md">License</a>)</strong></td> <td><strong title="Pay as you want">FREE<sup>*</sup> (<a target="_blank" href="https://raw.githubusercontent.com/faisalman/ua-parser-js/master/LICENSE.md">License</a>)</strong></td>
<td><strong title="$14 (one-time fee)">$14 (<a target="_blank" href="https://raw.githubusercontent.com/faisalman/ua-parser-js/pro-personal/LICENSE.md">License</a>)</strong></td> <td><strong title="$14 (one-time fee)">$14 (<a target="_blank" href="https://raw.githubusercontent.com/faisalman/ua-parser-js/pro-personal/LICENSE.md">License</a>)</strong></td>
<td><strong title="$29 (one-time fee)">$29 (<a target="_blank" href="https://raw.githubusercontent.com/faisalman/ua-parser-js/pro-business/LICENSE.md">License</a>)</strong></td> <td><strong title="$29 (one-time fee)">$29 (<a target="_blank" href="https://raw.githubusercontent.com/faisalman/ua-parser-js/pro-business/LICENSE.md">License</a>)</strong></td>
<td><strong title="$599 (one-time fee)">$599 (<a target="_blank" href="https://raw.githubusercontent.com/faisalman/ua-parser-js/pro-enterprise/LICENSE.md">License</a>)</strong></td> <td><strong title="$599 (one-time fee)">$599 (<a target="_blank" href="https://raw.githubusercontent.com/faisalman/ua-parser-js/pro-enterprise/LICENSE.md">License</a>)</strong></td>
@ -236,10 +259,7 @@ Made with [contributors-img](https://contrib.rocks).
## Backers & Sponsors ## Backers & Sponsors
<a href="https://opencollective.com/ua-parser-js"><img src="https://opencollective.com/ua-parser-js/organizations.svg?avatarHeight=64"></a> Support the **open-source editions** of UAParser.js through one of the following options:
<a href="https://opencollective.com/ua-parser-js"><img src="https://opencollective.com/ua-parser-js/individuals.svg?avatarHeight=64"></a>
You can support the open-source editions of UAParser.js through one of the following options:
[![OpenCollective](https://img.shields.io/badge/OpenCollective-dddddd?style=for-the-badge&logo=opencollective&color=dddddd [![OpenCollective](https://img.shields.io/badge/OpenCollective-dddddd?style=for-the-badge&logo=opencollective&color=dddddd
)](https://opencollective.com/ua-parser-js) )](https://opencollective.com/ua-parser-js)
@ -249,3 +269,6 @@ You can support the open-source editions of UAParser.js through one of the follo
)](https://paypal.me/faisalman) )](https://paypal.me/faisalman)
[![WeChat/Alipay](https://img.shields.io/badge/Other_Payment_Methods-Alipay_/_WeChat_Pay-09b83e?style=for-the-badge&logo=mastercard&color=09b83e [![WeChat/Alipay](https://img.shields.io/badge/Other_Payment_Methods-Alipay_/_WeChat_Pay-09b83e?style=for-the-badge&logo=mastercard&color=09b83e
)](https://store.faisalman.com/buy/3d71f2f3-cf4d-473c-892a-9d4497c890be) )](https://store.faisalman.com/buy/3d71f2f3-cf4d-473c-892a-9d4497c890be)
<a href="https://opencollective.com/ua-parser-js"><img src="https://opencollective.com/ua-parser-js/organizations.svg?avatarHeight=64"></a>
<a href="https://opencollective.com/ua-parser-js"><img src="https://opencollective.com/ua-parser-js/individuals.svg?avatarHeight=64"></a>

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", "name": "ua-parser-js",
"version": "2.0.4", "version": "2.0.5",
"lockfileVersion": 3, "lockfileVersion": 3,
"requires": true, "requires": true,
"packages": { "packages": {
"": { "": {
"name": "ua-parser-js", "name": "ua-parser-js",
"version": "2.0.4", "version": "2.0.5",
"funding": [ "funding": [
{ {
"type": "opencollective", "type": "opencollective",
@ -23,11 +23,10 @@
], ],
"license": "AGPL-3.0-or-later", "license": "AGPL-3.0-or-later",
"dependencies": { "dependencies": {
"@types/node-fetch": "^2.6.12",
"detect-europe-js": "^0.1.2", "detect-europe-js": "^0.1.2",
"is-standalone-pwa": "^0.1.1", "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": { "bin": {
"ua-parser-js": "script/cli.js" "ua-parser-js": "script/cli.js"
@ -402,23 +401,6 @@
"integrity": "sha512-hov8bUuiLiyFPGyFPE1lwWhmzYbirOXQNNo40+y3zow8aFVTeyn3VWL0VFFfdNddA8S4Vf0Tc062rzyNr7Paag==", "integrity": "sha512-hov8bUuiLiyFPGyFPE1lwWhmzYbirOXQNNo40+y3zow8aFVTeyn3VWL0VFFfdNddA8S4Vf0Tc062rzyNr7Paag==",
"dev": true "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": { "node_modules/@types/normalize-package-data": {
"version": "2.4.4", "version": "2.4.4",
"resolved": "https://registry.npmjs.org/@types/normalize-package-data/-/normalize-package-data-2.4.4.tgz", "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": ">=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": { "node_modules/balanced-match": {
"version": "1.0.2", "version": "1.0.2",
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
@ -664,17 +641,6 @@
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
"dev": true "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": { "node_modules/concat-map": {
"version": "0.0.1", "version": "0.0.1",
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
@ -753,14 +719,6 @@
"node": ">=0.10.0" "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": { "node_modules/detect-europe-js": {
"version": "0.1.2", "version": "0.1.2",
"resolved": "https://registry.npmjs.org/detect-europe-js/-/detect-europe-js-0.1.2.tgz", "resolved": "https://registry.npmjs.org/detect-europe-js/-/detect-europe-js-0.1.2.tgz",
@ -1011,19 +969,6 @@
"flat": "cli.js" "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": { "node_modules/fs.realpath": {
"version": "1.0.0", "version": "1.0.0",
"resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
@ -1591,25 +1536,6 @@
"node": ">=8.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": { "node_modules/min-indent": {
"version": "1.0.1", "version": "1.0.1",
"resolved": "https://registry.npmjs.org/min-indent/-/min-indent-1.0.1.tgz", "resolved": "https://registry.npmjs.org/min-indent/-/min-indent-1.0.1.tgz",
@ -1963,25 +1889,6 @@
"node": "^10 || ^12 || >=13.7" "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": { "node_modules/normalize-package-data": {
"version": "3.0.3", "version": "3.0.3",
"resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-3.0.3.tgz", "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-3.0.3.tgz",
@ -2713,11 +2620,6 @@
"node": ">=8.0" "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": { "node_modules/trim-newlines": {
"version": "3.0.1", "version": "3.0.1",
"resolved": "https://registry.npmjs.org/trim-newlines/-/trim-newlines-3.0.1.tgz", "resolved": "https://registry.npmjs.org/trim-newlines/-/trim-newlines-3.0.1.tgz",
@ -2791,10 +2693,14 @@
"node": ">=0.8.0" "node": ">=0.8.0"
} }
}, },
"node_modules/undici-types": { "node_modules/undici": {
"version": "6.20.0", "version": "7.12.0",
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.20.0.tgz", "resolved": "https://registry.npmjs.org/undici/-/undici-7.12.0.tgz",
"integrity": "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==" "integrity": "sha512-GrKEsc3ughskmGA9jevVlIOPMiiAHJ4OFUtaAH+NhfTUSiZ1wMPIQqQvAJUrJspFXJt3EBWgpAeoHEDVT1IBug==",
"license": "MIT",
"engines": {
"node": ">=20.18.1"
}
}, },
"node_modules/validate-npm-package-license": { "node_modules/validate-npm-package-license": {
"version": "3.0.4", "version": "3.0.4",
@ -2806,20 +2712,6 @@
"spdx-expression-parse": "^3.0.0" "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": { "node_modules/which": {
"version": "2.0.2", "version": "2.0.2",
"resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",

View File

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

View File

@ -2,15 +2,18 @@
/* jshint esversion: 6 */ /* jshint esversion: 6 */
const fs = require('fs'); const fs = require('fs');
const generateMJS = (module) => { const defaultReplacements = {
let { src, dest, title, replacements } = module; mjs: [
let text = fs.readFileSync(src, 'utf-8');
replacements.push(
[/const (.+?)\s*=\s*require\(\'\.(.+)\'\)/ig, 'import $1 from \'\.$2.mjs\''], [/const (.+?)\s*=\s*require\(\'\.(.+)\'\)/ig, 'import $1 from \'\.$2.mjs\''],
[/const (.+?)\s*=\s*require\(\'(.+)\'\)/ig, 'import $1 from \'$2\''], [/const (.+?)\s*=\s*require\(\'(.+)\'\)/ig, 'import $1 from \'$2\''],
[/module\.exports =/ig, 'export'] [/module\.exports =/ig, 'export']
); ]
}
const generateFile = (module) => {
let { src, dest, title, replacements } = module;
let text = fs.readFileSync(src, 'utf-8');
replacements.forEach(rep => { replacements.forEach(rep => {
text = text.replace(rep[0], rep[1]); text = text.replace(rep[0], rep[1]);
}); });
@ -18,42 +21,54 @@ const generateMJS = (module) => {
console.log(`Generate ${dest}`); console.log(`Generate ${dest}`);
fs.writeFileSync(dest, fs.writeFileSync(dest,
`// Generated ESM version of ${title} `// ${title}
// DO NOT EDIT THIS FILE! // DO NOT EDIT THIS FILE!
// Source: /${src} // Source: /${src}
${text}`, 'utf-8'); ${text}`, 'utf-8');
}; };
const modules = [ const files = [
{ {
src : 'src/main/ua-parser.js', src : 'src/main/ua-parser.js',
dest : 'src/main/ua-parser.mjs', dest : 'src/main/ua-parser.mjs',
title : 'ua-parser-js', title : 'Generated ESM version of ua-parser-js',
replacements : [ replacements : [
[/\(func[\s\S]+strict\';/ig, ''], [/\(func[\s\S]+strict\';/ig, ''],
[/esversion\: 3/ig, 'esversion: 6'], [/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', src : 'src/enums/ua-parser-enums.js',
dest :'src/enums/ua-parser-enums.mjs', dest :'src/enums/ua-parser-enums.mjs',
title : 'ua-parser-js/enums', title : 'Generated ESM version of ua-parser-js/enums',
replacements : [] 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', src : 'src/extensions/ua-parser-extensions.js',
dest : 'src/extensions/ua-parser-extensions.mjs', dest : 'src/extensions/ua-parser-extensions.mjs',
title : 'ua-parser-js/extensions', title : 'Generated ESM version of ua-parser-js/extensions',
replacements : [] replacements : [...defaultReplacements.mjs]
}, },
{ {
src : 'src/helpers/ua-parser-helpers.js', src : 'src/helpers/ua-parser-helpers.js',
dest : 'src/helpers/ua-parser-helpers.mjs', dest : 'src/helpers/ua-parser-helpers.mjs',
title : 'ua-parser-js/helpers', title : 'Generated ESM version of ua-parser-js/helpers',
replacements : [] 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 https://github.com/faisalman/ua-parser-js
Author: Faisal Salman <f@faisalman.com> Author: Faisal Salman <f@faisalman.com>
AGPLv3 License */ AGPLv3 License */
@ -7,7 +7,7 @@
/*jshint esversion: 6 */ /*jshint esversion: 6 */
const Browser = Object.freeze({ const BrowserName = Object.freeze({
'115': '115', '115': '115',
'2345': '2345', '2345': '2345',
'360': '360', '360': '360',
@ -158,10 +158,15 @@ const Browser = Object.freeze({
WEIBO: 'Weibo', WEIBO: 'Weibo',
WHALE: 'Whale', WHALE: 'Whale',
WOLVIC: 'Wolvic', WOLVIC: 'Wolvic',
YANDEX: 'Yandex' YANDEX: 'Yandex',
ZALO: 'Zalo'
// TODO : test! // TODO : test!
}); });
/**
* @deprecated Use `BrowserName` instead
*/
const Browser = BrowserName;
const BrowserType = Object.freeze({ const BrowserType = Object.freeze({
CRAWLER: 'crawler', CRAWLER: 'crawler',
@ -173,8 +178,9 @@ const BrowserType = Object.freeze({
LIBRARY: 'library' LIBRARY: 'library'
}); });
const CPU = Object.freeze({ const CPUArch = Object.freeze({
'68K': '68k', '68K': '68k',
ALPHA: 'alpha',
ARM : 'arm', ARM : 'arm',
ARM_64: 'arm64', ARM_64: 'arm64',
ARM_HF: 'armhf', ARM_HF: 'armhf',
@ -192,8 +198,12 @@ const CPU = Object.freeze({
X86: 'ia32', X86: 'ia32',
X86_64: 'amd64' X86_64: 'amd64'
}); });
/**
* @deprecated Use `CPUArch` instead
*/
const CPU = CPUArch;
const Device = Object.freeze({ const DeviceType = Object.freeze({
CONSOLE: 'console', CONSOLE: 'console',
DESKTOP: 'desktop', DESKTOP: 'desktop',
EMBEDDED: 'embedded', EMBEDDED: 'embedded',
@ -203,8 +213,12 @@ const Device = Object.freeze({
WEARABLE: 'wearable', WEARABLE: 'wearable',
XR: 'xr' XR: 'xr'
}); });
/**
* @deprecated Use `DeviceType` instead
*/
const Device = DeviceType;
const Vendor = Object.freeze({ const DeviceVendor = Object.freeze({
ACER: 'Acer', ACER: 'Acer',
ADVAN: 'Advan', ADVAN: 'Advan',
ALCATEL: 'Alcatel', ALCATEL: 'Alcatel',
@ -252,6 +266,7 @@ const Vendor = Object.freeze({
PALM: 'Palm', PALM: 'Palm',
PANASONIC: 'Panasonic', PANASONIC: 'Panasonic',
PEBBLE: 'Pebble', PEBBLE: 'Pebble',
PHILIPS: 'Philips',
PICO: 'Pico', PICO: 'Pico',
POLYTRON: 'Polytron', POLYTRON: 'Polytron',
REALME: 'Realme', REALME: 'Realme',
@ -266,7 +281,7 @@ const Vendor = Object.freeze({
SPRINT: 'Sprint', SPRINT: 'Sprint',
TCL: 'TCL', TCL: 'TCL',
TECHNISAT: 'TechniSAT', TECHNISAT: 'TechniSAT',
TECNO: 'Tecno', TECNO: 'TECNO',
TESLA: 'Tesla', TESLA: 'Tesla',
ULEFONE: 'Ulefone', ULEFONE: 'Ulefone',
VIVO: 'Vivo', VIVO: 'Vivo',
@ -279,8 +294,12 @@ const Vendor = Object.freeze({
// TODO : test! // TODO : test!
}); });
/**
* @deprecated Use `DeviceVendor` instead
*/
const Vendor = DeviceVendor;
const Engine = Object.freeze({ const EngineName = Object.freeze({
AMAYA: 'Amaya', AMAYA: 'Amaya',
ARKWEB: 'ArkWeb', ARKWEB: 'ArkWeb',
BLINK: 'Blink', BLINK: 'Blink',
@ -302,8 +321,12 @@ const Engine = Object.freeze({
W3M: 'w3m', W3M: 'w3m',
WEBKIT: 'WebKit' WEBKIT: 'WebKit'
}); });
/**
* @deprecated Use `EngineName` instead
*/
const Engine = EngineName;
const OS = Object.freeze({ const OSName = Object.freeze({
AIX: 'AIX', AIX: 'AIX',
AMIGA_OS: 'Amiga OS', AMIGA_OS: 'Amiga OS',
ANDROID: 'Android', ANDROID: 'Android',
@ -399,13 +422,322 @@ const OS = Object.freeze({
// TODO : test! // 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 = { module.exports = {
Browser, Browser,// deprecated
CPU, // deprecated
Device, // deprecated
Vendor, // deprecated
Engine, // deprecated
OS, // deprecated
BrowserName,
BrowserType, BrowserType,
CPU, CPUArch,
Device, DeviceType,
Vendor, DeviceVendor,
Engine, EngineName,
OS OSName,
Extension
}; };

View File

@ -3,7 +3,7 @@
// Source: /src/enums/ua-parser-enums.js // 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 https://github.com/faisalman/ua-parser-js
Author: Faisal Salman <f@faisalman.com> Author: Faisal Salman <f@faisalman.com>
AGPLv3 License */ AGPLv3 License */
@ -11,7 +11,7 @@
/*jshint esversion: 6 */ /*jshint esversion: 6 */
const Browser = Object.freeze({ const BrowserName = Object.freeze({
'115': '115', '115': '115',
'2345': '2345', '2345': '2345',
'360': '360', '360': '360',
@ -162,10 +162,15 @@ const Browser = Object.freeze({
WEIBO: 'Weibo', WEIBO: 'Weibo',
WHALE: 'Whale', WHALE: 'Whale',
WOLVIC: 'Wolvic', WOLVIC: 'Wolvic',
YANDEX: 'Yandex' YANDEX: 'Yandex',
ZALO: 'Zalo'
// TODO : test! // TODO : test!
}); });
/**
* @deprecated Use `BrowserName` instead
*/
const Browser = BrowserName;
const BrowserType = Object.freeze({ const BrowserType = Object.freeze({
CRAWLER: 'crawler', CRAWLER: 'crawler',
@ -177,8 +182,9 @@ const BrowserType = Object.freeze({
LIBRARY: 'library' LIBRARY: 'library'
}); });
const CPU = Object.freeze({ const CPUArch = Object.freeze({
'68K': '68k', '68K': '68k',
ALPHA: 'alpha',
ARM : 'arm', ARM : 'arm',
ARM_64: 'arm64', ARM_64: 'arm64',
ARM_HF: 'armhf', ARM_HF: 'armhf',
@ -196,8 +202,12 @@ const CPU = Object.freeze({
X86: 'ia32', X86: 'ia32',
X86_64: 'amd64' X86_64: 'amd64'
}); });
/**
* @deprecated Use `CPUArch` instead
*/
const CPU = CPUArch;
const Device = Object.freeze({ const DeviceType = Object.freeze({
CONSOLE: 'console', CONSOLE: 'console',
DESKTOP: 'desktop', DESKTOP: 'desktop',
EMBEDDED: 'embedded', EMBEDDED: 'embedded',
@ -207,8 +217,12 @@ const Device = Object.freeze({
WEARABLE: 'wearable', WEARABLE: 'wearable',
XR: 'xr' XR: 'xr'
}); });
/**
* @deprecated Use `DeviceType` instead
*/
const Device = DeviceType;
const Vendor = Object.freeze({ const DeviceVendor = Object.freeze({
ACER: 'Acer', ACER: 'Acer',
ADVAN: 'Advan', ADVAN: 'Advan',
ALCATEL: 'Alcatel', ALCATEL: 'Alcatel',
@ -256,6 +270,7 @@ const Vendor = Object.freeze({
PALM: 'Palm', PALM: 'Palm',
PANASONIC: 'Panasonic', PANASONIC: 'Panasonic',
PEBBLE: 'Pebble', PEBBLE: 'Pebble',
PHILIPS: 'Philips',
PICO: 'Pico', PICO: 'Pico',
POLYTRON: 'Polytron', POLYTRON: 'Polytron',
REALME: 'Realme', REALME: 'Realme',
@ -270,7 +285,7 @@ const Vendor = Object.freeze({
SPRINT: 'Sprint', SPRINT: 'Sprint',
TCL: 'TCL', TCL: 'TCL',
TECHNISAT: 'TechniSAT', TECHNISAT: 'TechniSAT',
TECNO: 'Tecno', TECNO: 'TECNO',
TESLA: 'Tesla', TESLA: 'Tesla',
ULEFONE: 'Ulefone', ULEFONE: 'Ulefone',
VIVO: 'Vivo', VIVO: 'Vivo',
@ -283,8 +298,12 @@ const Vendor = Object.freeze({
// TODO : test! // TODO : test!
}); });
/**
* @deprecated Use `DeviceVendor` instead
*/
const Vendor = DeviceVendor;
const Engine = Object.freeze({ const EngineName = Object.freeze({
AMAYA: 'Amaya', AMAYA: 'Amaya',
ARKWEB: 'ArkWeb', ARKWEB: 'ArkWeb',
BLINK: 'Blink', BLINK: 'Blink',
@ -306,8 +325,12 @@ const Engine = Object.freeze({
W3M: 'w3m', W3M: 'w3m',
WEBKIT: 'WebKit' WEBKIT: 'WebKit'
}); });
/**
* @deprecated Use `EngineName` instead
*/
const Engine = EngineName;
const OS = Object.freeze({ const OSName = Object.freeze({
AIX: 'AIX', AIX: 'AIX',
AMIGA_OS: 'Amiga OS', AMIGA_OS: 'Amiga OS',
ANDROID: 'Android', ANDROID: 'Android',
@ -403,13 +426,322 @@ const OS = Object.freeze({
// TODO : test! // 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 { export {
Browser, Browser,// deprecated
CPU, // deprecated
Device, // deprecated
Vendor, // deprecated
Engine, // deprecated
OS, // deprecated
BrowserName,
BrowserType, BrowserType,
CPU, CPUArch,
Device, DeviceType,
Vendor, DeviceVendor,
Engine, EngineName,
OS 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 // Project: https://github.com/faisalman/ua-parser-js
// Definitions by: Faisal Salman <https://github.com/faisalman> // 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 https://github.com/faisalman/ua-parser-js
Author: Faisal Salman <f@faisalman.com> Author: Faisal Salman <f@faisalman.com>
AGPLv3 License */ AGPLv3 License */
@ -43,20 +43,31 @@ const Crawlers = Object.freeze({
// AhrefsBot - https://ahrefs.com/robot // AhrefsBot - https://ahrefs.com/robot
// Amazonbot - https://developer.amazon.com/amazonbot // Amazonbot - https://developer.amazon.com/amazonbot
// Bingbot / AdIdxBot - https://www.bing.com/webmasters/help/which-crawlers-does-bing-use-8c184ec0 // 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 // 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 // Dotbot - https://moz.com/help/moz-procedures/crawlers/dotbot
// DuckDuckBot - http://duckduckgo.com/duckduckbot.html // DuckDuckBot - http://duckduckgo.com/duckduckbot.html
// FacebookBot - https://developers.facebook.com/docs/sharing/bot/ // FacebookBot - https://developers.facebook.com/docs/sharing/bot/
// GPTBot - https://platform.openai.com/docs/gptbot // GPTBot - https://platform.openai.com/docs/gptbot
// iAskBot - https://iask.ai // iAskBot - https://iask.ai
// Kagibot - https://kagi.com/bot
// Kangaroo Bot - https://kangaroollm.com.au/kangaroo-bot/
// LinkedInBot - http://www.linkedin.com // LinkedInBot - http://www.linkedin.com
// MJ12bot - https://mj12bot.com/ // MJ12bot - https://mj12bot.com/
// MojeekBot - https://www.mojeek.com/bot.html // MojeekBot - https://www.mojeek.com/bot.html
// Onespot - https://www.onespot.com/identifying-traffic.html // Onespot - https://www.onespot.com/identifying-traffic.html
// OpenAI's SearchGPT - https://platform.openai.com/docs/bots // OpenAI's SearchGPT - https://platform.openai.com/docs/bots
// PerplexityBot - https://perplexity.ai/perplexitybot // PerplexityBot - https://perplexity.ai/perplexitybot
// SBIntuitionsBot - https://www.sbintuitions.co.jp/bot/
// SeznamBot - http://napoveda.seznam.cz/seznambot-intro // 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 - http://apple.com/go/applebot
/(applebot(?:-extended)?)\/?([\w\.]*)/i, /(applebot(?:-extended)?)\/?([\w\.]*)/i,
@ -65,7 +76,7 @@ const Crawlers = Object.freeze({
/(baiduspider[-imagevdonwsfcpr]{0,7})\/?([\w\.]*)/i, /(baiduspider[-imagevdonwsfcpr]{0,7})\/?([\w\.]*)/i,
// ClaudeBot (Anthropic) // 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 // Coc Coc Bot - https://help.coccoc.com/en/search-engine
/(coccocbot-(?:image|web))\/([\w\.]+)/i, /(coccocbot-(?:image|web))\/([\w\.]+)/i,
@ -83,6 +94,9 @@ const Crawlers = Object.freeze({
// Internet Archive (archive.org) // Internet Archive (archive.org)
/(ia_archiver|archive\.org_bot)\/?([\w\.]*)/i, /(ia_archiver|archive\.org_bot)\/?([\w\.]*)/i,
// OnCrawl
/(oncrawl) mobile\/([\w\.]+)/i,
// Qwantbot - https://help.qwant.com/bot // Qwantbot - https://help.qwant.com/bot
/(qwantbot)[-\w]*\/?([\w\.]*)/i, /(qwantbot)[-\w]*\/?([\w\.]*)/i,
@ -96,30 +110,38 @@ const Crawlers = Object.freeze({
/(y!?j-(?:asr|br[uw]|dscv|mmp|vsidx|wsc))\/([\w\.]+)/i, /(y!?j-(?:asr|br[uw]|dscv|mmp|vsidx|wsc))\/([\w\.]+)/i,
// Yandex Bots - https://yandex.com/bots // 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 (Naver)
/(yeti)\/([\w\.]+)/i, /(yeti)\/([\w\.]+)/i,
// aiHitBot / Diffbot / Linespider / Magpie-Crawler / Omgilibot / OpenAI Image Downloader / Webzio-Extended / Screaming Frog SEO Spider / Startpage / Timpibot / VelenPublicWebCrawler / YisouSpider / YouBot // 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
/((?: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 // 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]], [NAME, VERSION, [TYPE, CRAWLER]],
[
// YandexBot MirrorDetector
/(yandexbot\/([\w\.]+); mirrordetector)/i
],
[[NAME, /\/.+;/ig, ''], VERSION, [TYPE, CRAWLER]],
[ [
// Google Bots // Google Bots
/((?:adsbot|apis|mediapartners)-google(?:-mobile)?|google-?(?:other|cloudvertexbot|extended|safety))/i, /((?:adsbot|apis|mediapartners)-google(?:-mobile)?|google-?(?:other|cloudvertexbot|extended|safety))/i,
// AI2Bot - https://allenai.org/crawler // AI2Bot - https://allenai.org/crawler
// Bytespider
// DataForSeoBot - https://dataforseo.com/dataforseo-bot // DataForSeoBot - https://dataforseo.com/dataforseo-bot
// Huawei AspiegelBot / PetalBot https://aspiegel.com/petalbot // Huawei AspiegelBot / PetalBot https://aspiegel.com/petalbot
// ImagesiftBot - https://imagesift.com/about // ImagesiftBot - https://imagesift.com/about
// Qihoo 360Spider // Siteimprove - https://help.siteimprove.com/support/solutions/articles/80000448553
// TurnitinBot - https://www.turnitin.com/robot/crawlerinfo.html // 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 // 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]] [NAME, [TYPE, CRAWLER]]
] ]
@ -234,16 +256,17 @@ const Emails = Object.freeze({
const Fetchers = Object.freeze({ const Fetchers = Object.freeze({
browser : [ 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 // 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 // ChatGPT-User - https://platform.openai.com/docs/plugins/bot
// DuckAssistBot - https://duckduckgo.com/duckassistbot/ // DuckAssistBot - https://duckduckgo.com/duckassistbot/
// Better Uptime / BingPreview / Mastodon / MicrosoftPreview / Pinterestbot / Redditbot / Rogerbot / SiteAuditBot / Telegrambot / Twitterbot / UptimeRobot
// Google Site Verifier / Meta / Yahoo! Japan // Google Site Verifier / Meta / Yahoo! Japan
// Iframely - https://iframely.com/docs/about // Iframely - https://iframely.com/docs/about
// Perplexity-User - https://docs.perplexity.ai/guides/bots // Perplexity-User - https://docs.perplexity.ai/guides/bots
// MistralAI-User - https://docs.mistral.ai/robots/ // MistralAI-User - https://docs.mistral.ai/robots/
// Yandex Bots - https://yandex.com/bots // 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
/(bluesky) cardyb\/([\w\.]+)/i, /(bluesky) cardyb\/([\w\.]+)/i,
@ -260,8 +283,8 @@ const Fetchers = Object.freeze({
[NAME, VERSION, [TYPE, FETCHER]], [NAME, VERSION, [TYPE, FETCHER]],
[ [
// Google Bots / Cohere / Snapchat / Vercelbot / Yandex Bots // Google Bots / Chrome-Lighthouse / Gemini-Deep-Research / 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 /((?: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]], [NAME, [TYPE, FETCHER]],
], ],
@ -404,8 +427,8 @@ const Vehicles = Object.freeze({
const Bots = Object.freeze({ const Bots = Object.freeze({
browser : [ browser : [
...CLIs.browser, ...CLIs.browser,
...Crawlers.browser,
...Fetchers.browser, ...Fetchers.browser,
...Crawlers.browser,
...Libraries.browser ...Libraries.browser
], ],
os : [ os : [

View File

@ -3,7 +3,7 @@
// Source: /src/extensions/ua-parser-extensions.js // 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 https://github.com/faisalman/ua-parser-js
Author: Faisal Salman <f@faisalman.com> Author: Faisal Salman <f@faisalman.com>
AGPLv3 License */ AGPLv3 License */
@ -47,20 +47,31 @@ const Crawlers = Object.freeze({
// AhrefsBot - https://ahrefs.com/robot // AhrefsBot - https://ahrefs.com/robot
// Amazonbot - https://developer.amazon.com/amazonbot // Amazonbot - https://developer.amazon.com/amazonbot
// Bingbot / AdIdxBot - https://www.bing.com/webmasters/help/which-crawlers-does-bing-use-8c184ec0 // 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 // 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 // Dotbot - https://moz.com/help/moz-procedures/crawlers/dotbot
// DuckDuckBot - http://duckduckgo.com/duckduckbot.html // DuckDuckBot - http://duckduckgo.com/duckduckbot.html
// FacebookBot - https://developers.facebook.com/docs/sharing/bot/ // FacebookBot - https://developers.facebook.com/docs/sharing/bot/
// GPTBot - https://platform.openai.com/docs/gptbot // GPTBot - https://platform.openai.com/docs/gptbot
// iAskBot - https://iask.ai // iAskBot - https://iask.ai
// Kagibot - https://kagi.com/bot
// Kangaroo Bot - https://kangaroollm.com.au/kangaroo-bot/
// LinkedInBot - http://www.linkedin.com // LinkedInBot - http://www.linkedin.com
// MJ12bot - https://mj12bot.com/ // MJ12bot - https://mj12bot.com/
// MojeekBot - https://www.mojeek.com/bot.html // MojeekBot - https://www.mojeek.com/bot.html
// Onespot - https://www.onespot.com/identifying-traffic.html // Onespot - https://www.onespot.com/identifying-traffic.html
// OpenAI's SearchGPT - https://platform.openai.com/docs/bots // OpenAI's SearchGPT - https://platform.openai.com/docs/bots
// PerplexityBot - https://perplexity.ai/perplexitybot // PerplexityBot - https://perplexity.ai/perplexitybot
// SBIntuitionsBot - https://www.sbintuitions.co.jp/bot/
// SeznamBot - http://napoveda.seznam.cz/seznambot-intro // 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 - http://apple.com/go/applebot
/(applebot(?:-extended)?)\/?([\w\.]*)/i, /(applebot(?:-extended)?)\/?([\w\.]*)/i,
@ -69,7 +80,7 @@ const Crawlers = Object.freeze({
/(baiduspider[-imagevdonwsfcpr]{0,7})\/?([\w\.]*)/i, /(baiduspider[-imagevdonwsfcpr]{0,7})\/?([\w\.]*)/i,
// ClaudeBot (Anthropic) // 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 // Coc Coc Bot - https://help.coccoc.com/en/search-engine
/(coccocbot-(?:image|web))\/([\w\.]+)/i, /(coccocbot-(?:image|web))\/([\w\.]+)/i,
@ -87,6 +98,9 @@ const Crawlers = Object.freeze({
// Internet Archive (archive.org) // Internet Archive (archive.org)
/(ia_archiver|archive\.org_bot)\/?([\w\.]*)/i, /(ia_archiver|archive\.org_bot)\/?([\w\.]*)/i,
// OnCrawl
/(oncrawl) mobile\/([\w\.]+)/i,
// Qwantbot - https://help.qwant.com/bot // Qwantbot - https://help.qwant.com/bot
/(qwantbot)[-\w]*\/?([\w\.]*)/i, /(qwantbot)[-\w]*\/?([\w\.]*)/i,
@ -100,30 +114,38 @@ const Crawlers = Object.freeze({
/(y!?j-(?:asr|br[uw]|dscv|mmp|vsidx|wsc))\/([\w\.]+)/i, /(y!?j-(?:asr|br[uw]|dscv|mmp|vsidx|wsc))\/([\w\.]+)/i,
// Yandex Bots - https://yandex.com/bots // 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 (Naver)
/(yeti)\/([\w\.]+)/i, /(yeti)\/([\w\.]+)/i,
// aiHitBot / Diffbot / Linespider / Magpie-Crawler / Omgilibot / OpenAI Image Downloader / Webzio-Extended / Screaming Frog SEO Spider / Startpage / Timpibot / VelenPublicWebCrawler / YisouSpider / YouBot // 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
/((?: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 // 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]], [NAME, VERSION, [TYPE, CRAWLER]],
[
// YandexBot MirrorDetector
/(yandexbot\/([\w\.]+); mirrordetector)/i
],
[[NAME, /\/.+;/ig, ''], VERSION, [TYPE, CRAWLER]],
[ [
// Google Bots // Google Bots
/((?:adsbot|apis|mediapartners)-google(?:-mobile)?|google-?(?:other|cloudvertexbot|extended|safety))/i, /((?:adsbot|apis|mediapartners)-google(?:-mobile)?|google-?(?:other|cloudvertexbot|extended|safety))/i,
// AI2Bot - https://allenai.org/crawler // AI2Bot - https://allenai.org/crawler
// Bytespider
// DataForSeoBot - https://dataforseo.com/dataforseo-bot // DataForSeoBot - https://dataforseo.com/dataforseo-bot
// Huawei AspiegelBot / PetalBot https://aspiegel.com/petalbot // Huawei AspiegelBot / PetalBot https://aspiegel.com/petalbot
// ImagesiftBot - https://imagesift.com/about // ImagesiftBot - https://imagesift.com/about
// Qihoo 360Spider // Siteimprove - https://help.siteimprove.com/support/solutions/articles/80000448553
// TurnitinBot - https://www.turnitin.com/robot/crawlerinfo.html // 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 // 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]] [NAME, [TYPE, CRAWLER]]
] ]
@ -238,16 +260,17 @@ const Emails = Object.freeze({
const Fetchers = Object.freeze({ const Fetchers = Object.freeze({
browser : [ 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 // 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 // ChatGPT-User - https://platform.openai.com/docs/plugins/bot
// DuckAssistBot - https://duckduckgo.com/duckassistbot/ // DuckAssistBot - https://duckduckgo.com/duckassistbot/
// Better Uptime / BingPreview / Mastodon / MicrosoftPreview / Pinterestbot / Redditbot / Rogerbot / SiteAuditBot / Telegrambot / Twitterbot / UptimeRobot
// Google Site Verifier / Meta / Yahoo! Japan // Google Site Verifier / Meta / Yahoo! Japan
// Iframely - https://iframely.com/docs/about // Iframely - https://iframely.com/docs/about
// Perplexity-User - https://docs.perplexity.ai/guides/bots // Perplexity-User - https://docs.perplexity.ai/guides/bots
// MistralAI-User - https://docs.mistral.ai/robots/ // MistralAI-User - https://docs.mistral.ai/robots/
// Yandex Bots - https://yandex.com/bots // 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
/(bluesky) cardyb\/([\w\.]+)/i, /(bluesky) cardyb\/([\w\.]+)/i,
@ -264,8 +287,8 @@ const Fetchers = Object.freeze({
[NAME, VERSION, [TYPE, FETCHER]], [NAME, VERSION, [TYPE, FETCHER]],
[ [
// Google Bots / Cohere / Snapchat / Vercelbot / Yandex Bots // Google Bots / Chrome-Lighthouse / Gemini-Deep-Research / 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 /((?: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]], [NAME, [TYPE, FETCHER]],
], ],
@ -408,8 +431,8 @@ const Vehicles = Object.freeze({
const Bots = Object.freeze({ const Bots = Object.freeze({
browser : [ browser : [
...CLIs.browser, ...CLIs.browser,
...Crawlers.browser,
...Fetchers.browser, ...Fetchers.browser,
...Crawlers.browser,
...Libraries.browser ...Libraries.browser
], ],
os : [ 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 // Project: https://github.com/faisalman/ua-parser-js
// Definitions by: Faisal Salman <https://github.com/faisalman> // Definitions by: Faisal Salman <https://github.com/faisalman>
import type { IResult } from "../main/ua-parser"; import type { IResult } from "../main/ua-parser";
declare function getDeviceVendor(model: string): string | undefined; export function getDeviceVendor(model: string): string | undefined;
declare function isAppleSilicon(resultOrUA: IResult | string): boolean; export function isAppleSilicon(resultOrUA: IResult | string): boolean;
declare function isAIBot(resultOrUA: IResult | string): boolean; export function isAIBot(resultOrUA: IResult | string): boolean;
declare function isBot(resultOrUA: IResult | string): boolean; export function isBot(resultOrUA: IResult | string): boolean;
declare function isChromeFamily(resultOrUA: IResult | string): boolean; export function isChromeFamily(resultOrUA: IResult | string): boolean;
declare function isElectron(): boolean; export function isElectron(): boolean;
declare function isFromEU(): boolean; export function isFromEU(): boolean;
declare function isFrozenUA(ua: string): boolean; export function isFrozenUA(ua: string): boolean;
declare function isStandalonePWA(): boolean; export function isStandalonePWA(): boolean;
export {
getDeviceVendor,
isAppleSilicon,
isAIBot,
isBot,
isChromeFamily,
isElectron,
isFromEU,
isFrozenUA,
isStandalonePWA
}

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

View File

@ -3,7 +3,7 @@
// Source: /src/helpers/ua-parser-helpers.js // 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 https://github.com/faisalman/ua-parser-js
Author: Faisal Salman <f@faisalman.com> Author: Faisal Salman <f@faisalman.com>
AGPLv3 License */ AGPLv3 License */
@ -12,11 +12,12 @@
/*jshint esversion: 6 */ /*jshint esversion: 6 */
import { UAParser } from '../main/ua-parser.mjs'; import { UAParser } from '../main/ua-parser.mjs';
import { CPU, OS, Engine } from '../enums/ua-parser-enums.mjs'; import { CPUArch, OSName, EngineName, Extension, BrowserType } from '../enums/ua-parser-enums.mjs';
import { Bots } from '../extensions/ua-parser-extensions.mjs'; import { Bots, Crawlers } from '../extensions/ua-parser-extensions.mjs';
import { isFromEU } from 'detect-europe-js'; import { isFromEU } from 'detect-europe-js';
import { isFrozenUA } from 'ua-is-frozen'; import { isFrozenUA } from 'ua-is-frozen';
import { isStandalonePWA } from 'is-standalone-pwa'; import { isStandalonePWA } from 'is-standalone-pwa';
const { Crawler } = Extension.BrowserName;
const toResult = (value, head, ext) => typeof value === 'string' ? UAParser(value, head, ext) : value; 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 isAppleSilicon = (resultOrUA) => {
const res = toResult(resultOrUA); const res = toResult(resultOrUA);
if (res.os.is(OS.MACOS)) { if (res.os.is(OSName.MACOS)) {
if (res.cpu.is(CPU.ARM)) { if (res.cpu.is(CPUArch.ARM)) {
return true; return true;
} }
if (typeof resultOrUA !== 'string' && typeof window !== 'undefined') { if (typeof resultOrUA !== 'string' && typeof window !== 'undefined') {
@ -48,88 +49,129 @@ const isAppleSilicon = (resultOrUA) => {
const isAIBot = (resultOrUA) => [ const isAIBot = (resultOrUA) => [
// AI2 // AI2
'ai2bot', Crawler.AI2_BOT,
// Amazon // Amazon
'amazonbot', Crawler.AMAZON_BOT,
// Anthropic // Anthropic
'anthropic-ai', Crawler.ANTHROPIC_AI,
'claude-web', Crawler.ANTHROPIC_CLAUDE_BOT,
'claudebot', Crawler.ANTHROPIC_CLAUDE_SEARCHBOT,
Crawler.ANTHROPIC_CLAUDE_WEB,
// Apple // Apple
'applebot', Crawler.APPLE_BOT,
'applebot-extended', Crawler.APPLE_BOT_EXTENDED,
// Brave
Crawler.BRAVE_BOT,
// ByteDance // ByteDance
'bytespider', Crawler.BYTEDANCE_BYTESPIDER,
Crawler.BYTEDANCE_TIKTOKSPIDER,
// Cohere
Crawler.COHERE_TRAINING_DATA_CRAWLER,
// Common Crawl // Common Crawl
'ccbot', Crawler.COMMON_CRAWL_CCBOT,
// Coveo
Crawler.COVEO_BOT,
// DataForSeo // DataForSeo
'dataforseobot', Crawler.DATAFORSEO_BOT,
// DeepSeek
Crawler.DEEPSEEK_BOT,
// Diffbot // Diffbot
'diffbot', Crawler.DIFFBOT,
// Google // Google
'googleother', Crawler.GOOGLE_EXTENDED,
'googleother-image', Crawler.GOOGLE_OTHER,
'googleother-video', Crawler.GOOGLE_OTHER_IMAGE,
'google-extended', Crawler.GOOGLE_OTHER_VIDEO,
Crawler.GOOGLE_CLOUDVERTEXBOT,
// Hive AI // Hive AI
'imagesiftbot', Crawler.HIVE_IMAGESIFTBOT,
// Huawei // Huawei
'petalbot', Crawler.HUAWEI_PETALBOT,
Crawler.HUAWEI_PANGUBOT,
// Hugging Face
Crawler.HUGGINGFACE_BOT,
// Kangaroo
Crawler.KANGAROO_BOT,
// Mendable.ai
Crawler.FIRECRAWL_AGENT,
// Meta // Meta
'facebookbot', Crawler.META_FACEBOOKBOT,
'meta-externalagent', Crawler.META_EXTERNALAGENT,
// OpenAI // OpenAI
'gptbot', Crawler.OPENAI_GPTBOT,
'oai-searchbot', Crawler.OPENAI_SEARCH_BOT,
// Perplexity // Perplexity
'perplexitybot', Crawler.PERPLEXITY_BOT,
// Replicate
Crawler.REPLICATE_BOT,
// Runpod
Crawler.RUNPOD_BOT,
// SB Intuitions
Crawler.SB_INTUITIONS_BOT,
// Semrush // Semrush
'semrushbot-ocob', Crawler.SEMRUSH_BOT_CONTENTSHAKE,
// Timpi // Timpi
'timpibot', Crawler.TIMPI_BOT,
// Together AI
Crawler.TOGETHER_BOT,
// Velen.io // Velen.io
'velenpublicwebcrawler', Crawler.HUNTER_VELENPUBLICWEBCRAWLER,
// Vercel
Crawler.VERCEL_V0BOT,
// Webz.io // Webz.io
'omgili', Crawler.WEBZIO_OMGILI,
'omgilibot', Crawler.WEBZIO_OMGILI_BOT,
'webzio-extended', Crawler.WEBZIO_EXTENDED,
// X
Crawler.XAI_BOT,
// You.com // You.com
'youbot', Crawler.YOU_BOT,
// Zhipu AI // Zhipu AI
'chatglm-spider', Crawler.ZHIPU_CHATGLM_SPIDER
]
// Zyte .map((s) => s.toLowerCase())
'scrapy' .includes(String(toResult(resultOrUA, Crawlers).browser.name).toLowerCase());
].includes(String(toResult(resultOrUA, Bots).browser.name).toLowerCase());
const isBot = (resultOrUA) => [ const isBot = (resultOrUA) => [
'cli', BrowserType.CLI,
'crawler', BrowserType.CRAWLER,
'fetcher', BrowserType.FETCHER,
'library' BrowserType.LIBRARY
].includes(toResult(resultOrUA, Bots).browser.type); ].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 const isElectron = () => !!(process?.versions?.hasOwnProperty('electron') || // node.js
/ electron\//i.test(navigator?.userAgent)); // browser / 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 // Project: https://github.com/faisalman/ua-parser-js
// Definitions by: Faisal Salman <https://github.com/faisalman> // Definitions by: Faisal Salman <https://github.com/faisalman>
import type { IncomingHttpHeaders } from 'http'; import type { Headers } from "undici";
import type { Headers as FetchAPIHeaders } from 'node-fetch'; import { BrowserType, CPUArch, DeviceType, EngineName } from "../enums/ua-parser-enums";
declare namespace UAParser { declare namespace UAParser {
@ -18,21 +18,21 @@ declare namespace UAParser {
name?: string; name?: string;
version?: string; version?: string;
major?: string; major?: string;
type?: 'crawler' | 'cli' | 'email' | 'fetcher' | 'inapp' | 'mediaplayer' | 'library'; type?: typeof BrowserType[keyof typeof BrowserType];
} }
interface ICPU extends IData<ICPU> { 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> { interface IDevice extends IData<IDevice> {
type?: 'mobile' | 'tablet' | 'console' | 'smarttv' | 'wearable' | 'xr' | 'embedded'; type?: typeof DeviceType[keyof typeof DeviceType];
vendor?: string; vendor?: string;
model?: string; model?: string;
} }
interface IEngine extends IData<IEngine> { 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; version?: string;
} }
@ -53,7 +53,7 @@ declare namespace UAParser {
type RegexMap = ((RegExp | string | (string | RegExp | Function)[])[])[]; type RegexMap = ((RegExp | string | (string | RegExp | Function)[])[])[];
type UAParserProps = 'browser' | 'cpu' | 'device' | 'engine' | 'os'; type UAParserProps = 'browser' | 'cpu' | 'device' | 'engine' | 'os';
type UAParserExt = Partial<Record<UAParserProps, RegexMap>> | Partial<Record<UAParserProps, RegexMap>>[]; 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, extensions?: UAParserExt, headers?: UAParserHeaders): IResult;
export function UAParser(uastring?: string, 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> Copyright © 2012-2025 Faisal Salman <f@faisalman.com>
AGPLv3 License *//* AGPLv3 License *//*
Detect Browser, Engine, OS, CPU, and Device type/model from User-Agent data. Detect Browser, Engine, OS, CPU, and Device type/model from User-Agent data.
@ -19,7 +19,7 @@
// Constants // Constants
///////////// /////////////
var LIBVERSION = '2.0.4', var LIBVERSION = '2.0.5',
UA_MAX_LENGTH = 500, UA_MAX_LENGTH = 500,
USER_AGENT = 'user-agent', USER_AGENT = 'user-agent',
EMPTY = '', EMPTY = '',
@ -188,6 +188,8 @@
}, },
setProps = function (arr) { setProps = function (arr) {
for (var i in arr) { for (var i in arr) {
if (!arr.hasOwnProperty(i)) continue;
var propName = arr[i]; var propName = arr[i];
if (typeof propName == OBJ_TYPE && propName.length == 2) { if (typeof propName == OBJ_TYPE && propName.length == 2) {
this[propName[0]] = propName[1]; this[propName[0]] = propName[1];
@ -455,6 +457,8 @@
], [VERSION, [NAME, 'TikTok'], [TYPE, INAPP]], [ ], [VERSION, [NAME, 'TikTok'], [TYPE, INAPP]], [
/\[(linkedin)app\]/i // LinkedIn App for iOS & Android /\[(linkedin)app\]/i // LinkedIn App for iOS & Android
], [NAME, [TYPE, INAPP]], [ ], [NAME, [TYPE, INAPP]], [
/(zalo(?:app)?)[\/\sa-z]*([\w\.-]+)/i // Zalo
], [[NAME, /(.+)/, 'Zalo'], VERSION, [TYPE, INAPP]], [
/(chromium)[\/ ]([-\w\.]+)/i // Chromium /(chromium)[\/ ]([-\w\.]+)/i // Chromium
], [NAME, VERSION], [ ], [NAME, VERSION], [
@ -536,15 +540,15 @@
/( (ce|mobile); ppc;|\/[\w\.]+arm\b)/i /( (ce|mobile); ppc;|\/[\w\.]+arm\b)/i
], [[ARCHITECTURE, 'arm']], [ ], [[ARCHITECTURE, 'arm']], [
/((ppc|powerpc)(64)?)( mac|;|\))/i // PowerPC
], [[ARCHITECTURE, /ower/, EMPTY, lowerize]], [
/ sun4\w[;\)]/i // SPARC / sun4\w[;\)]/i // SPARC
], [[ARCHITECTURE, '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 // 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 : [[ device : [[
@ -768,7 +772,8 @@
/; (blu|hmd|imo|infinix|lava|oneplus|tcl)[_ ]([\w\+ ]+?)(?: bui|\)|; r)/i, // BLU/HMD/IMO/Infinix/Lava/OnePlus/TCL /; (blu|hmd|imo|infinix|lava|oneplus|tcl)[_ ]([\w\+ ]+?)(?: bui|\)|; r)/i, // BLU/HMD/IMO/Infinix/Lava/OnePlus/TCL
/(hp) ([\w ]+\w)/i, // HP iPAQ /(hp) ([\w ]+\w)/i, // HP iPAQ
/(microsoft); (lumia[\w ]+)/i, // Microsoft Lumia /(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]], [ ], [VENDOR, MODEL, [TYPE, MOBILE]], [
/(kobo)\s(ereader|touch)/i, // Kobo /(kobo)\s(ereader|touch)/i, // Kobo
@ -795,6 +800,7 @@
// SMARTTVS // SMARTTVS
/////////////////// ///////////////////
/(philips)[\w ]+tv/i, // Philips
/smart-tv.+(samsung)/i // Samsung /smart-tv.+(samsung)/i // Samsung
], [VENDOR, [TYPE, SMARTTV]], [ ], [VENDOR, [TYPE, SMARTTV]], [
/hbbtv.+maple;(\d+)/i /hbbtv.+maple;(\d+)/i
@ -832,11 +838,6 @@
/\b(roku)[\dx]*[\)\/]((?:dvp-)?[\d\.]*)/i, // Roku /\b(roku)[\dx]*[\)\/]((?:dvp-)?[\d\.]*)/i, // Roku
/hbbtv\/\d+\.\d+\.\d+ +\([\w\+ ]*; *([\w\d][^;]*);([^;]*)/i // HbbTV devices /hbbtv\/\d+\.\d+\.\d+ +\([\w\+ ]*; *([\w\d][^;]*);([^;]*)/i // HbbTV devices
], [[VENDOR, /.+\/(\w+)/, '$1', strMapper, {'LG':'lge'}], [MODEL, trim], [TYPE, SMARTTV]], [ ], [[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 // CONSOLES
@ -883,7 +884,7 @@
/droid.+; (glass) \d/i // Google Glass /droid.+; (glass) \d/i // Google Glass
], [MODEL, [VENDOR, GOOGLE], [TYPE, XR]], [ ], [MODEL, [VENDOR, GOOGLE], [TYPE, XR]], [
/(pico) (4|neo3(?: link|pro)?)/i // Pico /(pico) ([\w ]+) os\d/i // Pico
], [VENDOR, MODEL, [TYPE, XR]], [ ], [VENDOR, MODEL, [TYPE, XR]], [
/(quest( \d| pro)?s?).+vr/i // Meta Quest /(quest( \d| pro)?s?).+vr/i // Meta Quest
], [MODEL, [VENDOR, FACEBOOK], [TYPE, XR]], [ ], [MODEL, [VENDOR, FACEBOOK], [TYPE, XR]], [
@ -907,6 +908,10 @@
// MIXED (GENERIC) // 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 /droid .+?; ([^;]+?)(?: bui|; wv\)|\) applew).+?(mobile|vr|\d) safari/i
], [MODEL, [TYPE, strMapper, { 'mobile' : 'Mobile', 'xr' : 'VR', '*' : TABLET }]], [ ], [MODEL, [TYPE, strMapper, { 'mobile' : 'Mobile', 'xr' : 'VR', '*' : TABLET }]], [
/\b((tablet|tab)[;\/]|focus\/\d(?!.+mobile))/i // Unidentifiable Tablet /\b((tablet|tab)[;\/]|focus\/\d(?!.+mobile))/i // Unidentifiable Tablet
@ -1263,7 +1268,7 @@
case UA_ENGINE: case UA_ENGINE:
var brands = uaCH[FULLVERLIST] || uaCH[BRANDS], prevName; var brands = uaCH[FULLVERLIST] || uaCH[BRANDS], prevName;
if (brands) { if (brands) {
for (var i in brands) { for (var i=0; i<brands.length; i++) {
var brandName = brands[i].brand || brands[i], var brandName = brands[i].brand || brands[i],
brandVersion = brands[i].version; brandVersion = brands[i].version;
if (this.itemType == UA_BROWSER && if (this.itemType == UA_BROWSER &&
@ -1385,11 +1390,22 @@
extensions = undefined; extensions = undefined;
} }
if (headers) {
if (typeof headers.append === FUNC_TYPE) {
// Convert Headers object into a plain object // Convert Headers object into a plain object
if (headers && typeof headers.append === FUNC_TYPE) {
var kv = {}; var kv = {};
headers.forEach(function (v, k) { kv[k] = v; }); headers.forEach(function (v, k) { kv[String(k).toLowerCase()] = v; });
headers = kv; 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)) { if (!(this instanceof UAParser)) {

View File

@ -3,7 +3,7 @@
// Source: /src/main/ua-parser.js // Source: /src/main/ua-parser.js
///////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////
/* UAParser.js v2.0.4 /* UAParser.js v2.0.5
Copyright © 2012-2025 Faisal Salman <f@faisalman.com> Copyright © 2012-2025 Faisal Salman <f@faisalman.com>
AGPLv3 License *//* AGPLv3 License *//*
Detect Browser, Engine, OS, CPU, and Device type/model from User-Agent data. Detect Browser, Engine, OS, CPU, and Device type/model from User-Agent data.
@ -21,7 +21,7 @@
// Constants // Constants
///////////// /////////////
var LIBVERSION = '2.0.4', var LIBVERSION = '2.0.5',
UA_MAX_LENGTH = 500, UA_MAX_LENGTH = 500,
USER_AGENT = 'user-agent', USER_AGENT = 'user-agent',
EMPTY = '', EMPTY = '',
@ -190,6 +190,8 @@
}, },
setProps = function (arr) { setProps = function (arr) {
for (var i in arr) { for (var i in arr) {
if (!arr.hasOwnProperty(i)) continue;
var propName = arr[i]; var propName = arr[i];
if (typeof propName == OBJ_TYPE && propName.length == 2) { if (typeof propName == OBJ_TYPE && propName.length == 2) {
this[propName[0]] = propName[1]; this[propName[0]] = propName[1];
@ -457,6 +459,8 @@
], [VERSION, [NAME, 'TikTok'], [TYPE, INAPP]], [ ], [VERSION, [NAME, 'TikTok'], [TYPE, INAPP]], [
/\[(linkedin)app\]/i // LinkedIn App for iOS & Android /\[(linkedin)app\]/i // LinkedIn App for iOS & Android
], [NAME, [TYPE, INAPP]], [ ], [NAME, [TYPE, INAPP]], [
/(zalo(?:app)?)[\/\sa-z]*([\w\.-]+)/i // Zalo
], [[NAME, /(.+)/, 'Zalo'], VERSION, [TYPE, INAPP]], [
/(chromium)[\/ ]([-\w\.]+)/i // Chromium /(chromium)[\/ ]([-\w\.]+)/i // Chromium
], [NAME, VERSION], [ ], [NAME, VERSION], [
@ -538,15 +542,15 @@
/( (ce|mobile); ppc;|\/[\w\.]+arm\b)/i /( (ce|mobile); ppc;|\/[\w\.]+arm\b)/i
], [[ARCHITECTURE, 'arm']], [ ], [[ARCHITECTURE, 'arm']], [
/((ppc|powerpc)(64)?)( mac|;|\))/i // PowerPC
], [[ARCHITECTURE, /ower/, EMPTY, lowerize]], [
/ sun4\w[;\)]/i // SPARC / sun4\w[;\)]/i // SPARC
], [[ARCHITECTURE, '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 // 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 : [[ device : [[
@ -770,7 +774,8 @@
/; (blu|hmd|imo|infinix|lava|oneplus|tcl)[_ ]([\w\+ ]+?)(?: bui|\)|; r)/i, // BLU/HMD/IMO/Infinix/Lava/OnePlus/TCL /; (blu|hmd|imo|infinix|lava|oneplus|tcl)[_ ]([\w\+ ]+?)(?: bui|\)|; r)/i, // BLU/HMD/IMO/Infinix/Lava/OnePlus/TCL
/(hp) ([\w ]+\w)/i, // HP iPAQ /(hp) ([\w ]+\w)/i, // HP iPAQ
/(microsoft); (lumia[\w ]+)/i, // Microsoft Lumia /(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]], [ ], [VENDOR, MODEL, [TYPE, MOBILE]], [
/(kobo)\s(ereader|touch)/i, // Kobo /(kobo)\s(ereader|touch)/i, // Kobo
@ -797,6 +802,7 @@
// SMARTTVS // SMARTTVS
/////////////////// ///////////////////
/(philips)[\w ]+tv/i, // Philips
/smart-tv.+(samsung)/i // Samsung /smart-tv.+(samsung)/i // Samsung
], [VENDOR, [TYPE, SMARTTV]], [ ], [VENDOR, [TYPE, SMARTTV]], [
/hbbtv.+maple;(\d+)/i /hbbtv.+maple;(\d+)/i
@ -834,11 +840,6 @@
/\b(roku)[\dx]*[\)\/]((?:dvp-)?[\d\.]*)/i, // Roku /\b(roku)[\dx]*[\)\/]((?:dvp-)?[\d\.]*)/i, // Roku
/hbbtv\/\d+\.\d+\.\d+ +\([\w\+ ]*; *([\w\d][^;]*);([^;]*)/i // HbbTV devices /hbbtv\/\d+\.\d+\.\d+ +\([\w\+ ]*; *([\w\d][^;]*);([^;]*)/i // HbbTV devices
], [[VENDOR, /.+\/(\w+)/, '$1', strMapper, {'LG':'lge'}], [MODEL, trim], [TYPE, SMARTTV]], [ ], [[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 // CONSOLES
@ -885,7 +886,7 @@
/droid.+; (glass) \d/i // Google Glass /droid.+; (glass) \d/i // Google Glass
], [MODEL, [VENDOR, GOOGLE], [TYPE, XR]], [ ], [MODEL, [VENDOR, GOOGLE], [TYPE, XR]], [
/(pico) (4|neo3(?: link|pro)?)/i // Pico /(pico) ([\w ]+) os\d/i // Pico
], [VENDOR, MODEL, [TYPE, XR]], [ ], [VENDOR, MODEL, [TYPE, XR]], [
/(quest( \d| pro)?s?).+vr/i // Meta Quest /(quest( \d| pro)?s?).+vr/i // Meta Quest
], [MODEL, [VENDOR, FACEBOOK], [TYPE, XR]], [ ], [MODEL, [VENDOR, FACEBOOK], [TYPE, XR]], [
@ -909,6 +910,10 @@
// MIXED (GENERIC) // 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 /droid .+?; ([^;]+?)(?: bui|; wv\)|\) applew).+?(mobile|vr|\d) safari/i
], [MODEL, [TYPE, strMapper, { 'mobile' : 'Mobile', 'xr' : 'VR', '*' : TABLET }]], [ ], [MODEL, [TYPE, strMapper, { 'mobile' : 'Mobile', 'xr' : 'VR', '*' : TABLET }]], [
/\b((tablet|tab)[;\/]|focus\/\d(?!.+mobile))/i // Unidentifiable Tablet /\b((tablet|tab)[;\/]|focus\/\d(?!.+mobile))/i // Unidentifiable Tablet
@ -1265,7 +1270,7 @@
case UA_ENGINE: case UA_ENGINE:
var brands = uaCH[FULLVERLIST] || uaCH[BRANDS], prevName; var brands = uaCH[FULLVERLIST] || uaCH[BRANDS], prevName;
if (brands) { if (brands) {
for (var i in brands) { for (var i=0; i<brands.length; i++) {
var brandName = brands[i].brand || brands[i], var brandName = brands[i].brand || brands[i],
brandVersion = brands[i].version; brandVersion = brands[i].version;
if (this.itemType == UA_BROWSER && if (this.itemType == UA_BROWSER &&
@ -1387,11 +1392,22 @@
extensions = undefined; extensions = undefined;
} }
if (headers) {
if (typeof headers.append === FUNC_TYPE) {
// Convert Headers object into a plain object // Convert Headers object into a plain object
if (headers && typeof headers.append === FUNC_TYPE) {
var kv = {}; var kv = {};
headers.forEach(function (v, k) { kv[k] = v; }); headers.forEach(function (v, k) { kv[String(k).toLowerCase()] = v; });
headers = kv; 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)) { 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", "major" : "10",
"type" : "inapp" "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" "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", "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", "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" "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", "desc": "Samsung SmartTV",
"ua": "Mozilla/5.0 (SMART-TV; X11; Linux armv7l) AppleWebkit/537.42 (KHTML, like Gecko) Safari/537.42", "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", "model": "Neo3 Link",
"type": "xr" "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" "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", "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)", "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" "type" : "crawler"
} }
}, },
{
"desc" : "Baidu ADS",
"ua" : "Baidu-ADS",
"expect" :
{
"name" : "Baidu-ADS",
"version" : "undefined",
"type" : "crawler"
}
},
{ {
"desc" : "Baiduspider", "desc" : "Baiduspider",
"ua" : "Mozilla/5.0 (compatible; Baiduspider/2.0; +http://www.baidu.com/search/spider.html)", "ua" : "Mozilla/5.0 (compatible; Baiduspider/2.0; +http://www.baidu.com/search/spider.html)",
@ -229,6 +259,36 @@
"type" : "crawler" "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", "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", "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" "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)", "desc" : "Coc Coc Bot (web)",
"ua" : "Mozilla/5.0 (compatible; coccocbot-web/1.0; +http://help.coccoc.com/searchengine)", "ua" : "Mozilla/5.0 (compatible; coccocbot-web/1.0; +http://help.coccoc.com/searchengine)",
@ -290,15 +370,55 @@
} }
}, },
{ {
"desc" : "ClaudeWeb", "desc" : "cohere-training-data-crawler",
"ua" : "Claude-Web/1.0 (web crawler; +https://www.anthropic.com/; bots@anthropic.com)", "ua" : "cohere-training-data-crawler (+crawler@cohere.ai)",
"expect" : "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", "version" : "1.0",
"type" : "crawler" "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", "desc" : "DataForSEO",
"ua" : "Mozilla/5.0 (compatible; DataForSeoBot; +https://dataforseo.com/dataforseo-bot)", "ua" : "Mozilla/5.0 (compatible; DataForSeoBot; +https://dataforseo.com/dataforseo-bot)",
@ -339,6 +459,16 @@
"type" : "crawler" "type" : "crawler"
} }
}, },
{
"desc" : "DeepSeekBot",
"ua" : "DeepSeekBot",
"expect" :
{
"name" : "DeepSeekBot",
"version" : "undefined",
"type" : "crawler"
}
},
{ {
"desc" : "Diffbot", "desc" : "Diffbot",
"ua" : "Diffbot/0.1", "ua" : "Diffbot/0.1",
@ -369,6 +499,26 @@
"type" : "crawler" "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", "desc" : "Exabot",
"ua" : "Mozilla/5.0 (compatible; Exabot/3.0; +http://www.exabot.com/go/robot)", "ua" : "Mozilla/5.0 (compatible; Exabot/3.0; +http://www.exabot.com/go/robot)",
@ -409,6 +559,36 @@
"type" : "crawler" "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", "desc" : "Googlebot-Video",
"ua" : "Googlebot-Video/1.0", "ua" : "Googlebot-Video/1.0",
@ -509,6 +689,16 @@
"type" : "crawler" "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", "desc" : "Google-Safety",
"ua" : "Google-Safety", "ua" : "Google-Safety",
@ -529,6 +719,16 @@
"type" : "crawler" "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", "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", "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" "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", "desc" : "Linespider",
"ua" : "Mozilla/5.0 (compatible; Linespider/1.1; +https://lin.ee/4dwXkTH)", "ua" : "Mozilla/5.0 (compatible; Linespider/1.1; +https://lin.ee/4dwXkTH)",
@ -579,6 +799,16 @@
"type" : "crawler" "type" : "crawler"
} }
}, },
{
"desc" : "Marginalia Search",
"ua" : "search.marginalia.nu",
"expect" :
{
"name" : "marginalia",
"version" : "undefined",
"type" : "crawler"
}
},
{ {
"desc" : "Meta-ExternalAgent", "desc" : "Meta-ExternalAgent",
"ua" : "meta-externalagent/1.1 (+https://developers.facebook.com/docs/sharing/webmasters/crawler)", "ua" : "meta-externalagent/1.1 (+https://developers.facebook.com/docs/sharing/webmasters/crawler)",
@ -610,6 +840,16 @@
"type" : "crawler" "type" : "crawler"
} }
}, },
{
"desc" : "msnbot",
"ua" : "msnbot/2.0b (+http://search.msn.com/msnbot.htm)",
"expect" :
{
"name" : "msnbot",
"version" : "2.0b",
"type" : "crawler"
}
},
{ {
"desc" : "Omgili", "desc" : "Omgili",
"ua" : "omgili/0.5 +https://omgili.com", "ua" : "omgili/0.5 +https://omgili.com",
@ -630,6 +870,16 @@
"type" : "crawler" "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", "desc" : "Onespot",
"ua" : "Mozilla/5.0 (compatible; Onespot-ScraperBot/1.0; +https://www.onespot.com/identifying-traffic.html)", "ua" : "Mozilla/5.0 (compatible; Onespot-ScraperBot/1.0; +https://www.onespot.com/identifying-traffic.html)",
@ -650,6 +900,16 @@
"type" : "crawler" "type" : "crawler"
} }
}, },
{
"desc" : "PanguBot",
"ua" : "Mozilla/5.0 (compatible; PanguBot/1.0)",
"expect" :
{
"name" : "PanguBot",
"version" : "1.0",
"type" : "crawler"
}
},
{ {
"desc" : "PerplexityBot", "desc" : "PerplexityBot",
"ua" : "Mozilla/5.0 AppleWebKit/537.36 (KHTML, like Gecko; compatible; PerplexityBot/1.0; +https://perplexity.ai/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" "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", "desc" : "SemrushBot",
"ua" : "Mozilla/5.0 (compatible; SemrushBot/7~bl; +http://www.semrush.com/bot.html)", "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)", "ua" : "Sogou web spider/4.0(+http://www.sogou.com/docs/help/webmasters.htm#07)",
"expect" : "expect" :
{ {
@ -790,6 +1110,16 @@
"type" : "crawler" "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", "desc" : "Timpibot",
"ua" : "Timpibot/0.8 (+http://www.timpi.io)", "ua" : "Timpibot/0.8 (+http://www.timpi.io)",
@ -800,6 +1130,16 @@
"type" : "crawler" "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", "desc" : "TurnitinBot",
"ua" : "TurnitinBot (https://turnitin.com/robot/crawlerinfo.html)", "ua" : "TurnitinBot (https://turnitin.com/robot/crawlerinfo.html)",
@ -810,6 +1150,26 @@
"type" : "crawler" "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", "desc" : "VelenPublicWebCrawler",
"ua" : "Mozilla/5.0 (compatible; VelenPublicWebCrawler/1.0; +https://velen.io)", "ua" : "Mozilla/5.0 (compatible; VelenPublicWebCrawler/1.0; +https://velen.io)",
@ -820,6 +1180,36 @@
"type" : "crawler" "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", "desc" : "Yahoo! Japan",
"ua" : "Y!J-BRW/1.0 (https://www.yahoo-help.jp/app/answers/detail/p/595/a_id/42716)", "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" "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", "desc" : "YandexBot",
"ua" : "Mozilla/5.0 (compatible; YandexBot/3.0; +http://yandex.com/bots)", "ua" : "Mozilla/5.0 (compatible; YandexBot/3.0; +http://yandex.com/bots)",
@ -850,6 +1280,256 @@
"type" : "crawler" "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", "desc" : "Yeti",
"ua" : "Mozilla/5.0 (compatible; Yeti/1.1; +http://naver.me/spd)", "ua" : "Mozilla/5.0 (compatible; Yeti/1.1; +http://naver.me/spd)",
@ -889,5 +1569,15 @@
"version" : "undefined", "version" : "undefined",
"type" : "crawler" "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" "type" : "fetcher"
} }
}, },
{
"desc" : "Asana",
"ua" : "Asana/1.4.0 WebsiteMetadataRetriever",
"expect" :
{
"name" : "Asana",
"version" : "1.4.0",
"type" : "fetcher"
}
},
{ {
"desc" : "Better Uptime Bot", "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", "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" "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", "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", "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" "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", "desc" : "ChatGPT-User",
"ua" : "Mozilla/5.0 AppleWebKit/537.36 (KHTML, like Gecko); compatible; ChatGPT-User/1.0; +https://openai.com/bot", "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" "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", "desc" : "DuckAssistBot",
"ua" : "DuckAssistBot/1.2; (+http://duckduckgo.com/duckassistbot.html)", "ua" : "DuckAssistBot/1.2; (+http://duckduckgo.com/duckassistbot.html)",
@ -59,6 +129,16 @@
"type" : "fetcher" "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", "desc" : "Google FeedFetcher",
"ua" : "FeedFetcher-Google; (+http://www.google.com/feedfetcher.html)", "ua" : "FeedFetcher-Google; (+http://www.google.com/feedfetcher.html)",
@ -129,6 +209,16 @@
"type" : "fetcher" "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", "desc" : "Iframely",
"ua" : "Iframely/1.3.1 (+https://iframely.com/docs/about)", "ua" : "Iframely/1.3.1 (+https://iframely.com/docs/about)",
@ -139,6 +229,16 @@
"type" : "fetcher" "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", "desc" : "Meta-ExternalFetcher",
"ua" : "meta-externalfetcher/1.1 (+https://developers.facebook.com/docs/sharing/webmasters/crawler)", "ua" : "meta-externalfetcher/1.1 (+https://developers.facebook.com/docs/sharing/webmasters/crawler)",
@ -249,6 +349,26 @@
"type" : "fetcher" "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", "desc" : "Vercelbot",
"ua" : "Vercelbot (+https://vercel.com)", "ua" : "Vercelbot (+https://vercel.com)",
@ -259,6 +379,26 @@
"type" : "fetcher" "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", "desc" : "WhatsApp",
"ua" : "WhatsApp/2.23.20.0", "ua" : "WhatsApp/2.23.20.0",
@ -268,5 +408,105 @@
"version" : "2.23.20.0", "version" : "2.23.20.0",
"type" : "fetcher" "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 { 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'; import * as assert from 'assert';
describe('Returns', () => { describe('Returns', () => {
@ -19,8 +19,8 @@ describe('Returns', () => {
describe('Enums', () => { describe('Enums', () => {
it('Can use enum', () => { 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'); 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(cpu.is(CPUArch.ARM), true);
assert.strictEqual(device.is(Device.MOBILE), true); assert.strictEqual(device.is(DeviceType.MOBILE), true);
assert.strictEqual(engine.is(Engine.GECKO), 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 safe = require('safe-regex');
const { UAParser } = require('../../src/main/ua-parser'); const { UAParser } = require('../../src/main/ua-parser');
const { Bots, CLIs, Crawlers, Emails, Fetchers, InApps, Libraries, Vehicles } = require('../../src/extensions/ua-parser-extensions'); 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', () => { 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 jsdom = 'Mozilla/5.0 (darwin) AppleWebKit/537.36 (KHTML, like Gecko) jsdom/20.0.3';
const scrapy = 'Scrapy/1.5.0 (+https://scrapy.org)'; 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); 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(outlook).getBrowser(), {name: Email.MICROSOFT_OUTLOOK, version: "16.0.9126", major: "16", type: BrowserType.EMAIL});
assert.deepEqual(emailParser.setUA(thunderbird).getBrowser(), {name: "Thunderbird", version: "78.13.0", major: "78", type: "email"}); assert.deepEqual(emailParser.setUA(thunderbird).getBrowser(), {name: Email.THUNDERBIRD, version: "78.13.0", major: "78", type: BrowserType.EMAIL});
const libraryParser = new UAParser(Libraries); 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(axios).getBrowser(), {name: Library.AXIOS, version: "1.3.5", major: "1", type: BrowserType.LIBRARY});
assert.deepEqual(libraryParser.setUA(jsdom).getBrowser(), {name: "jsdom", version: "20.0.3", major: "20", type: "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: "Scrapy", version: "1.5.0", major: "1", type: "library"}); assert.deepEqual(libraryParser.setUA(scrapy).getBrowser(), {name: Library.SCRAPY, version: "1.5.0", major: "1", type: BrowserType.LIBRARY});
// Bluesky // Bluesky
const bluesky = 'Mozilla/5.0 (compatible; Bluesky Cardyb/1.1; +mailto:support@bsky.app)'; const bluesky = 'Mozilla/5.0 (compatible; Bluesky Cardyb/1.1; +mailto:support@bsky.app)';
assert.deepEqual(new UAParser(bluesky, Bots).getBrowser(), { assert.deepEqual(new UAParser(bluesky, Bots).getBrowser(), {
name: 'Bluesky', name: Fetcher.BLUESKY,
version: '1.1', version: '1.1',
major: '1', major: '1',
type: 'fetcher' type: BrowserType.FETCHER
}); });
const whatsapp = "WhatsApp/2.0 A"; const whatsapp = "WhatsApp/2.0 A";
assert.deepEqual(new UAParser(whatsapp, Fetchers).getOS(), { assert.deepEqual(new UAParser(whatsapp, Fetchers).getOS(), {
name : 'Android', name : OSName.ANDROID,
version : undefined version : undefined
}); });
}); });
@ -77,14 +79,14 @@ describe('Merge', () => {
// try merging crawlers & CLIs // try merging crawlers & CLIs
const crawlersAndCLIs = { browser : [...Crawlers.browser, ...CLIs.browser]}; const crawlersAndCLIs = { browser : [...Crawlers.browser, ...CLIs.browser]};
const crawlersAndCLIsParser = new UAParser(crawlersAndCLIs); 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(wget).getBrowser(), {name: CLI.WGET, version: "1.21.1", major: "1", type: BrowserType.CLI});
assert.deepEqual(crawlersAndCLIsParser.setUA(facebookBot).getBrowser(), {name: "FacebookBot", version: "1.0", major: "1", type:"crawler"}); assert.deepEqual(crawlersAndCLIsParser.setUA(facebookBot).getBrowser(), {name: Crawler.META_FACEBOOKBOT, version: "1.0", major: "1", type: BrowserType.CRAWLER});
// alternative merge options // alternative merge options
const crawlersAndCLIsParser2 = new UAParser([Crawlers, CLIs]); const crawlersAndCLIsParser2 = new UAParser([Crawlers, CLIs]);
const crawlersAndCLIsParser3 = new UAParser(facebookBot, [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(crawlersAndCLIsParser2.setUA(wget).getBrowser(), {name: CLI.WGET, version: "1.21.1", major: "1", type: BrowserType.CLI});
assert.deepEqual(crawlersAndCLIsParser3.getBrowser(), {name: "FacebookBot", version: "1.0", major: "1", type:"crawler"}); 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 { UAParser } = require('../../src/main/ua-parser');
const { getDeviceVendor, isAppleSilicon, isAIBot, isBot, isChromeFamily } = require('../../src/helpers/ua-parser-helpers'); const { getDeviceVendor, isAppleSilicon, isAIBot, isBot, isChromeFamily } = require('../../src/helpers/ua-parser-helpers');
const { Bots, Emails } = require('../../src/extensions/ua-parser-extensions'); const { Bots, Emails } = require('../../src/extensions/ua-parser-extensions');
const { DeviceVendor } = require('../../src/enums/ua-parser-enums');
describe('getDeviceVendor', () => { describe('getDeviceVendor', () => {
it('Can guess the device vendor from a model name', () => { it('Can guess the device vendor from a model name', () => {
@ -11,10 +12,10 @@ describe('getDeviceVendor', () => {
const modelNexus = 'Nexus 6P'; const modelNexus = 'Nexus 6P';
const modelAquos = 'AQUOS-TVX19B'; const modelAquos = 'AQUOS-TVX19B';
assert.equal(getDeviceVendor(modelSM), 'Samsung'); assert.equal(getDeviceVendor(modelSM), DeviceVendor.SAMSUNG);
assert.equal(getDeviceVendor(modelRedmi), 'Xiaomi'); assert.equal(getDeviceVendor(modelRedmi), DeviceVendor.XIAOMI);
assert.equal(getDeviceVendor(modelNexus), 'Huawei'); assert.equal(getDeviceVendor(modelNexus), DeviceVendor.HUAWEI);
assert.equal(getDeviceVendor(modelAquos), 'Sharp'); 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 devices = readJsonFiles('test/data/ua/device');
var engines = require('../data/ua/engine/engine-all.json'); var engines = require('../data/ua/engine/engine-all.json');
var os = readJsonFiles('test/data/ua/os'); var os = readJsonFiles('test/data/ua/os');
var { Headers } = require('node-fetch'); var { Headers } = require('undici');
function readJsonFiles(dir) { function readJsonFiles(dir) {
var list = []; var list = [];
@ -91,6 +91,34 @@ describe('Returns', function () {
}); });
done(); 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 () { describe('Extending Regex', function () {
@ -353,4 +381,18 @@ describe('Read user-agent data from req.headers', function () {
const { browser } = UAParser(reqHeaders); const { browser } = UAParser(reqHeaders);
assert.strictEqual(browser.is('Midori'), true); 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 assert = require('assert');
const { UAParser } = require('../../src/main/ua-parser'); 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', () => { describe('Map UA-CH headers', () => {
@ -25,27 +27,27 @@ describe('Map UA-CH headers', () => {
it('Can read from client-hints headers using `withClientHints()`', () => { 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.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.version, "93.0.1.2");
assert.strictEqual(uap.browser.major, "93"); 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.version, "93.0.1.2");
assert.strictEqual(browser.major, "93"); assert.strictEqual(browser.major, "93");
assert.strictEqual(uap.cpu.architecture, "arm64"); assert.strictEqual(uap.cpu.architecture, CPUArch.ARM_64);
assert.strictEqual(cpu.architecture, "arm64"); assert.strictEqual(cpu.architecture, CPUArch.ARM_64);
assert.strictEqual(uap.device.type, "mobile"); assert.strictEqual(uap.device.type, DeviceType.MOBILE);
assert.strictEqual(uap.device.model, "Pixel 99"); assert.strictEqual(uap.device.model, "Pixel 99");
assert.strictEqual(uap.device.vendor, "Google"); assert.strictEqual(uap.device.vendor, DeviceVendor.GOOGLE);
assert.strictEqual(device.type, "mobile"); assert.strictEqual(device.type, DeviceType.MOBILE);
assert.strictEqual(device.model, "Pixel 99"); assert.strictEqual(device.model, "Pixel 99");
assert.strictEqual(device.vendor, "Google"); assert.strictEqual(device.vendor, DeviceVendor.GOOGLE);
assert.strictEqual(uap.engine.name, 'Blink'); assert.strictEqual(uap.engine.name, EngineName.BLINK);
assert.strictEqual(uap.engine.version, '93.0.1.2'); 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(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(uap.os.version, "11");
assert.strictEqual(os.name, "Windows"); assert.strictEqual(os.name, OSName.WINDOWS);
assert.strictEqual(os.version, "11"); assert.strictEqual(os.version, "11");
}); });
@ -58,16 +60,16 @@ describe('Map UA-CH headers', () => {
engine = new UAParser(headers).getEngine(); engine = new UAParser(headers).getEngine();
os = new UAParser(headers).getOS(); 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.version, "110.0.0.0");
assert.strictEqual(uap.browser.major, "110"); 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.type, undefined);
assert.strictEqual(uap.device.model, undefined); assert.strictEqual(uap.device.model, undefined);
assert.strictEqual(uap.device.vendor, 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.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); assert.strictEqual(uap.os.version, undefined);
}); });
@ -80,16 +82,16 @@ describe('Map UA-CH headers', () => {
uap = UAParser(headers2).withClientHints(); 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.version, "110.0.0.0");
assert.strictEqual(uap.browser.major, "110"); 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, "mobile"); assert.strictEqual(uap.device.type, DeviceType.MOBILE);
assert.strictEqual(uap.device.model, undefined); assert.strictEqual(uap.device.model, undefined);
assert.strictEqual(uap.device.vendor, 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.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); 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.os.is(OSName.MACOS), true);
assert.strictEqual(ua.cpu.is("arm"), true); assert.strictEqual(ua.cpu.is(CPUArch.ARM), true);
assert.strictEqual(ua.device.is("mobile"), false); assert.strictEqual(ua.device.is(DeviceType.MOBILE), false);
assert.strictEqual(ua.device.is("tablet"), false); assert.strictEqual(ua.device.is(DeviceType.TABLET), false);
}); });
}); });
@ -138,11 +140,11 @@ describe('Map UA-CH headers', () => {
}; };
UAParser(FFVR).withClientHints().then(ua => { UAParser(FFVR).withClientHints().then(ua => {
assert.strictEqual(ua.device.type, 'xr'); assert.strictEqual(ua.device.type, DeviceType.XR);
}); });
UAParser(FFEInk).withClientHints().then(ua => { 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(); 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.version, undefined);
assert.strictEqual(uap.browser.major, undefined); assert.strictEqual(uap.browser.major, undefined);
}); });
@ -195,429 +197,208 @@ describe('Map UA-CH headers', () => {
}; };
uap = UAParser(headers3a).withClientHints(); 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"); assert.strictEqual(uap.browser.version, "120.0.6099.132");
uap = UAParser(headers3b).withClientHints(); 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"); assert.strictEqual(uap.browser.version, "120.0.6099.132");
uap = UAParser(headers3c).withClientHints(); 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"); assert.strictEqual(uap.browser.version, "120.0.6099.132");
uap = UAParser(headers3d).withClientHints(); 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"); assert.strictEqual(uap.browser.version, "120.0.6099.133");
uap = UAParser(headers3e).withClientHints(); 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"); assert.strictEqual(uap.browser.version, "120.0.6099.133");
uap = UAParser(headers3f).withClientHints(); 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"); assert.strictEqual(uap.browser.version, "120.0.6099.133");
}); });
}); });
describe('UA-CH Headers tests', () => { describe('UA-CH Headers tests', () => {
[ UACHTests.forEach(test => {
{ it(`Test for ${test.desc}`, () => {
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 => {
const { browser } = UAParser(test.headers).withClientHints(); const { browser } = UAParser(test.headers).withClientHints();
assert.deepEqual(browser, test.expect.browser); assert.deepEqual(browser, test.expect.browser);
}); });
}); });
});
describe('Identify vendor & type of device from given model name', () => { describe('Identify vendor & type of device from given model name', () => {
[ [
{ {
model: '220733SG', model: '220733SG',
expect: { expect: {
vendor : 'Xiaomi', vendor : DeviceVendor.XIAOMI,
type : 'mobile' type : DeviceType.MOBILE
} }
}, },
{ {
model: '5087Z', model: '5087Z',
expect: { expect: {
vendor : 'TCL', vendor : DeviceVendor.TCL,
type : 'mobile' type : DeviceType.MOBILE
} }
}, },
{ {
model: '9137W', model: '9137W',
expect: { expect: {
vendor : 'TCL', vendor : DeviceVendor.TCL,
type : 'tablet' type : DeviceType.TABLET
} }
}, },
{ {
model: 'BE2015', model: 'BE2015',
expect: { expect: {
vendor : 'OnePlus', vendor : DeviceVendor.ONEPLUS,
type : 'mobile' type : DeviceType.MOBILE
} }
}, },
{ {
model: 'CPH2389', model: 'CPH2389',
expect: { expect: {
vendor : 'OnePlus', vendor : DeviceVendor.ONEPLUS,
type : 'mobile' type : DeviceType.MOBILE
} }
}, },
{ {
model: 'Infinix X669C', model: 'Infinix X669C',
expect: { expect: {
vendor : 'Infinix', vendor : DeviceVendor.INFINIX,
type : 'mobile' type : DeviceType.MOBILE
} }
}, },
{ {
model: 'itel L6502', model: 'itel L6502',
expect: { expect: {
vendor : 'itel', vendor : DeviceVendor.ITEL,
type : 'mobile' type : DeviceType.MOBILE
} }
}, },
{ {
model: 'Lenovo TB-X606F', model: 'Lenovo TB-X606F',
expect: { expect: {
vendor : 'Lenovo', vendor : DeviceVendor.LENOVO,
type : 'tablet' type : DeviceType.TABLET
} }
}, },
{ {
model: 'LM-Q720', model: 'LM-Q720',
expect: { expect: {
vendor : 'LG', vendor : DeviceVendor.LG,
type : 'mobile' type : DeviceType.MOBILE
} }
}, },
{ {
model: 'M2003J15SC', model: 'M2003J15SC',
expect: { expect: {
vendor : 'Xiaomi', vendor : DeviceVendor.XIAOMI,
type : 'mobile' type : DeviceType.MOBILE
} }
}, },
{ {
model: 'MAR-LX1A', model: 'MAR-LX1A',
expect: { expect: {
vendor : 'Huawei', vendor : DeviceVendor.HUAWEI,
type : 'mobile' type : DeviceType.MOBILE
} }
}, },
{ {
model: 'moto g(20)', model: 'moto g(20)',
expect: { expect: {
vendor : 'Motorola', vendor : DeviceVendor.MOTOROLA,
type : 'mobile' type : DeviceType.MOBILE
} }
}, },
{ {
model: 'Nokia C210', model: 'Nokia C210',
expect: { expect: {
vendor : 'Nokia', vendor : DeviceVendor.NOKIA,
type : 'mobile' type : DeviceType.MOBILE
} }
}, },
{ {
model: 'Pixel 8', model: 'Pixel 8',
expect: { expect: {
vendor : 'Google', vendor : DeviceVendor.GOOGLE,
type : 'mobile' type : DeviceType.MOBILE
} }
}, },
{ {
model: 'Redmi Note 9S', model: 'Redmi Note 9S',
expect: { expect: {
vendor : 'Xiaomi', vendor : DeviceVendor.XIAOMI,
type : 'mobile' type : DeviceType.MOBILE
} }
}, },
{ {
model: 'RMX3830', model: 'RMX3830',
expect: { expect: {
vendor : 'Realme', vendor : DeviceVendor.REALME,
type : 'mobile' type : DeviceType.MOBILE
} }
}, },
{ {
model: 'SM-S536DL', model: 'SM-S536DL',
expect: { expect: {
vendor : 'Samsung', vendor : DeviceVendor.SAMSUNG,
type : 'mobile' type : DeviceType.MOBILE
} }
}, },
{ {
model: 'SM-S546VL', model: 'SM-S546VL',
expect: { expect: {
vendor : 'Samsung', vendor : DeviceVendor.SAMSUNG,
type : 'mobile' type : DeviceType.MOBILE
} }
}, },
{ {
model: 'SM-T875', model: 'SM-T875',
expect: { expect: {
vendor : 'Samsung', vendor : DeviceVendor.SAMSUNG,
type : 'tablet' type : DeviceType.TABLET
} }
}, },
{ {
model: 'STK-L21', model: 'STK-L21',
expect: { expect: {
vendor : 'Huawei', vendor : DeviceVendor.HUAWEI,
type : 'mobile' type : DeviceType.MOBILE
} }
}, },
{ {
model: 'T430W', model: 'T430W',
expect: { expect: {
vendor : 'TCL', vendor : DeviceVendor.TCL,
type : 'mobile' type : DeviceType.MOBILE
} }
}, },
{ {
model: 'TECNO KI5k', model: 'TECNO KI5k',
expect: { expect: {
vendor : 'TECNO', vendor : DeviceVendor.TECNO,
type : 'mobile' type : DeviceType.MOBILE
} }
}, },
{ {
model: 'vivo 1820', model: 'vivo 1820',
expect: { expect: {
vendor : 'Vivo', vendor : DeviceVendor.VIVO,
type : 'mobile' type : DeviceType.MOBILE
} }
}, },
{ {
model: 'Xbox', model: 'Xbox',
expect: { expect: {
vendor : 'Microsoft', vendor : DeviceVendor.MICROSOFT,
type : 'console' type : DeviceType.CONSOLE
} }
} }
] ]