mirror of
https://github.com/faisalman/ua-parser-js.git
synced 2025-11-15 14:42:16 +03:00
Compare commits
11 Commits
pro-enterp
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5a5b321347 | ||
|
|
e9f78ceb80 | ||
|
|
38301f8803 | ||
|
|
e5648826b9 | ||
|
|
a558cc1a5b | ||
|
|
cb9b50a81a | ||
|
|
042c57cc10 | ||
|
|
232fb321f1 | ||
|
|
a3a7a5e377 | ||
|
|
2d8c8fa142 | ||
|
|
d84ba1888b |
@@ -5,7 +5,7 @@
|
|||||||
---
|
---
|
||||||
|
|
||||||
[](https://uaparser.dev)
|
[](https://uaparser.dev)
|
||||||
[](https://uaparser.dev)
|
[](https://uaparser.dev)
|
||||||
[](https://uaparser.dev)
|
[](https://uaparser.dev)
|
||||||
[](https://uaparser.dev)
|
[](https://uaparser.dev)
|
||||||
|
|
||||||
@@ -277,4 +277,4 @@ Support the **open-source editions** of UAParser.js through one of the following
|
|||||||
)](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/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>
|
<a href="https://opencollective.com/ua-parser-js"><img src="https://opencollective.com/ua-parser-js/individuals.svg?avatarHeight=64"></a>
|
||||||
|
|||||||
15
package.json
15
package.json
@@ -190,6 +190,21 @@
|
|||||||
"import": "./src/main/ua-parser.mjs",
|
"import": "./src/main/ua-parser.mjs",
|
||||||
"types": "./src/main/ua-parser.d.ts"
|
"types": "./src/main/ua-parser.d.ts"
|
||||||
},
|
},
|
||||||
|
"./bot-detection": {
|
||||||
|
"require": "./src/bot-detection/bot-detection.js",
|
||||||
|
"import": "./src/bot-detection/bot-detection.mjs",
|
||||||
|
"types": "./src/bot-detection/bot-detection.d.ts"
|
||||||
|
},
|
||||||
|
"./browser-detection": {
|
||||||
|
"require": "./src/browser-detection/browser-detection.js",
|
||||||
|
"import": "./src/browser-detection/browser-detection.mjs",
|
||||||
|
"types": "./src/browser-detection/browser-detection.d.ts"
|
||||||
|
},
|
||||||
|
"./device-detection": {
|
||||||
|
"require": "./src/device-detection/device-detection.js",
|
||||||
|
"import": "./src/device-detection/device-detection.mjs",
|
||||||
|
"types": "./src/device-detection/device-detection.d.ts"
|
||||||
|
},
|
||||||
"./enums": {
|
"./enums": {
|
||||||
"require": "./src/enums/ua-parser-enums.js",
|
"require": "./src/enums/ua-parser-enums.js",
|
||||||
"import": "./src/enums/ua-parser-enums.mjs",
|
"import": "./src/enums/ua-parser-enums.mjs",
|
||||||
|
|||||||
@@ -40,6 +40,24 @@ const files = [
|
|||||||
...defaultReplacements.mjs
|
...defaultReplacements.mjs
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
src : 'src/bot-detection/bot-detection.js',
|
||||||
|
dest :'src/bot-detection/bot-detection.mjs',
|
||||||
|
title : 'Generated ESM version of ua-parser-js/bot-detection',
|
||||||
|
replacements : [...defaultReplacements.mjs]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
src : 'src/browser-detection/browser-detection.js',
|
||||||
|
dest :'src/browser-detection/browser-detection.mjs',
|
||||||
|
title : 'Generated ESM version of ua-parser-js/browser-detection',
|
||||||
|
replacements : [...defaultReplacements.mjs]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
src : 'src/device-detection/device-detection.js',
|
||||||
|
dest :'src/device-detection/device-detection.mjs',
|
||||||
|
title : 'Generated ESM version of ua-parser-js/device-detection',
|
||||||
|
replacements : [...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',
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ try {
|
|||||||
|
|
||||||
if (!process.argv[2].startsWith('-')) {
|
if (!process.argv[2].startsWith('-')) {
|
||||||
|
|
||||||
const results = process.argv.slice(2).map(ua => UAParser(ua));
|
const results = process.argv.slice(2).map(ua => UAParser(ua, [Bots, Emails, ExtraDevices, InApps, Vehicles]));
|
||||||
console.log(JSON.stringify(results, null, 4));
|
console.log(JSON.stringify(results, null, 4));
|
||||||
process.exit(0);
|
process.exit(0);
|
||||||
|
|
||||||
|
|||||||
7
src/bot-detection/bot-detection.d.ts
vendored
Normal file
7
src/bot-detection/bot-detection.d.ts
vendored
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
// Type definitions for bot-detection submodule of UAParser.js v2.0.7
|
||||||
|
// Project: https://github.com/faisalman/ua-parser-js
|
||||||
|
// Definitions by: Faisal Salman <https://github.com/faisalman>
|
||||||
|
|
||||||
|
export function isAIAssistant(ua: string): boolean;
|
||||||
|
export function isAICrawler(ua: string): boolean;
|
||||||
|
export function isBot(ua: string): boolean;
|
||||||
188
src/bot-detection/bot-detection.js
Normal file
188
src/bot-detection/bot-detection.js
Normal file
@@ -0,0 +1,188 @@
|
|||||||
|
//////////////////////////////////////////////////
|
||||||
|
/* bot-detection submodule of UAParser.js v2.0.7
|
||||||
|
https://github.com/faisalman/ua-parser-js
|
||||||
|
Author: Faisal Salman <f@faisalman.com>
|
||||||
|
AGPLv3 License */
|
||||||
|
/////////////////////////////////////////////////
|
||||||
|
|
||||||
|
/*jshint esversion: 6 */
|
||||||
|
|
||||||
|
const { UAParser } = require('../main/ua-parser');
|
||||||
|
const { Bots, Crawlers, Fetchers } = require('../extensions/ua-parser-extensions');
|
||||||
|
const { BrowserType, Extension } = require('../enums/ua-parser-enums');
|
||||||
|
const { Crawler, Fetcher } = Extension.BrowserName;
|
||||||
|
|
||||||
|
class BotList {
|
||||||
|
constructor(ext, prop, list) {
|
||||||
|
this.ext = ext;
|
||||||
|
this.prop = prop;
|
||||||
|
this.list = list.map(x => x.toLowerCase());
|
||||||
|
}
|
||||||
|
includes(ua) {
|
||||||
|
return this.list.includes(
|
||||||
|
(typeof ua === 'string' ?
|
||||||
|
new UAParser(ua, this.ext).getBrowser() :
|
||||||
|
ua.browser
|
||||||
|
)[this.prop]?.toLowerCase());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const BotTypes = new BotList(Bots, 'type', [
|
||||||
|
BrowserType.CLI,
|
||||||
|
BrowserType.CRAWLER,
|
||||||
|
BrowserType.FETCHER,
|
||||||
|
BrowserType.LIBRARY
|
||||||
|
]);
|
||||||
|
|
||||||
|
const AIAssistants = new BotList(Fetchers, 'name', [
|
||||||
|
|
||||||
|
// Amazon
|
||||||
|
Fetcher.AMAZON_NOVA_ACT,
|
||||||
|
|
||||||
|
// Anthropic
|
||||||
|
Fetcher.ANTHROPIC_CLAUDE_USER,
|
||||||
|
|
||||||
|
// Cohere
|
||||||
|
Fetcher.COHERE_AI,
|
||||||
|
|
||||||
|
// DuckDuckGo
|
||||||
|
Fetcher.DUCKDUCKGO_ASSISTBOT,
|
||||||
|
|
||||||
|
// Google
|
||||||
|
Fetcher.GOOGLE_GEMINI_DEEP_RESEARCH,
|
||||||
|
|
||||||
|
// Mistral AI
|
||||||
|
Fetcher.MISTRALAI_USER,
|
||||||
|
|
||||||
|
// OpenAI
|
||||||
|
Fetcher.OPENAI_CHATGPT_USER,
|
||||||
|
|
||||||
|
// Perplexity
|
||||||
|
Fetcher.PERPLEXITY_USER
|
||||||
|
]);
|
||||||
|
|
||||||
|
const AICrawlers = new BotList(Crawlers, 'name', [
|
||||||
|
|
||||||
|
// AI2
|
||||||
|
Crawler.AI2_BOT,
|
||||||
|
|
||||||
|
// Amazon
|
||||||
|
Crawler.AMAZON_BOT,
|
||||||
|
|
||||||
|
// Anthropic
|
||||||
|
Crawler.ANTHROPIC_AI,
|
||||||
|
Crawler.ANTHROPIC_CLAUDE_BOT,
|
||||||
|
Crawler.ANTHROPIC_CLAUDE_SEARCHBOT,
|
||||||
|
Crawler.ANTHROPIC_CLAUDE_WEB,
|
||||||
|
|
||||||
|
// Apple
|
||||||
|
Crawler.APPLE_BOT,
|
||||||
|
Crawler.APPLE_BOT_EXTENDED,
|
||||||
|
|
||||||
|
// Brave
|
||||||
|
Crawler.BRAVE_BOT,
|
||||||
|
|
||||||
|
// ByteDance
|
||||||
|
Crawler.BYTEDANCE_BYTESPIDER,
|
||||||
|
Crawler.BYTEDANCE_TIKTOKSPIDER,
|
||||||
|
|
||||||
|
// Cohere
|
||||||
|
Crawler.COHERE_TRAINING_DATA_CRAWLER,
|
||||||
|
|
||||||
|
// Common Crawl
|
||||||
|
Crawler.COMMON_CRAWL_CCBOT,
|
||||||
|
|
||||||
|
// Coveo
|
||||||
|
Crawler.COVEO_BOT,
|
||||||
|
|
||||||
|
// DataForSeo
|
||||||
|
Crawler.DATAFORSEO_BOT,
|
||||||
|
|
||||||
|
// DeepSeek
|
||||||
|
Crawler.DEEPSEEK_BOT,
|
||||||
|
|
||||||
|
// Diffbot
|
||||||
|
Crawler.DIFFBOT,
|
||||||
|
|
||||||
|
// Google
|
||||||
|
Crawler.GOOGLE_EXTENDED,
|
||||||
|
Crawler.GOOGLE_OTHER,
|
||||||
|
Crawler.GOOGLE_OTHER_IMAGE,
|
||||||
|
Crawler.GOOGLE_OTHER_VIDEO,
|
||||||
|
Crawler.GOOGLE_CLOUDVERTEXBOT,
|
||||||
|
|
||||||
|
// Hive AI
|
||||||
|
Crawler.HIVE_IMAGESIFTBOT,
|
||||||
|
|
||||||
|
// Huawei
|
||||||
|
Crawler.HUAWEI_PETALBOT,
|
||||||
|
Crawler.HUAWEI_PANGUBOT,
|
||||||
|
|
||||||
|
// Hugging Face
|
||||||
|
Crawler.HUGGINGFACE_BOT,
|
||||||
|
|
||||||
|
// Kangaroo
|
||||||
|
Crawler.KANGAROO_BOT,
|
||||||
|
|
||||||
|
// Mendable.ai
|
||||||
|
Crawler.FIRECRAWL_AGENT,
|
||||||
|
|
||||||
|
// Meta
|
||||||
|
Crawler.META_FACEBOOKBOT,
|
||||||
|
Crawler.META_EXTERNALAGENT,
|
||||||
|
|
||||||
|
// OpenAI
|
||||||
|
Crawler.OPENAI_GPTBOT,
|
||||||
|
Crawler.OPENAI_SEARCH_BOT,
|
||||||
|
|
||||||
|
// Perplexity
|
||||||
|
Crawler.PERPLEXITY_BOT,
|
||||||
|
|
||||||
|
// Replicate
|
||||||
|
Crawler.REPLICATE_BOT,
|
||||||
|
|
||||||
|
// Runpod
|
||||||
|
Crawler.RUNPOD_BOT,
|
||||||
|
|
||||||
|
// SB Intuitions
|
||||||
|
Crawler.SB_INTUITIONS_BOT,
|
||||||
|
|
||||||
|
// Semrush
|
||||||
|
Crawler.SEMRUSH_BOT_CONTENTSHAKE,
|
||||||
|
|
||||||
|
// Timpi
|
||||||
|
Crawler.TIMPI_BOT,
|
||||||
|
|
||||||
|
// Together AI
|
||||||
|
Crawler.TOGETHER_BOT,
|
||||||
|
|
||||||
|
// Velen.io
|
||||||
|
Crawler.HUNTER_VELENPUBLICWEBCRAWLER,
|
||||||
|
|
||||||
|
// Vercel
|
||||||
|
Crawler.VERCEL_V0BOT,
|
||||||
|
|
||||||
|
// Webz.io
|
||||||
|
Crawler.WEBZIO_OMGILI,
|
||||||
|
Crawler.WEBZIO_OMGILI_BOT,
|
||||||
|
Crawler.WEBZIO_EXTENDED,
|
||||||
|
|
||||||
|
// X
|
||||||
|
Crawler.XAI_BOT,
|
||||||
|
|
||||||
|
// You.com
|
||||||
|
Crawler.YOU_BOT,
|
||||||
|
|
||||||
|
// Zhipu AI
|
||||||
|
Crawler.ZHIPU_CHATGLM_SPIDER
|
||||||
|
]);
|
||||||
|
|
||||||
|
const isBot = ua => BotTypes.includes(ua);
|
||||||
|
const isAIAssistant = ua => AIAssistants.includes(ua);
|
||||||
|
const isAICrawler = ua => AICrawlers.includes(ua);
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
isAIAssistant,
|
||||||
|
isAICrawler,
|
||||||
|
isBot
|
||||||
|
}
|
||||||
189
src/bot-detection/bot-detection.mjs
Normal file
189
src/bot-detection/bot-detection.mjs
Normal file
@@ -0,0 +1,189 @@
|
|||||||
|
// Generated ESM version of ua-parser-js/bot-detection
|
||||||
|
// DO NOT EDIT THIS FILE!
|
||||||
|
// Source: /src/bot-detection/bot-detection.js
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////
|
||||||
|
/* bot-detection submodule of UAParser.js v2.0.7
|
||||||
|
https://github.com/faisalman/ua-parser-js
|
||||||
|
Author: Faisal Salman <f@faisalman.com>
|
||||||
|
AGPLv3 License */
|
||||||
|
/////////////////////////////////////////////////
|
||||||
|
|
||||||
|
/*jshint esversion: 6 */
|
||||||
|
|
||||||
|
import { UAParser } from '../main/ua-parser.mjs';
|
||||||
|
import { Extension, BrowserType } from '../enums/ua-parser-enums.mjs';
|
||||||
|
import { Bots, Crawlers, Fetchers } from '../extensions/ua-parser-extensions.mjs';
|
||||||
|
const { Crawler, Fetcher } = Extension.BrowserName;
|
||||||
|
|
||||||
|
class BotList {
|
||||||
|
constructor(ext, prop, list) {
|
||||||
|
this.ext = ext;
|
||||||
|
this.prop = prop;
|
||||||
|
this.list = list.map(x => x.toLowerCase());
|
||||||
|
}
|
||||||
|
includes(ua) {
|
||||||
|
return this.list.includes(
|
||||||
|
(typeof ua === 'string' ?
|
||||||
|
new UAParser(ua, this.ext).getBrowser() :
|
||||||
|
ua.browser
|
||||||
|
)[this.prop]?.toLowerCase());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const BotTypes = new BotList(Bots, 'type', [
|
||||||
|
BrowserType.CLI,
|
||||||
|
BrowserType.CRAWLER,
|
||||||
|
BrowserType.FETCHER,
|
||||||
|
BrowserType.LIBRARY
|
||||||
|
]);
|
||||||
|
|
||||||
|
const AIAssistants = new BotList(Fetchers, 'name', [
|
||||||
|
|
||||||
|
// Anthropic
|
||||||
|
Fetcher.ANTHROPIC_CLAUDE_USER,
|
||||||
|
|
||||||
|
// Cohere
|
||||||
|
Fetcher.COHERE_AI,
|
||||||
|
|
||||||
|
// DuckDuckGo
|
||||||
|
Fetcher.DUCKDUCKGO_ASSISTBOT,
|
||||||
|
|
||||||
|
// Google
|
||||||
|
Fetcher.GOOGLE_GEMINI_DEEP_RESEARCH,
|
||||||
|
|
||||||
|
// Mistral AI
|
||||||
|
Fetcher.MISTRALAI_USER,
|
||||||
|
|
||||||
|
// OpenAI
|
||||||
|
Fetcher.OPENAI_CHATGPT_USER,
|
||||||
|
|
||||||
|
// Perplexity
|
||||||
|
Fetcher.PERPLEXITY_USER
|
||||||
|
]);
|
||||||
|
|
||||||
|
const AICrawlers = new BotList(Crawlers, 'name', [
|
||||||
|
|
||||||
|
// AI2
|
||||||
|
Crawler.AI2_BOT,
|
||||||
|
|
||||||
|
// Amazon
|
||||||
|
Crawler.AMAZON_BOT,
|
||||||
|
|
||||||
|
// Anthropic
|
||||||
|
Crawler.ANTHROPIC_AI,
|
||||||
|
Crawler.ANTHROPIC_CLAUDE_BOT,
|
||||||
|
Crawler.ANTHROPIC_CLAUDE_SEARCHBOT,
|
||||||
|
Crawler.ANTHROPIC_CLAUDE_WEB,
|
||||||
|
|
||||||
|
// Apple
|
||||||
|
Crawler.APPLE_BOT,
|
||||||
|
Crawler.APPLE_BOT_EXTENDED,
|
||||||
|
|
||||||
|
// Brave
|
||||||
|
Crawler.BRAVE_BOT,
|
||||||
|
|
||||||
|
// ByteDance
|
||||||
|
Crawler.BYTEDANCE_BYTESPIDER,
|
||||||
|
Crawler.BYTEDANCE_TIKTOKSPIDER,
|
||||||
|
|
||||||
|
// Cohere
|
||||||
|
Crawler.COHERE_TRAINING_DATA_CRAWLER,
|
||||||
|
|
||||||
|
// Common Crawl
|
||||||
|
Crawler.COMMON_CRAWL_CCBOT,
|
||||||
|
|
||||||
|
// Coveo
|
||||||
|
Crawler.COVEO_BOT,
|
||||||
|
|
||||||
|
// DataForSeo
|
||||||
|
Crawler.DATAFORSEO_BOT,
|
||||||
|
|
||||||
|
// DeepSeek
|
||||||
|
Crawler.DEEPSEEK_BOT,
|
||||||
|
|
||||||
|
// Diffbot
|
||||||
|
Crawler.DIFFBOT,
|
||||||
|
|
||||||
|
// Google
|
||||||
|
Crawler.GOOGLE_EXTENDED,
|
||||||
|
Crawler.GOOGLE_OTHER,
|
||||||
|
Crawler.GOOGLE_OTHER_IMAGE,
|
||||||
|
Crawler.GOOGLE_OTHER_VIDEO,
|
||||||
|
Crawler.GOOGLE_CLOUDVERTEXBOT,
|
||||||
|
|
||||||
|
// Hive AI
|
||||||
|
Crawler.HIVE_IMAGESIFTBOT,
|
||||||
|
|
||||||
|
// Huawei
|
||||||
|
Crawler.HUAWEI_PETALBOT,
|
||||||
|
Crawler.HUAWEI_PANGUBOT,
|
||||||
|
|
||||||
|
// Hugging Face
|
||||||
|
Crawler.HUGGINGFACE_BOT,
|
||||||
|
|
||||||
|
// Kangaroo
|
||||||
|
Crawler.KANGAROO_BOT,
|
||||||
|
|
||||||
|
// Mendable.ai
|
||||||
|
Crawler.FIRECRAWL_AGENT,
|
||||||
|
|
||||||
|
// Meta
|
||||||
|
Crawler.META_FACEBOOKBOT,
|
||||||
|
Crawler.META_EXTERNALAGENT,
|
||||||
|
|
||||||
|
// OpenAI
|
||||||
|
Crawler.OPENAI_GPTBOT,
|
||||||
|
Crawler.OPENAI_SEARCH_BOT,
|
||||||
|
|
||||||
|
// Perplexity
|
||||||
|
Crawler.PERPLEXITY_BOT,
|
||||||
|
|
||||||
|
// Replicate
|
||||||
|
Crawler.REPLICATE_BOT,
|
||||||
|
|
||||||
|
// Runpod
|
||||||
|
Crawler.RUNPOD_BOT,
|
||||||
|
|
||||||
|
// SB Intuitions
|
||||||
|
Crawler.SB_INTUITIONS_BOT,
|
||||||
|
|
||||||
|
// Semrush
|
||||||
|
Crawler.SEMRUSH_BOT_CONTENTSHAKE,
|
||||||
|
|
||||||
|
// Timpi
|
||||||
|
Crawler.TIMPI_BOT,
|
||||||
|
|
||||||
|
// Together AI
|
||||||
|
Crawler.TOGETHER_BOT,
|
||||||
|
|
||||||
|
// Velen.io
|
||||||
|
Crawler.HUNTER_VELENPUBLICWEBCRAWLER,
|
||||||
|
|
||||||
|
// Vercel
|
||||||
|
Crawler.VERCEL_V0BOT,
|
||||||
|
|
||||||
|
// Webz.io
|
||||||
|
Crawler.WEBZIO_OMGILI,
|
||||||
|
Crawler.WEBZIO_OMGILI_BOT,
|
||||||
|
Crawler.WEBZIO_EXTENDED,
|
||||||
|
|
||||||
|
// X
|
||||||
|
Crawler.XAI_BOT,
|
||||||
|
|
||||||
|
// You.com
|
||||||
|
Crawler.YOU_BOT,
|
||||||
|
|
||||||
|
// Zhipu AI
|
||||||
|
Crawler.ZHIPU_CHATGLM_SPIDER
|
||||||
|
]);
|
||||||
|
|
||||||
|
const isBot = ua => BotTypes.includes(ua);
|
||||||
|
const isAIAssistant = ua => AIAssistants.includes(ua);
|
||||||
|
const isAICrawler = ua => AICrawlers.includes(ua);
|
||||||
|
|
||||||
|
export {
|
||||||
|
isAIAssistant,
|
||||||
|
isAICrawler,
|
||||||
|
isBot
|
||||||
|
}
|
||||||
10
src/browser-detection/browser-detection.d.ts
vendored
Normal file
10
src/browser-detection/browser-detection.d.ts
vendored
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
// Type definitions for browser-detection submodule of UAParser.js v2.0.7
|
||||||
|
// Project: https://github.com/faisalman/ua-parser-js
|
||||||
|
// Definitions by: Faisal Salman <https://github.com/faisalman>
|
||||||
|
|
||||||
|
import type { IResult } from "../main/ua-parser";
|
||||||
|
|
||||||
|
export function isChromeFamily(resultOrUA: IResult | string): boolean;
|
||||||
|
export function isElectron(): boolean;
|
||||||
|
export function isFromEU(): boolean;
|
||||||
|
export function isStandalonePWA(): boolean;
|
||||||
30
src/browser-detection/browser-detection.js
Normal file
30
src/browser-detection/browser-detection.js
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
//////////////////////////////////////////////////////
|
||||||
|
/* browser-detection submodule of UAParser.js v2.0.7
|
||||||
|
https://github.com/faisalman/ua-parser-js
|
||||||
|
Author: Faisal Salman <f@faisalman.com>
|
||||||
|
AGPLv3 License */
|
||||||
|
/////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
/*jshint esversion: 6 */
|
||||||
|
|
||||||
|
const { UAParser } = require('../main/ua-parser');
|
||||||
|
const { EngineName } = require('../enums/ua-parser-enums');
|
||||||
|
const { isStandalonePWA } = require('is-standalone-pwa');
|
||||||
|
const { isFromEU } = require('detect-europe-js');
|
||||||
|
|
||||||
|
const isChromeFamily = val => !!(
|
||||||
|
(typeof val === 'string' ?
|
||||||
|
new UAParser(val).getEngine() :
|
||||||
|
val.engine
|
||||||
|
)?.is(EngineName.BLINK));
|
||||||
|
|
||||||
|
const isElectron = () => !!(
|
||||||
|
process?.versions?.hasOwnProperty('electron') || // node.js
|
||||||
|
/ electron\//i.test(navigator?.userAgent)); // browser
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
isChromeFamily,
|
||||||
|
isElectron,
|
||||||
|
isFromEU,
|
||||||
|
isStandalonePWA
|
||||||
|
}
|
||||||
30
src/browser-detection/browser-detection.mjs
Normal file
30
src/browser-detection/browser-detection.mjs
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
// Generated ESM version of ua-parser-js/browser-detection
|
||||||
|
// DO NOT EDIT THIS FILE!
|
||||||
|
// Source: /src/browser-detection/browser-detection.js
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////
|
||||||
|
/* browser-detection submodule of UAParser.js v2.0.7
|
||||||
|
https://github.com/faisalman/ua-parser-js
|
||||||
|
Author: Faisal Salman <f@faisalman.com>
|
||||||
|
AGPLv3 License */
|
||||||
|
/////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
/*jshint esversion: 6 */
|
||||||
|
|
||||||
|
import { UAParser } from '../main/ua-parser.mjs';
|
||||||
|
import { isStandalonePWA } from 'is-standalone-pwa';
|
||||||
|
|
||||||
|
const isChromeFamily = val => !!(
|
||||||
|
(typeof val === 'string' ?
|
||||||
|
new UAParser(val).getEngine() :
|
||||||
|
val.engine
|
||||||
|
)?.is(EngineName.BLINK));
|
||||||
|
|
||||||
|
const isElectron = () => !!(process?.versions?.hasOwnProperty('electron') || // node.js
|
||||||
|
/ electron\//i.test(navigator?.userAgent)); // browser
|
||||||
|
|
||||||
|
export {
|
||||||
|
isChromeFamily,
|
||||||
|
isElectron,
|
||||||
|
isStandalonePWA
|
||||||
|
}
|
||||||
8
src/device-detection/device-detection.d.ts
vendored
Normal file
8
src/device-detection/device-detection.d.ts
vendored
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
// Type definitions for device-detection submodule of UAParser.js v2.0.7
|
||||||
|
// Project: https://github.com/faisalman/ua-parser-js
|
||||||
|
// Definitions by: Faisal Salman <https://github.com/faisalman>
|
||||||
|
|
||||||
|
import type { IResult } from "../main/ua-parser";
|
||||||
|
|
||||||
|
export function getDeviceVendor(model: string): string | undefined;
|
||||||
|
export function isAppleSilicon(resultOrUA: IResult | string): boolean;
|
||||||
43
src/device-detection/device-detection.js
Normal file
43
src/device-detection/device-detection.js
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
/////////////////////////////////////////////////////
|
||||||
|
/* device-detection submodule of UAParser.js v2.0.7
|
||||||
|
https://github.com/faisalman/ua-parser-js
|
||||||
|
Author: Faisal Salman <f@faisalman.com>
|
||||||
|
AGPLv3 License */
|
||||||
|
////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
/*jshint esversion: 6 */
|
||||||
|
|
||||||
|
const { UAParser } = require('../main/ua-parser');
|
||||||
|
const { CPUArch, OSName } = require('../enums/ua-parser-enums');
|
||||||
|
|
||||||
|
const getDeviceVendor = (model) => new UAParser(`Mozilla/5.0 (Linux; Android 10; ${model}) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/100.0.0.0 Safari/537.36`).getDevice().vendor;
|
||||||
|
|
||||||
|
const isAppleSilicon = (val) => {
|
||||||
|
const { os, cpu } = typeof val !== 'string' ? val : {
|
||||||
|
os: new UAParser(val).getOS(),
|
||||||
|
cpu: new UAParser(val).getCPU()
|
||||||
|
};
|
||||||
|
if (os.is(OSName.MACOS)) {
|
||||||
|
if (cpu.is(CPUArch.ARM)) {
|
||||||
|
return true;
|
||||||
|
} else if (typeof window !== 'undefined') {
|
||||||
|
try {
|
||||||
|
const canvas = document.createElement('canvas');
|
||||||
|
const webgl = canvas.getContext('webgl2') ||
|
||||||
|
canvas.getContext('webgl') ||
|
||||||
|
canvas.getContext('experimental-webgl');
|
||||||
|
return webgl
|
||||||
|
.getParameter(webgl.getExtension('WEBGL_debug_renderer_info').UNMASKED_RENDERER_WEBGL)
|
||||||
|
.match(/apple m\d/i);
|
||||||
|
} catch {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
getDeviceVendor,
|
||||||
|
isAppleSilicon
|
||||||
|
}
|
||||||
47
src/device-detection/device-detection.mjs
Normal file
47
src/device-detection/device-detection.mjs
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
// Generated ESM version of ua-parser-js/device-detection
|
||||||
|
// DO NOT EDIT THIS FILE!
|
||||||
|
// Source: /src/device-detection/device-detection.js
|
||||||
|
|
||||||
|
/////////////////////////////////////////////////////
|
||||||
|
/* device-detection submodule of UAParser.js v2.0.7
|
||||||
|
https://github.com/faisalman/ua-parser-js
|
||||||
|
Author: Faisal Salman <f@faisalman.com>
|
||||||
|
AGPLv3 License */
|
||||||
|
////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
/*jshint esversion: 6 */
|
||||||
|
|
||||||
|
import { UAParser } from '../main/ua-parser.mjs';
|
||||||
|
import { CPUArch, OSName } from '../enums/ua-parser-enums.mjs';
|
||||||
|
|
||||||
|
const getDeviceVendor = (model) => new UAParser(`Mozilla/5.0 (Linux; Android 10; ${model}) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/100.0.0.0 Safari/537.36`).getDevice().vendor;
|
||||||
|
|
||||||
|
const isAppleSilicon = (val) => {
|
||||||
|
const { os, cpu } = typeof val !== 'string' ? val : {
|
||||||
|
os: new UAParser(val).getOS(),
|
||||||
|
cpu: new UAParser(val).getCPU()
|
||||||
|
};
|
||||||
|
if (os.is(OSName.MACOS)) {
|
||||||
|
if (cpu.is(CPUArch.ARM)) {
|
||||||
|
return true;
|
||||||
|
} else if (typeof window !== 'undefined') {
|
||||||
|
try {
|
||||||
|
const canvas = document.createElement('canvas');
|
||||||
|
const webgl = canvas.getContext('webgl2') ||
|
||||||
|
canvas.getContext('webgl') ||
|
||||||
|
canvas.getContext('experimental-webgl');
|
||||||
|
return webgl
|
||||||
|
.getParameter(webgl.getExtension('WEBGL_debug_renderer_info').UNMASKED_RENDERER_WEBGL)
|
||||||
|
.match(/apple m\d/i);
|
||||||
|
} catch {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
export {
|
||||||
|
getDeviceVendor,
|
||||||
|
isAppleSilicon
|
||||||
|
}
|
||||||
@@ -15,6 +15,7 @@ const BrowserName = Object.freeze({
|
|||||||
AMAYA: 'Amaya',
|
AMAYA: 'Amaya',
|
||||||
ANDROID: 'Android Browser',
|
ANDROID: 'Android Browser',
|
||||||
ARORA: 'Arora',
|
ARORA: 'Arora',
|
||||||
|
ATLAS: 'Atlas',
|
||||||
AVANT: 'Avant',
|
AVANT: 'Avant',
|
||||||
AVAST: 'Avast Secure Browser',
|
AVAST: 'Avast Secure Browser',
|
||||||
AVG: 'AVG Secure Browser',
|
AVG: 'AVG Secure Browser',
|
||||||
@@ -224,8 +225,9 @@ const DeviceVendor = Object.freeze({
|
|||||||
ACER: 'Acer',
|
ACER: 'Acer',
|
||||||
ADVAN: 'Advan',
|
ADVAN: 'Advan',
|
||||||
ALCATEL: 'Alcatel',
|
ALCATEL: 'Alcatel',
|
||||||
APPLE: 'Apple',
|
|
||||||
AMAZON: 'Amazon',
|
AMAZON: 'Amazon',
|
||||||
|
ANBERNIC: 'Anbernic',
|
||||||
|
APPLE: 'Apple',
|
||||||
ARCHOS: 'Archos',
|
ARCHOS: 'Archos',
|
||||||
ASUS: 'ASUS',
|
ASUS: 'ASUS',
|
||||||
ATT: 'AT&T',
|
ATT: 'AT&T',
|
||||||
@@ -254,6 +256,7 @@ const DeviceVendor = Object.freeze({
|
|||||||
LAVA: 'Lava',
|
LAVA: 'Lava',
|
||||||
LENOVO: 'Lenovo',
|
LENOVO: 'Lenovo',
|
||||||
LG: 'LG',
|
LG: 'LG',
|
||||||
|
LOGITECH: 'Logitech',
|
||||||
MEIZU: 'Meizu',
|
MEIZU: 'Meizu',
|
||||||
MICROMAX: 'Micromax',
|
MICROMAX: 'Micromax',
|
||||||
MICROSOFT: 'Microsoft',
|
MICROSOFT: 'Microsoft',
|
||||||
@@ -627,6 +630,7 @@ const Extension = Object.freeze({
|
|||||||
},
|
},
|
||||||
Fetcher: {
|
Fetcher: {
|
||||||
AHREFS_SITEAUDIT: 'AhrefsSiteAudit',
|
AHREFS_SITEAUDIT: 'AhrefsSiteAudit',
|
||||||
|
AMAZON_NOVA_ACT: 'NovaAct',
|
||||||
ANTHROPIC_CLAUDE_USER: 'Claude-User',
|
ANTHROPIC_CLAUDE_USER: 'Claude-User',
|
||||||
ASANA: 'Asana',
|
ASANA: 'Asana',
|
||||||
BETTER_UPTIME_BOT: 'Better Uptime Bot',
|
BETTER_UPTIME_BOT: 'Better Uptime Bot',
|
||||||
@@ -704,9 +708,13 @@ const Extension = Object.freeze({
|
|||||||
AIOHTTP: 'aiohttp',
|
AIOHTTP: 'aiohttp',
|
||||||
APACHE_HTTPCLIENT: 'Apache-HttpClient',
|
APACHE_HTTPCLIENT: 'Apache-HttpClient',
|
||||||
AXIOS: 'axios',
|
AXIOS: 'axios',
|
||||||
|
BUN: 'Bun',
|
||||||
|
DART: 'Dart',
|
||||||
|
DENO: 'Deno',
|
||||||
GO_HTTP_CLIENT: 'go-http-client',
|
GO_HTTP_CLIENT: 'go-http-client',
|
||||||
GOT: 'got',
|
GOT: 'got',
|
||||||
GUZZLEHTTP: 'GuzzleHttp',
|
GUZZLEHTTP: 'GuzzleHttp',
|
||||||
|
HACKNEY: 'hackney',
|
||||||
JAVA: 'Java',
|
JAVA: 'Java',
|
||||||
JAVA_HTTPCLIENT: 'Java-http-client',
|
JAVA_HTTPCLIENT: 'Java-http-client',
|
||||||
JSDOM: 'jsdom',
|
JSDOM: 'jsdom',
|
||||||
@@ -714,16 +722,19 @@ const Extension = Object.freeze({
|
|||||||
LUA_RESTY_HTTP: 'lua-resty-http',
|
LUA_RESTY_HTTP: 'lua-resty-http',
|
||||||
NEEDLE: 'Needle',
|
NEEDLE: 'Needle',
|
||||||
NUTCH: 'Nutch',
|
NUTCH: 'Nutch',
|
||||||
OKHTTP: 'OkHttp',
|
|
||||||
NODE_FETCH: 'node-fetch',
|
NODE_FETCH: 'node-fetch',
|
||||||
|
NODE_JS: 'Node.js',
|
||||||
NODE_SUPERAGENT: 'node-superagent',
|
NODE_SUPERAGENT: 'node-superagent',
|
||||||
|
OKHTTP: 'OkHttp',
|
||||||
PHP_SOAP: 'PHP-SOAP',
|
PHP_SOAP: 'PHP-SOAP',
|
||||||
POSTMAN_RUNTIME: 'PostmanRuntime',
|
POSTMAN_RUNTIME: 'PostmanRuntime',
|
||||||
PYTHON_HTTPX: 'python-httpx',
|
PYTHON_HTTPX: 'python-httpx',
|
||||||
PYTHON_URLLIB: 'python-urllib',
|
PYTHON_URLLIB: 'python-urllib',
|
||||||
PYTHON_URLLIB3: 'python-urllib3',
|
PYTHON_URLLIB3: 'python-urllib3',
|
||||||
PYTHON_REQUESTS: 'python-requests',
|
PYTHON_REQUESTS: 'python-requests',
|
||||||
SCRAPY: 'Scrapy'
|
REST_CLIENT: 'rest-client',
|
||||||
|
SCRAPY: 'Scrapy',
|
||||||
|
UNDICI: 'undici'
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
DeviceVendor: {
|
DeviceVendor: {
|
||||||
|
|||||||
@@ -258,7 +258,7 @@ 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
|
// Asana / Bitlybot / Better Uptime / BingPreview / Blueno / Cohere-AI / HubSpot Page Fetcher / kakaotalk-scrap / Mastodon / MicrosoftPreview / Pinterestbot / Redditbot / Rogerbot / SiteAuditBot / Telegrambot / Twitterbot / UptimeRobot / WhatsApp
|
||||||
// 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
|
// 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
|
||||||
@@ -268,19 +268,19 @@ const Fetchers = Object.freeze({
|
|||||||
// 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
|
||||||
/(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,
|
/(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|whatsapp)\/([\w\.]+)/i,
|
||||||
|
|
||||||
// Bluesky
|
// Bluesky
|
||||||
/(bluesky) cardyb\/([\w\.]+)/i,
|
/(bluesky) cardyb\/([\w\.]+)/i,
|
||||||
|
|
||||||
|
// Nova Act - https://github.com/aws/nova-act
|
||||||
|
/agent-(novaact)\/([\w\.]+)/i,
|
||||||
|
|
||||||
// Skype
|
// Skype
|
||||||
/(skypeuripreview) preview\/([\w\.]+)/i,
|
/(skypeuripreview) preview\/([\w\.]+)/i,
|
||||||
|
|
||||||
// Slackbot - https://api.slack.com/robots
|
// Slackbot - https://api.slack.com/robots
|
||||||
/(slack(?:bot)?(?:-imgproxy|-linkexpanding)?) ([\w\.]+)/i,
|
/(slack(?:bot)?(?:-imgproxy|-linkexpanding)?) ([\w\.]+)/i
|
||||||
|
|
||||||
// WhatsApp
|
|
||||||
/(whatsapp)\/([\w\.]+)/i
|
|
||||||
],
|
],
|
||||||
[NAME, VERSION, [TYPE, FETCHER]],
|
[NAME, VERSION, [TYPE, FETCHER]],
|
||||||
|
|
||||||
@@ -389,13 +389,15 @@ const MediaPlayers = Object.freeze({
|
|||||||
|
|
||||||
const Libraries = Object.freeze({
|
const Libraries = Object.freeze({
|
||||||
browser : [
|
browser : [
|
||||||
// Apache-HttpClient/Axios/go-http-client/got/GuzzleHttp/Java[-HttpClient]/jsdom/libwww-perl/lua-resty-http/Needle/node-fetch/OkHttp/PHP-SOAP/PostmanRuntime/python-urllib/python-requests/Scrapy/superagent
|
|
||||||
[
|
[
|
||||||
/^(apache-httpclient|axios|(?:go|java)-http-client|got|guzzlehttp|java|libwww-perl|lua-resty-http|needle|node-(?:fetch|superagent)|okhttp|php-soap|postmanruntime|python-(?:httpx|urllib[23]?|requests)|scrapy)\/([\w\.]+)/i,
|
// Apache-HttpClient/Axios/Bun/Dart/go-http-client/got/GuzzleHttp/hackney/Java[-HttpClient]/jsdom/libwww-perl/lua-resty-http/Needle/Node.js/node-fetch/OkHttp/PHP-SOAP/PostmanRuntime/python-urllib/python-requests/rest-client/Scrapy/superagent
|
||||||
|
/^(apache-httpclient|axios|bun|dart|deno|(?:go|java)-http-client|got|guzzlehttp|hackney|java|libwww-perl|lua-resty-http|needle|node(?:\.js|-fetch|-superagent)|okhttp|php-soap|postmanruntime|python-(?:httpx|urllib[23]?|requests)|rest-client|scrapy)\/([\w\.]+)/i,
|
||||||
/(adobeair|aiohttp|jsdom)\/([\w\.]+)/i,
|
/(adobeair|aiohttp|jsdom)\/([\w\.]+)/i,
|
||||||
/(nutch)-([\w\.-]+)(\(|$)/i,
|
/(nutch)-([\w\.-]+)(\(|$)/i,
|
||||||
/\((java)\/([\w\.]+)/i
|
/\((java)\/([\w\.]+)/i
|
||||||
], [NAME, VERSION, [TYPE, LIBRARY]]
|
], [NAME, VERSION, [TYPE, LIBRARY]], [
|
||||||
|
/(node-fetch|undici)/i
|
||||||
|
], [NAME, [TYPE, LIBRARY]]
|
||||||
]
|
]
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
41
src/helpers/ua-parser-helpers.d.ts
vendored
41
src/helpers/ua-parser-helpers.d.ts
vendored
@@ -4,12 +4,37 @@
|
|||||||
|
|
||||||
import type { IResult } from "../main/ua-parser";
|
import type { IResult } from "../main/ua-parser";
|
||||||
|
|
||||||
export function getDeviceVendor(model: string): string | undefined;
|
|
||||||
export function isAppleSilicon(resultOrUA: IResult | string): boolean;
|
|
||||||
export function isAIBot(resultOrUA: IResult | string): boolean;
|
|
||||||
export function isBot(resultOrUA: IResult | string): boolean;
|
|
||||||
export function isChromeFamily(resultOrUA: IResult | string): boolean;
|
|
||||||
export function isElectron(): boolean;
|
|
||||||
export function isFromEU(): boolean;
|
|
||||||
export function isFrozenUA(ua: string): boolean;
|
export function isFrozenUA(ua: string): boolean;
|
||||||
export function isStandalonePWA(): boolean;
|
|
||||||
|
/**
|
||||||
|
* @deprecated Moved to `device-detection` submodule
|
||||||
|
*/
|
||||||
|
export function getDeviceVendor(model: string): string | undefined;
|
||||||
|
/**
|
||||||
|
* @deprecated Moved to `device-detection` submodule
|
||||||
|
*/
|
||||||
|
export function isAppleSilicon(resultOrUA: IResult | string): boolean;
|
||||||
|
/**
|
||||||
|
* @deprecated Moved to `bot-detection` submodule
|
||||||
|
*/
|
||||||
|
export function isAIBot(resultOrUA: IResult | string): boolean;
|
||||||
|
/**
|
||||||
|
* @deprecated Moved to `bot-detection` submodule
|
||||||
|
*/
|
||||||
|
export function isBot(resultOrUA: IResult | string): boolean;
|
||||||
|
/**
|
||||||
|
* @deprecated Moved to `browser-detection` submodule
|
||||||
|
*/
|
||||||
|
export function isChromeFamily(resultOrUA: IResult | string): boolean;
|
||||||
|
/**
|
||||||
|
* @deprecated Moved to `browser-detection` submodule
|
||||||
|
*/
|
||||||
|
export function isElectron(): boolean;
|
||||||
|
/**
|
||||||
|
* @deprecated Moved to `browser-detection` submodule
|
||||||
|
*/
|
||||||
|
export function isFromEU(): boolean;
|
||||||
|
/**
|
||||||
|
* @deprecated Moved to `browser-detection` submodule
|
||||||
|
*/
|
||||||
|
export function isStandalonePWA(): boolean;
|
||||||
@@ -8,170 +8,54 @@
|
|||||||
/*jshint esversion: 6 */
|
/*jshint esversion: 6 */
|
||||||
|
|
||||||
const { UAParser } = require('../main/ua-parser');
|
const { UAParser } = require('../main/ua-parser');
|
||||||
const { CPUArch, OSName, EngineName, Extension, BrowserType } = require('../enums/ua-parser-enums');
|
const { EngineName } = require('../enums/ua-parser-enums');
|
||||||
const { Bots, Crawlers } = require('../extensions/ua-parser-extensions');
|
const { getDeviceVendor: _getDeviceVendor, isAppleSilicon: _isAppleSilicon } = require('../device-detection/device-detection');
|
||||||
const { isFromEU } = require('detect-europe-js');
|
const { isBot: _isBot, isAICrawler } = require('../bot-detection/bot-detection');
|
||||||
|
const { isStandalonePWA: _isStandalonePWA } = require('../browser-detection/browser-detection');
|
||||||
|
const { isFromEU: _isFromEU } = require('../browser-detection/browser-detection');
|
||||||
const { isFrozenUA } = require('ua-is-frozen');
|
const { isFrozenUA } = require('ua-is-frozen');
|
||||||
const { isStandalonePWA } = require('is-standalone-pwa');
|
|
||||||
const { Crawler } = Extension.BrowserName;
|
|
||||||
|
|
||||||
const toResult = (value, head, ext) => typeof value === 'string' ? UAParser(value, head, ext) : value;
|
/**
|
||||||
|
* @deprecated Moved to `device-detection` submodule
|
||||||
|
*/
|
||||||
|
const getDeviceVendor = _getDeviceVendor;
|
||||||
|
|
||||||
const getDeviceVendor = (model) => UAParser(`Mozilla/5.0 (Linux; Android 10; ${model}) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/100.0.0.0 Safari/537.36`).device.vendor;
|
/**
|
||||||
|
* @deprecated Moved to `device-detection` submodule
|
||||||
|
*/
|
||||||
|
const isAppleSilicon = _isAppleSilicon;
|
||||||
|
|
||||||
const isAppleSilicon = (resultOrUA) => {
|
/**
|
||||||
const res = toResult(resultOrUA);
|
* @deprecated Moved to `bot-detection` submodule
|
||||||
if (res.os.is(OSName.MACOS)) {
|
*/
|
||||||
if (res.cpu.is(CPUArch.ARM)) {
|
const isAIBot = isAICrawler;
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (typeof resultOrUA !== 'string' && typeof window !== 'undefined') {
|
|
||||||
try {
|
|
||||||
const canvas = document.createElement('canvas');
|
|
||||||
const webgl = canvas.getContext('webgl2') || canvas.getContext('webgl') || canvas.getContext('experimental-webgl');
|
|
||||||
const debug = webgl.getExtension('WEBGL_debug_renderer_info');
|
|
||||||
const renderer = webgl.getParameter(debug.UNMASKED_RENDERER_WEBGL);
|
|
||||||
if (renderer.match(/apple m\d/i)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
} catch {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
const isAIBot = (resultOrUA) => [
|
/**
|
||||||
|
* @deprecated Moved to `bot-detection` submodule
|
||||||
|
*/
|
||||||
|
const isBot = _isBot;
|
||||||
|
|
||||||
// AI2
|
/**
|
||||||
Crawler.AI2_BOT,
|
* @deprecated Moved to `browser-detection` submodule
|
||||||
|
*/
|
||||||
// Amazon
|
const isChromeFamily = val => !!((typeof val === 'string' ? new UAParser(val).getEngine() : val.engine)?.is(EngineName.BLINK));
|
||||||
Crawler.AMAZON_BOT,
|
|
||||||
|
|
||||||
// Anthropic
|
|
||||||
Crawler.ANTHROPIC_AI,
|
|
||||||
Crawler.ANTHROPIC_CLAUDE_BOT,
|
|
||||||
Crawler.ANTHROPIC_CLAUDE_SEARCHBOT,
|
|
||||||
Crawler.ANTHROPIC_CLAUDE_WEB,
|
|
||||||
|
|
||||||
// Apple
|
|
||||||
Crawler.APPLE_BOT,
|
|
||||||
Crawler.APPLE_BOT_EXTENDED,
|
|
||||||
|
|
||||||
// Brave
|
|
||||||
Crawler.BRAVE_BOT,
|
|
||||||
|
|
||||||
// ByteDance
|
|
||||||
Crawler.BYTEDANCE_BYTESPIDER,
|
|
||||||
Crawler.BYTEDANCE_TIKTOKSPIDER,
|
|
||||||
|
|
||||||
// Cohere
|
|
||||||
Crawler.COHERE_TRAINING_DATA_CRAWLER,
|
|
||||||
|
|
||||||
// Common Crawl
|
|
||||||
Crawler.COMMON_CRAWL_CCBOT,
|
|
||||||
|
|
||||||
// Coveo
|
|
||||||
Crawler.COVEO_BOT,
|
|
||||||
|
|
||||||
// DataForSeo
|
|
||||||
Crawler.DATAFORSEO_BOT,
|
|
||||||
|
|
||||||
// DeepSeek
|
|
||||||
Crawler.DEEPSEEK_BOT,
|
|
||||||
|
|
||||||
// Diffbot
|
|
||||||
Crawler.DIFFBOT,
|
|
||||||
|
|
||||||
// Google
|
|
||||||
Crawler.GOOGLE_EXTENDED,
|
|
||||||
Crawler.GOOGLE_OTHER,
|
|
||||||
Crawler.GOOGLE_OTHER_IMAGE,
|
|
||||||
Crawler.GOOGLE_OTHER_VIDEO,
|
|
||||||
Crawler.GOOGLE_CLOUDVERTEXBOT,
|
|
||||||
|
|
||||||
// Hive AI
|
|
||||||
Crawler.HIVE_IMAGESIFTBOT,
|
|
||||||
|
|
||||||
// Huawei
|
|
||||||
Crawler.HUAWEI_PETALBOT,
|
|
||||||
Crawler.HUAWEI_PANGUBOT,
|
|
||||||
|
|
||||||
// Hugging Face
|
|
||||||
Crawler.HUGGINGFACE_BOT,
|
|
||||||
|
|
||||||
// Kangaroo
|
|
||||||
Crawler.KANGAROO_BOT,
|
|
||||||
|
|
||||||
// Mendable.ai
|
|
||||||
Crawler.FIRECRAWL_AGENT,
|
|
||||||
|
|
||||||
// Meta
|
|
||||||
Crawler.META_FACEBOOKBOT,
|
|
||||||
Crawler.META_EXTERNALAGENT,
|
|
||||||
|
|
||||||
// OpenAI
|
|
||||||
Crawler.OPENAI_GPTBOT,
|
|
||||||
Crawler.OPENAI_SEARCH_BOT,
|
|
||||||
|
|
||||||
// Perplexity
|
|
||||||
Crawler.PERPLEXITY_BOT,
|
|
||||||
|
|
||||||
// Replicate
|
|
||||||
Crawler.REPLICATE_BOT,
|
|
||||||
|
|
||||||
// Runpod
|
|
||||||
Crawler.RUNPOD_BOT,
|
|
||||||
|
|
||||||
// SB Intuitions
|
|
||||||
Crawler.SB_INTUITIONS_BOT,
|
|
||||||
|
|
||||||
// Semrush
|
|
||||||
Crawler.SEMRUSH_BOT_CONTENTSHAKE,
|
|
||||||
|
|
||||||
// Timpi
|
|
||||||
Crawler.TIMPI_BOT,
|
|
||||||
|
|
||||||
// Together AI
|
|
||||||
Crawler.TOGETHER_BOT,
|
|
||||||
|
|
||||||
// Velen.io
|
|
||||||
Crawler.HUNTER_VELENPUBLICWEBCRAWLER,
|
|
||||||
|
|
||||||
// Vercel
|
|
||||||
Crawler.VERCEL_V0BOT,
|
|
||||||
|
|
||||||
// Webz.io
|
|
||||||
Crawler.WEBZIO_OMGILI,
|
|
||||||
Crawler.WEBZIO_OMGILI_BOT,
|
|
||||||
Crawler.WEBZIO_EXTENDED,
|
|
||||||
|
|
||||||
// X
|
|
||||||
Crawler.XAI_BOT,
|
|
||||||
|
|
||||||
// You.com
|
|
||||||
Crawler.YOU_BOT,
|
|
||||||
|
|
||||||
// Zhipu AI
|
|
||||||
Crawler.ZHIPU_CHATGLM_SPIDER
|
|
||||||
]
|
|
||||||
.map((s) => s.toLowerCase())
|
|
||||||
.includes(String(toResult(resultOrUA, Crawlers).browser.name).toLowerCase());
|
|
||||||
|
|
||||||
const isBot = (resultOrUA) => [
|
|
||||||
BrowserType.CLI,
|
|
||||||
BrowserType.CRAWLER,
|
|
||||||
BrowserType.FETCHER,
|
|
||||||
BrowserType.LIBRARY
|
|
||||||
].includes(toResult(resultOrUA, Bots).browser.type);
|
|
||||||
|
|
||||||
const isChromeFamily = (resultOrUA) => toResult(resultOrUA).engine.is(EngineName.BLINK);
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @deprecated Moved to `browser-detection` submodule
|
||||||
|
*/
|
||||||
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
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @deprecated Moved to `browser-detection` submodule
|
||||||
|
*/
|
||||||
|
const isFromEU = _isFromEU;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @deprecated Moved to `browser-detection` submodule
|
||||||
|
*/
|
||||||
|
const isStandalonePWA = _isStandalonePWA;
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
getDeviceVendor,
|
getDeviceVendor,
|
||||||
isAppleSilicon,
|
isAppleSilicon,
|
||||||
|
|||||||
@@ -12,166 +12,34 @@
|
|||||||
/*jshint esversion: 6 */
|
/*jshint esversion: 6 */
|
||||||
|
|
||||||
import { UAParser } from '../main/ua-parser.mjs';
|
import { UAParser } from '../main/ua-parser.mjs';
|
||||||
import { CPUArch, OSName, EngineName, Extension, BrowserType } from '../enums/ua-parser-enums.mjs';
|
import { EngineName } from '../enums/ua-parser-enums.mjs';
|
||||||
import { Bots, Crawlers } from '../extensions/ua-parser-extensions.mjs';
|
import { getDeviceVendor: _getDeviceVendor, isAppleSilicon: _isAppleSilicon } from '../device-detection/device-detection.mjs';
|
||||||
|
import { isBot: _isBot, isAICrawler } from '../bot-detection/bot-detection.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;
|
/**
|
||||||
|
* @deprecated Moved to `device-detection` submodule
|
||||||
|
*/
|
||||||
|
const getDeviceVendor = _getDeviceVendor;
|
||||||
|
|
||||||
const getDeviceVendor = (model) => UAParser(`Mozilla/5.0 (Linux; Android 10; ${model}) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/100.0.0.0 Safari/537.36`).device.vendor;
|
/**
|
||||||
|
* @deprecated Moved to `device-detection` submodule
|
||||||
|
*/
|
||||||
|
const isAppleSilicon = _isAppleSilicon;
|
||||||
|
|
||||||
const isAppleSilicon = (resultOrUA) => {
|
/**
|
||||||
const res = toResult(resultOrUA);
|
* @deprecated Moved to `bot-detection` submodule
|
||||||
if (res.os.is(OSName.MACOS)) {
|
*/
|
||||||
if (res.cpu.is(CPUArch.ARM)) {
|
const isAIBot = isAICrawler;
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (typeof resultOrUA !== 'string' && typeof window !== 'undefined') {
|
|
||||||
try {
|
|
||||||
const canvas = document.createElement('canvas');
|
|
||||||
const webgl = canvas.getContext('webgl2') || canvas.getContext('webgl') || canvas.getContext('experimental-webgl');
|
|
||||||
const debug = webgl.getExtension('WEBGL_debug_renderer_info');
|
|
||||||
const renderer = webgl.getParameter(debug.UNMASKED_RENDERER_WEBGL);
|
|
||||||
if (renderer.match(/apple m\d/i)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
} catch {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
const isAIBot = (resultOrUA) => [
|
/**
|
||||||
|
* @deprecated Moved to `bot-detection` submodule
|
||||||
|
*/
|
||||||
|
const isBot = _isBot;
|
||||||
|
|
||||||
// AI2
|
const isChromeFamily = val => !!((typeof val === 'string' ? new UAParser(val).getEngine() : val.engine)?.is(EngineName.BLINK));
|
||||||
Crawler.AI2_BOT,
|
|
||||||
|
|
||||||
// Amazon
|
|
||||||
Crawler.AMAZON_BOT,
|
|
||||||
|
|
||||||
// Anthropic
|
|
||||||
Crawler.ANTHROPIC_AI,
|
|
||||||
Crawler.ANTHROPIC_CLAUDE_BOT,
|
|
||||||
Crawler.ANTHROPIC_CLAUDE_SEARCHBOT,
|
|
||||||
Crawler.ANTHROPIC_CLAUDE_WEB,
|
|
||||||
|
|
||||||
// Apple
|
|
||||||
Crawler.APPLE_BOT,
|
|
||||||
Crawler.APPLE_BOT_EXTENDED,
|
|
||||||
|
|
||||||
// Brave
|
|
||||||
Crawler.BRAVE_BOT,
|
|
||||||
|
|
||||||
// ByteDance
|
|
||||||
Crawler.BYTEDANCE_BYTESPIDER,
|
|
||||||
Crawler.BYTEDANCE_TIKTOKSPIDER,
|
|
||||||
|
|
||||||
// Cohere
|
|
||||||
Crawler.COHERE_TRAINING_DATA_CRAWLER,
|
|
||||||
|
|
||||||
// Common Crawl
|
|
||||||
Crawler.COMMON_CRAWL_CCBOT,
|
|
||||||
|
|
||||||
// Coveo
|
|
||||||
Crawler.COVEO_BOT,
|
|
||||||
|
|
||||||
// DataForSeo
|
|
||||||
Crawler.DATAFORSEO_BOT,
|
|
||||||
|
|
||||||
// DeepSeek
|
|
||||||
Crawler.DEEPSEEK_BOT,
|
|
||||||
|
|
||||||
// Diffbot
|
|
||||||
Crawler.DIFFBOT,
|
|
||||||
|
|
||||||
// Google
|
|
||||||
Crawler.GOOGLE_EXTENDED,
|
|
||||||
Crawler.GOOGLE_OTHER,
|
|
||||||
Crawler.GOOGLE_OTHER_IMAGE,
|
|
||||||
Crawler.GOOGLE_OTHER_VIDEO,
|
|
||||||
Crawler.GOOGLE_CLOUDVERTEXBOT,
|
|
||||||
|
|
||||||
// Hive AI
|
|
||||||
Crawler.HIVE_IMAGESIFTBOT,
|
|
||||||
|
|
||||||
// Huawei
|
|
||||||
Crawler.HUAWEI_PETALBOT,
|
|
||||||
Crawler.HUAWEI_PANGUBOT,
|
|
||||||
|
|
||||||
// Hugging Face
|
|
||||||
Crawler.HUGGINGFACE_BOT,
|
|
||||||
|
|
||||||
// Kangaroo
|
|
||||||
Crawler.KANGAROO_BOT,
|
|
||||||
|
|
||||||
// Mendable.ai
|
|
||||||
Crawler.FIRECRAWL_AGENT,
|
|
||||||
|
|
||||||
// Meta
|
|
||||||
Crawler.META_FACEBOOKBOT,
|
|
||||||
Crawler.META_EXTERNALAGENT,
|
|
||||||
|
|
||||||
// OpenAI
|
|
||||||
Crawler.OPENAI_GPTBOT,
|
|
||||||
Crawler.OPENAI_SEARCH_BOT,
|
|
||||||
|
|
||||||
// Perplexity
|
|
||||||
Crawler.PERPLEXITY_BOT,
|
|
||||||
|
|
||||||
// Replicate
|
|
||||||
Crawler.REPLICATE_BOT,
|
|
||||||
|
|
||||||
// Runpod
|
|
||||||
Crawler.RUNPOD_BOT,
|
|
||||||
|
|
||||||
// SB Intuitions
|
|
||||||
Crawler.SB_INTUITIONS_BOT,
|
|
||||||
|
|
||||||
// Semrush
|
|
||||||
Crawler.SEMRUSH_BOT_CONTENTSHAKE,
|
|
||||||
|
|
||||||
// Timpi
|
|
||||||
Crawler.TIMPI_BOT,
|
|
||||||
|
|
||||||
// Together AI
|
|
||||||
Crawler.TOGETHER_BOT,
|
|
||||||
|
|
||||||
// Velen.io
|
|
||||||
Crawler.HUNTER_VELENPUBLICWEBCRAWLER,
|
|
||||||
|
|
||||||
// Vercel
|
|
||||||
Crawler.VERCEL_V0BOT,
|
|
||||||
|
|
||||||
// Webz.io
|
|
||||||
Crawler.WEBZIO_OMGILI,
|
|
||||||
Crawler.WEBZIO_OMGILI_BOT,
|
|
||||||
Crawler.WEBZIO_EXTENDED,
|
|
||||||
|
|
||||||
// X
|
|
||||||
Crawler.XAI_BOT,
|
|
||||||
|
|
||||||
// You.com
|
|
||||||
Crawler.YOU_BOT,
|
|
||||||
|
|
||||||
// Zhipu AI
|
|
||||||
Crawler.ZHIPU_CHATGLM_SPIDER
|
|
||||||
]
|
|
||||||
.map((s) => s.toLowerCase())
|
|
||||||
.includes(String(toResult(resultOrUA, Crawlers).browser.name).toLowerCase());
|
|
||||||
|
|
||||||
const isBot = (resultOrUA) => [
|
|
||||||
BrowserType.CLI,
|
|
||||||
BrowserType.CRAWLER,
|
|
||||||
BrowserType.FETCHER,
|
|
||||||
BrowserType.LIBRARY
|
|
||||||
].includes(toResult(resultOrUA, Bots).browser.type);
|
|
||||||
|
|
||||||
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
|
||||||
|
|||||||
@@ -376,8 +376,8 @@
|
|||||||
/(?:ms|\()(ie) ([\w\.]+)/i, // Internet Explorer
|
/(?:ms|\()(ie) ([\w\.]+)/i, // Internet Explorer
|
||||||
|
|
||||||
// Blink/Webkit/KHTML based // Flock/RockMelt/Midori/Epiphany/Silk/Skyfire/Bolt/Iron/Iridium/PhantomJS/Bowser/QupZilla/Falkon/LG Browser/Otter/qutebrowser/Dooble/Palemoon
|
// Blink/Webkit/KHTML based // Flock/RockMelt/Midori/Epiphany/Silk/Skyfire/Bolt/Iron/Iridium/PhantomJS/Bowser/QupZilla/Falkon/LG Browser/Otter/qutebrowser/Dooble/Palemoon
|
||||||
/(flock|rockmelt|midori|epiphany|silk|skyfire|ovibrowser|bolt|iron|vivaldi|iridium|phantomjs|bowser|qupzilla|falkon|rekonq|puffin|brave|whale(?!.+naver)|qqbrowserlite|duckduckgo|klar|helio|(?=comodo_)?dragon|otter|dooble|(?:lg |qute)browser|palemoon)\/([-\w\.]+)/i,
|
/(atlas|flock|rockmelt|midori|epiphany|silk|skyfire|ovibrowser|bolt|iron|vivaldi|iridium|phantomjs|bowser|qupzilla|falkon|rekonq|puffin|brave|whale(?!.+naver)|qqbrowserlite|duckduckgo|klar|helio|(?=comodo_)?dragon|otter|dooble|(?:lg |qute)browser|palemoon)\/([-\w\.]+)/i,
|
||||||
// Rekonq/Puffin/Brave/Whale/QQBrowserLite/QQ//Vivaldi/DuckDuckGo/Klar/Helio/Dragon
|
// Atlas/Rekonq/Puffin/Brave/Whale/QQBrowserLite/QQ//Vivaldi/DuckDuckGo/Klar/Helio/Dragon
|
||||||
/(heytap|ovi|115|surf|qwant)browser\/([\d\.]+)/i, // HeyTap/Ovi/115/Surf
|
/(heytap|ovi|115|surf|qwant)browser\/([\d\.]+)/i, // HeyTap/Ovi/115/Surf
|
||||||
/(qwant)(?:ios|mobile)\/([\d\.]+)/i, // Qwant
|
/(qwant)(?:ios|mobile)\/([\d\.]+)/i, // Qwant
|
||||||
/(ecosia|weibo)(?:__| \w+@)([\d\.]+)/i // Ecosia/Weibo
|
/(ecosia|weibo)(?:__| \w+@)([\d\.]+)/i // Ecosia/Weibo
|
||||||
@@ -852,10 +852,9 @@
|
|||||||
], [MODEL, [VENDOR, MICROSOFT], [TYPE, CONSOLE]], [
|
], [MODEL, [VENDOR, MICROSOFT], [TYPE, CONSOLE]], [
|
||||||
/(ouya)/i, // Ouya
|
/(ouya)/i, // Ouya
|
||||||
/(nintendo) (\w+)/i, // Nintendo
|
/(nintendo) (\w+)/i, // Nintendo
|
||||||
/(retroid) (pocket ([^\)]+))/i // Retroid Pocket
|
/(retroid) (pocket ([^\)]+))/i, // Retroid Pocket
|
||||||
], [VENDOR, MODEL, [TYPE, CONSOLE]], [
|
/droid.+; ((shield|rgcube|gr0006))( bui|\))/i // Nvidia Portable/Anbernic/Logitech
|
||||||
/droid.+; (shield)( bui|\))/i // Nvidia Portable
|
], [[VENDOR, strMapper, { 'Nvidia': 'Shield', 'Anbernic': 'RGCUBE', 'Logitech': 'GR0006' }], MODEL, [TYPE, CONSOLE]], [
|
||||||
], [MODEL, [VENDOR, NVIDIA], [TYPE, CONSOLE]], [
|
|
||||||
|
|
||||||
///////////////////
|
///////////////////
|
||||||
// WEARABLES
|
// WEARABLES
|
||||||
|
|||||||
@@ -171,6 +171,16 @@
|
|||||||
"major" : "0"
|
"major" : "0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"desc" : "Atlas",
|
||||||
|
"ua" : "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36 Atlas/1.0",
|
||||||
|
"expect" :
|
||||||
|
{
|
||||||
|
"name" : "Atlas",
|
||||||
|
"version" : "1.0",
|
||||||
|
"major" : "1"
|
||||||
|
}
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"desc" : "Avant",
|
"desc" : "Avant",
|
||||||
"ua" : "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0; GTB5; Avant Browser; .NET CLR 1.1.4322; .NET CLR 2.0.50727)",
|
"ua" : "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0; GTB5; Avant Browser; .NET CLR 1.1.4322; .NET CLR 2.0.50727)",
|
||||||
|
|||||||
11
test/data/ua/device/anbernic.json
Normal file
11
test/data/ua/device/anbernic.json
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
[
|
||||||
|
{
|
||||||
|
"desc": "Anbernic",
|
||||||
|
"ua": "Mozilla/5.0 (Linux; Android 13; RGCUBE) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Mobile Safari/537.36",
|
||||||
|
"expect": {
|
||||||
|
"vendor": "Anbernic",
|
||||||
|
"model": "RGCUBE",
|
||||||
|
"type": "console"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
11
test/data/ua/device/logitech.json
Normal file
11
test/data/ua/device/logitech.json
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
[
|
||||||
|
{
|
||||||
|
"desc": "Logitech",
|
||||||
|
"ua": "Dalvik/2.1.0 (Linux; U; Android 11; GR0006 Build/SQ02K.00.0018)",
|
||||||
|
"expect": {
|
||||||
|
"vendor": "Logitech",
|
||||||
|
"model": "GR0006",
|
||||||
|
"type": "console"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
@@ -289,6 +289,16 @@
|
|||||||
"type" : "fetcher"
|
"type" : "fetcher"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"desc" : "NovaAct",
|
||||||
|
"ua" : "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/115.0.0.0 Safari/537.36 Agent-NovaAct/0.9",
|
||||||
|
"expect" :
|
||||||
|
{
|
||||||
|
"name" : "NovaAct",
|
||||||
|
"version" : "0.9",
|
||||||
|
"type" : "fetcher"
|
||||||
|
}
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"desc" : "Perplexity-User",
|
"desc" : "Perplexity-User",
|
||||||
"ua" : "Mozilla/5.0 AppleWebKit/537.36 (KHTML, like Gecko; compatible; Perplexity-User/1.0; +https://perplexity.ai/perplexity-user)",
|
"ua" : "Mozilla/5.0 AppleWebKit/537.36 (KHTML, like Gecko; compatible; Perplexity-User/1.0; +https://perplexity.ai/perplexity-user)",
|
||||||
|
|||||||
@@ -39,6 +39,36 @@
|
|||||||
"type" : "library"
|
"type" : "library"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"desc" : "Bun",
|
||||||
|
"ua" : "Bun/1.0.6",
|
||||||
|
"expect" :
|
||||||
|
{
|
||||||
|
"name" : "Bun",
|
||||||
|
"version" : "1.0.6",
|
||||||
|
"type" : "library"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"desc" : "Dart",
|
||||||
|
"ua" : "Dart/3.5 (dart:io)",
|
||||||
|
"expect" :
|
||||||
|
{
|
||||||
|
"name" : "Dart",
|
||||||
|
"version" : "3.5",
|
||||||
|
"type" : "library"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"desc" : "Deno",
|
||||||
|
"ua" : "Deno/2.1.7",
|
||||||
|
"expect" :
|
||||||
|
{
|
||||||
|
"name" : "Deno",
|
||||||
|
"version" : "2.1.7",
|
||||||
|
"type" : "library"
|
||||||
|
}
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"desc" : "go-http-client",
|
"desc" : "go-http-client",
|
||||||
"ua" : "go-http-client/1.1",
|
"ua" : "go-http-client/1.1",
|
||||||
@@ -59,6 +89,16 @@
|
|||||||
"type" : "library"
|
"type" : "library"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"desc" : "hackney",
|
||||||
|
"ua" : "hackney/1.20.1",
|
||||||
|
"expect" :
|
||||||
|
{
|
||||||
|
"name" : "hackney",
|
||||||
|
"version" : "1.20.1",
|
||||||
|
"type" : "library"
|
||||||
|
}
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"desc" : "GuzzleHttp",
|
"desc" : "GuzzleHttp",
|
||||||
"ua" : "GuzzleHttp/6.5.5 curl/7.70.0 PHP/7.4.22",
|
"ua" : "GuzzleHttp/6.5.5 curl/7.70.0 PHP/7.4.22",
|
||||||
@@ -129,6 +169,26 @@
|
|||||||
"type" : "library"
|
"type" : "library"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"desc" : "Node.js",
|
||||||
|
"ua" : "Node.js/22",
|
||||||
|
"expect" :
|
||||||
|
{
|
||||||
|
"name" : "Node.js",
|
||||||
|
"version" : "22",
|
||||||
|
"type" : "library"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"desc" : "node-fetch",
|
||||||
|
"ua" : "node-fetch/1.0 (+https://github.com/bitinn/node-fetch)",
|
||||||
|
"expect" :
|
||||||
|
{
|
||||||
|
"name" : "node-fetch",
|
||||||
|
"version" : "1.0",
|
||||||
|
"type" : "library"
|
||||||
|
}
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"desc" : "Nutch",
|
"desc" : "Nutch",
|
||||||
"ua" : "AliyunSecBot/Nutch-1.21-SNAPSHOT",
|
"ua" : "AliyunSecBot/Nutch-1.21-SNAPSHOT",
|
||||||
@@ -149,16 +209,6 @@
|
|||||||
"type" : "library"
|
"type" : "library"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"desc" : "node-fetch",
|
|
||||||
"ua" : "node-fetch/1.0 (+https://github.com/bitinn/node-fetch)",
|
|
||||||
"expect" :
|
|
||||||
{
|
|
||||||
"name" : "node-fetch",
|
|
||||||
"version" : "1.0",
|
|
||||||
"type" : "library"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"desc" : "PHP-SOAP",
|
"desc" : "PHP-SOAP",
|
||||||
"ua" : "PHP-SOAP/7.4.33",
|
"ua" : "PHP-SOAP/7.4.33",
|
||||||
@@ -219,6 +269,16 @@
|
|||||||
"type" : "library"
|
"type" : "library"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"desc" : "rest-client",
|
||||||
|
"ua" : "rest-client/2.1.0 (linux-gnu x86_64) ruby/2.7.2p137",
|
||||||
|
"expect" :
|
||||||
|
{
|
||||||
|
"name" : "rest-client",
|
||||||
|
"version" : "2.1.0",
|
||||||
|
"type" : "library"
|
||||||
|
}
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"desc" : "Scrapy",
|
"desc" : "Scrapy",
|
||||||
"ua" : "Scrapy/1.5.0 (+https://scrapy.org)",
|
"ua" : "Scrapy/1.5.0 (+https://scrapy.org)",
|
||||||
@@ -238,5 +298,15 @@
|
|||||||
"version" : "5.0.2",
|
"version" : "5.0.2",
|
||||||
"type" : "library"
|
"type" : "library"
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"desc" : "undici",
|
||||||
|
"ua" : "undici",
|
||||||
|
"expect" :
|
||||||
|
{
|
||||||
|
"name" : "undici",
|
||||||
|
"version" : "undefined",
|
||||||
|
"type" : "library"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -1,85 +0,0 @@
|
|||||||
const assert = require('assert');
|
|
||||||
const { UAParser } = require('../../src/main/ua-parser');
|
|
||||||
const { getDeviceVendor, isAppleSilicon, isAIBot, isBot, isChromeFamily } = require('../../src/helpers/ua-parser-helpers');
|
|
||||||
const { Bots, Emails } = require('../../src/extensions/ua-parser-extensions');
|
|
||||||
const { DeviceVendor } = require('../../src/enums/ua-parser-enums');
|
|
||||||
|
|
||||||
describe('getDeviceVendor', () => {
|
|
||||||
it('Can guess the device vendor from a model name', () => {
|
|
||||||
|
|
||||||
const modelSM = 'SM-A605G';
|
|
||||||
const modelRedmi = 'Redmi Note 8';
|
|
||||||
const modelNexus = 'Nexus 6P';
|
|
||||||
const modelAquos = 'AQUOS-TVX19B';
|
|
||||||
|
|
||||||
assert.equal(getDeviceVendor(modelSM), DeviceVendor.SAMSUNG);
|
|
||||||
assert.equal(getDeviceVendor(modelRedmi), DeviceVendor.XIAOMI);
|
|
||||||
assert.equal(getDeviceVendor(modelNexus), DeviceVendor.HUAWEI);
|
|
||||||
assert.equal(getDeviceVendor(modelAquos), DeviceVendor.SHARP);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('isAppleSilicon', () => {
|
|
||||||
it('Can detect Apple Silicon device', () => {
|
|
||||||
|
|
||||||
// non-real ua
|
|
||||||
const macARM = 'Mozilla/5.0 (Macintosh; ARM; Mac OS X 10.15; rv:97.0) Gecko/20100101 Firefox/97.0';
|
|
||||||
const macIntel = 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:97.0) Gecko/20100101 Firefox/97.0';
|
|
||||||
|
|
||||||
assert.equal(isAppleSilicon(UAParser(macIntel)), false);
|
|
||||||
assert.equal(isAppleSilicon(macIntel), false);
|
|
||||||
assert.equal(isAppleSilicon(UAParser(macARM)), true);
|
|
||||||
assert.equal(isAppleSilicon(macARM), true);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('isAIBot', () => {
|
|
||||||
it('Can detect AI Bots', () => {
|
|
||||||
|
|
||||||
const claudeBot = 'Mozilla/5.0 AppleWebKit/537.36 (KHTML, like Gecko; compatible; ClaudeBot/1.0; +claudebot@anthropic.com)';
|
|
||||||
const firefox = 'Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/111.0';
|
|
||||||
const searchGPT = 'Mozilla/5.0 AppleWebKit/537.36 (KHTML, like Gecko); compatible; OAI-SearchBot/1.0; +https://openai.com/searchbot';
|
|
||||||
const semrushAI = 'Mozilla/5.0 (compatible; SemrushBot-OCOB/1; +https://www.semrush.com/bot/)';
|
|
||||||
|
|
||||||
assert.equal(isAIBot(UAParser(claudeBot, Bots)), true);
|
|
||||||
assert.equal(isAIBot(claudeBot), true);
|
|
||||||
assert.equal(isAIBot(firefox), false);
|
|
||||||
assert.equal(isAIBot(searchGPT), true);
|
|
||||||
assert.equal(isAIBot(semrushAI), true);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('isBot', () => {
|
|
||||||
it('Can detect Bots', () => {
|
|
||||||
|
|
||||||
// non-real ua
|
|
||||||
const ahrefsBot = 'Mozilla/5.0 (compatible; AhrefsBot/7.0; +http://ahrefs.com/robot/)';
|
|
||||||
const firefox = 'Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/111.0';
|
|
||||||
const scrapy = 'Scrapy/1.5.0 (+https://scrapy.org)';
|
|
||||||
const thunderbird = 'Mozilla/5.0 (X11; Linux x86_64; rv:78.0) Gecko/20100101 Thunderbird/78.13.0';
|
|
||||||
|
|
||||||
const botParser = new UAParser(firefox, { Bots, Emails });
|
|
||||||
assert.equal(isBot(botParser.getResult()), false);
|
|
||||||
assert.equal(isBot(botParser.setUA(ahrefsBot).getResult()), true);
|
|
||||||
assert.equal(isBot(botParser.setUA(scrapy).getResult()), true);
|
|
||||||
assert.equal(isBot(botParser.setUA(thunderbird).getResult()), false);
|
|
||||||
|
|
||||||
assert.equal(isBot(ahrefsBot), true);
|
|
||||||
assert.equal(isBot(firefox), false);
|
|
||||||
assert.equal(isBot(scrapy), true);
|
|
||||||
assert.equal(isBot(thunderbird), false);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('isChromeFamily', () => {
|
|
||||||
it('Can detect Chromium-based browser', () => {
|
|
||||||
|
|
||||||
const edge = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36 Edg/119.0.2151.58';
|
|
||||||
const firefox = 'Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/111.0';
|
|
||||||
|
|
||||||
assert.equal(isChromeFamily(UAParser(edge)), true);
|
|
||||||
assert.equal(isChromeFamily(UAParser(firefox)), false);
|
|
||||||
assert.equal(isChromeFamily(edge), true);
|
|
||||||
assert.equal(isChromeFamily(firefox), false);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
42
test/unit/submodules/bot-detection.spec.js
Normal file
42
test/unit/submodules/bot-detection.spec.js
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
const assert = require('assert');
|
||||||
|
const { UAParser } = require('../../../src/main/ua-parser');
|
||||||
|
const { isAICrawler, isBot } = require('../../../src/bot-detection/bot-detection');
|
||||||
|
const { Bots, Emails } = require('../../../src/extensions/ua-parser-extensions');
|
||||||
|
|
||||||
|
describe('isAICrawler()', () => {
|
||||||
|
it('Can detect AI Crawlers', () => {
|
||||||
|
|
||||||
|
// AI Crawlers
|
||||||
|
const claudeBot = 'Mozilla/5.0 AppleWebKit/537.36 (KHTML, like Gecko; compatible; ClaudeBot/1.0; +claudebot@anthropic.com)';
|
||||||
|
const searchGPT = 'Mozilla/5.0 AppleWebKit/537.36 (KHTML, like Gecko); compatible; OAI-SearchBot/1.0; +https://openai.com/searchbot';
|
||||||
|
const semrushAI = 'Mozilla/5.0 (compatible; SemrushBot-OCOB/1; +https://www.semrush.com/bot/)';
|
||||||
|
|
||||||
|
assert.equal(isAICrawler(claudeBot), true);
|
||||||
|
assert.equal(isAICrawler(searchGPT), true);
|
||||||
|
assert.equal(isAICrawler(semrushAI), true);
|
||||||
|
|
||||||
|
// Non-AI Crawlers
|
||||||
|
const firefox = 'Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/111.0';
|
||||||
|
|
||||||
|
assert.equal(isAICrawler(firefox), false);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('isBot()', () => {
|
||||||
|
it('Can detect general Bots', () => {
|
||||||
|
|
||||||
|
// Bots
|
||||||
|
const ahrefsBot = 'Mozilla/5.0 (compatible; AhrefsBot/7.0; +http://ahrefs.com/robot/)';
|
||||||
|
const scrapy = 'Scrapy/1.5.0 (+https://scrapy.org)';
|
||||||
|
|
||||||
|
assert.equal(isBot(ahrefsBot), true);
|
||||||
|
assert.equal(isBot(scrapy), true);
|
||||||
|
|
||||||
|
// Non-bots
|
||||||
|
const firefox = 'Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/111.0';
|
||||||
|
const thunderbird = 'Mozilla/5.0 (X11; Linux x86_64; rv:78.0) Gecko/20100101 Thunderbird/78.13.0';
|
||||||
|
|
||||||
|
assert.equal(isBot(firefox), false);
|
||||||
|
assert.equal(isBot(thunderbird), false);
|
||||||
|
});
|
||||||
|
});
|
||||||
16
test/unit/submodules/browser-detection.spec.js
Normal file
16
test/unit/submodules/browser-detection.spec.js
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
const assert = require('assert');
|
||||||
|
const { UAParser } = require('../../../src/main/ua-parser');
|
||||||
|
const { isChromeFamily } = require('../../../src/browser-detection/browser-detection');
|
||||||
|
|
||||||
|
describe('isChromeFamily()', () => {
|
||||||
|
it('Can detect Chromium-based browser', () => {
|
||||||
|
|
||||||
|
const edge = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36 Edg/119.0.2151.58';
|
||||||
|
const firefox = 'Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/111.0';
|
||||||
|
|
||||||
|
assert.equal(isChromeFamily(UAParser(edge)), true);
|
||||||
|
assert.equal(isChromeFamily(edge), true);
|
||||||
|
assert.equal(isChromeFamily(UAParser(firefox)), false);
|
||||||
|
assert.equal(isChromeFamily(firefox), false);
|
||||||
|
});
|
||||||
|
});
|
||||||
32
test/unit/submodules/device-detection.spec.js
Normal file
32
test/unit/submodules/device-detection.spec.js
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
const assert = require('assert');
|
||||||
|
const { UAParser } = require('../../../src/main/ua-parser');
|
||||||
|
const { getDeviceVendor, isAppleSilicon } = require('../../../src/device-detection/device-detection');
|
||||||
|
const { DeviceVendor } = require('../../../src/enums/ua-parser-enums');
|
||||||
|
|
||||||
|
describe('getDeviceVendor()', () => {
|
||||||
|
it('Can guess the device vendor from a model name', () => {
|
||||||
|
|
||||||
|
const sm = 'SM-A605G';
|
||||||
|
const redmi = 'Redmi Note 8';
|
||||||
|
const nexus = 'Nexus 6P';
|
||||||
|
const aquos = 'AQUOS-TVX19B';
|
||||||
|
|
||||||
|
assert.equal(getDeviceVendor(sm), DeviceVendor.SAMSUNG);
|
||||||
|
assert.equal(getDeviceVendor(redmi), DeviceVendor.XIAOMI);
|
||||||
|
assert.equal(getDeviceVendor(nexus), DeviceVendor.HUAWEI);
|
||||||
|
assert.equal(getDeviceVendor(aquos), DeviceVendor.SHARP);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('isAppleSilicon()', () => {
|
||||||
|
it('Can detect Apple Silicon device', () => {
|
||||||
|
|
||||||
|
const macARM = 'Mozilla/5.0 (Macintosh; ARM; Mac OS X 10.15; rv:97.0) Gecko/20100101 Firefox/97.0';
|
||||||
|
const macIntel = 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:97.0) Gecko/20100101 Firefox/97.0';
|
||||||
|
|
||||||
|
assert.equal(isAppleSilicon(UAParser(macIntel)), false);
|
||||||
|
assert.equal(isAppleSilicon(macIntel), false);
|
||||||
|
assert.equal(isAppleSilicon(UAParser(macARM)), true);
|
||||||
|
assert.equal(isAppleSilicon(macARM), true);
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -3,9 +3,9 @@ const assert = require('assert');
|
|||||||
const parseJS = require('@babel/parser').parse;
|
const parseJS = require('@babel/parser').parse;
|
||||||
const traverse = require('@babel/traverse').default;
|
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 { BrowserType, OSName, Extension } = require('../../../src/enums/ua-parser-enums');
|
||||||
const { CLI, Crawler, Email, Fetcher, Library } = Extension.BrowserName;
|
const { CLI, Crawler, Email, Fetcher, Library } = Extension.BrowserName;
|
||||||
|
|
||||||
describe('Extensions', () => {
|
describe('Extensions', () => {
|
||||||
@@ -19,7 +19,7 @@ describe('Extensions', () => {
|
|||||||
['Vehicles', 'vehicle', Vehicles]
|
['Vehicles', 'vehicle', Vehicles]
|
||||||
]
|
]
|
||||||
.forEach(([desc, path, ext]) => {
|
.forEach(([desc, path, ext]) => {
|
||||||
const tests = require(`../data/ua/extension/${path}.json`);
|
const tests = require(`../../data/ua/extension/${path}.json`);
|
||||||
describe(desc, () => {
|
describe(desc, () => {
|
||||||
tests.forEach((test) => {
|
tests.forEach((test) => {
|
||||||
it(`Can detect ${test.desc}: "${test.ua}"`, () => {
|
it(`Can detect ${test.desc}: "${test.ua}"`, () => {
|
||||||
13
test/unit/submodules/helpers.spec.js
Normal file
13
test/unit/submodules/helpers.spec.js
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
const assert = require('assert');
|
||||||
|
const { isFrozenUA } = require('../../../src/helpers/ua-parser-helpers');
|
||||||
|
|
||||||
|
describe('isFrozenUA()', () => {
|
||||||
|
it('matches supplied user-agent string with known frozen user-agent pattern', () => {
|
||||||
|
|
||||||
|
const regularMobileUA = "Mozilla/5.0 (Linux; Android 9; SM-A205U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/93.0.1234.56 Mobile Safari/537.36";
|
||||||
|
const frozenMobileUA = "Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/93.0.0.0 Mobile Safari/537.36";
|
||||||
|
|
||||||
|
assert.equal(isFrozenUA(regularMobileUA), false);
|
||||||
|
assert.equal(isFrozenUA(frozenMobileUA), true);
|
||||||
|
});
|
||||||
|
});
|
||||||
Reference in New Issue
Block a user