ua-browser 1.0.0 → 1.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +132 -38
- package/README.zh-CN.md +176 -0
- package/dist/index.cjs +32 -11
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +5 -5
- package/dist/index.d.ts +5 -5
- package/dist/index.min.js +2 -2
- package/dist/index.min.js.map +1 -1
- package/dist/index.mjs +32 -11
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,27 +1,39 @@
|
|
|
1
|
-
#
|
|
1
|
+
# ua-browser
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
[](https://www.npmjs.com/package/ua-browser)
|
|
4
|
+
[](https://www.npmjs.com/package/ua-browser)
|
|
5
|
+
[](./LICENSE)
|
|
6
|
+
[](https://www.typescriptlang.org/)
|
|
4
7
|
|
|
5
|
-
|
|
8
|
+
Detect browser, OS, device type, rendering engine, CPU architecture, bots, and headless browsers from User Agent strings. Zero dependencies. Works in both browser and Node.js environments.
|
|
6
9
|
|
|
7
|
-
|
|
10
|
+
**[📖 Documentation](https://yangtianxia.github.io/ua-browser/)** · **[🎮 Playground](https://yangtianxia.github.io/ua-browser/playground)** · **[中文](./README.zh-CN.md)**
|
|
11
|
+
|
|
12
|
+
## Features
|
|
13
|
+
|
|
14
|
+
- **Comprehensive detection** — browser, OS, engine, device type (Mobile / Tablet / TV / PC), CPU arch, bots, headless browsers
|
|
15
|
+
- **AI bot recognition** — built-in support for GPTBot, ClaudeBot, PerplexityBot, CCBot and more
|
|
16
|
+
- **Zero dependencies** — no runtime dependencies, tiny bundle size after gzip
|
|
17
|
+
- **Pure function** — `parseUA()` has no global state, works seamlessly with SSR / Node.js
|
|
18
|
+
- **TypeScript** — full type definitions with precise literal union types (`BrowserName`, `OsName`, etc.)
|
|
19
|
+
- **Tree-shakeable** — import only what you need
|
|
20
|
+
|
|
21
|
+
## Installation
|
|
8
22
|
|
|
9
23
|
```sh
|
|
10
24
|
npm i ua-browser
|
|
11
|
-
#
|
|
25
|
+
# pnpm
|
|
12
26
|
pnpm add ua-browser
|
|
13
|
-
#
|
|
27
|
+
# yarn
|
|
14
28
|
yarn add ua-browser
|
|
15
29
|
```
|
|
16
30
|
|
|
17
|
-
##
|
|
31
|
+
## Quick Start
|
|
18
32
|
|
|
19
33
|
```typescript
|
|
20
34
|
import uaBrowser from 'ua-browser'
|
|
21
35
|
|
|
22
36
|
const info = uaBrowser()
|
|
23
|
-
// 或传入自定义 UA 字符串
|
|
24
|
-
const info = uaBrowser('Mozilla/5.0 (Windows NT 10.0; Win64; x64) ...')
|
|
25
37
|
|
|
26
38
|
console.log(info)
|
|
27
39
|
// {
|
|
@@ -36,47 +48,129 @@ console.log(info)
|
|
|
36
48
|
// isHeadless: false,
|
|
37
49
|
// isBot: false,
|
|
38
50
|
// botName: 'unknown',
|
|
39
|
-
// language: '
|
|
51
|
+
// language: 'en-US',
|
|
40
52
|
// platform: 'Win32'
|
|
41
53
|
// }
|
|
42
54
|
```
|
|
43
55
|
|
|
44
|
-
|
|
56
|
+
> Pass a custom UA string: `uaBrowser('Mozilla/5.0 ...')`
|
|
57
|
+
|
|
58
|
+
## Usage
|
|
59
|
+
|
|
60
|
+
### Browser
|
|
45
61
|
|
|
46
62
|
```typescript
|
|
47
|
-
import
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
}
|
|
63
|
+
import uaBrowser from 'ua-browser'
|
|
64
|
+
|
|
65
|
+
const { browser, os, device } = uaBrowser()
|
|
66
|
+
|
|
67
|
+
if (device === 'Mobile') {
|
|
68
|
+
// redirect to mobile version
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
if (browser === 'Wechat') {
|
|
72
|
+
// WeChat in-app browser logic
|
|
73
|
+
}
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
### Node.js / SSR
|
|
77
|
+
|
|
78
|
+
Use the pure `parseUA` function with the UA string from the request header:
|
|
79
|
+
|
|
80
|
+
```typescript
|
|
81
|
+
import { parseUA } from 'ua-browser'
|
|
82
|
+
|
|
83
|
+
const ua = req.headers['user-agent'] ?? ''
|
|
84
|
+
const { browser, os, isBot } = parseUA(ua)
|
|
85
|
+
|
|
86
|
+
if (isBot) {
|
|
87
|
+
// block or allow crawlers
|
|
88
|
+
}
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
### CDN
|
|
92
|
+
|
|
93
|
+
```html
|
|
94
|
+
<script src="https://cdn.jsdelivr.net/npm/ua-browser/dist/index.min.js"></script>
|
|
95
|
+
<script>
|
|
96
|
+
const { browser, os } = uaBrowser()
|
|
97
|
+
</script>
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
### Accurate Windows 10 / 11 Detection
|
|
101
|
+
|
|
102
|
+
Windows 10 and 11 share the same UA string. Use the Client Hints API to distinguish them:
|
|
103
|
+
|
|
104
|
+
```typescript
|
|
105
|
+
import { parseUA, getWindowsVersion, getNavContext } from 'ua-browser'
|
|
106
|
+
|
|
107
|
+
const nav = getNavContext()
|
|
108
|
+
const windowsVersion = await getWindowsVersion(nav)
|
|
109
|
+
const result = parseUA(navigator.userAgent, { nav, windowsVersion })
|
|
110
|
+
|
|
111
|
+
console.log(result.osVersion) // '10' or '11'
|
|
58
112
|
```
|
|
59
113
|
|
|
60
114
|
## API
|
|
61
115
|
|
|
62
|
-
### `uaBrowser(ua
|
|
116
|
+
### Default export `uaBrowser(ua?)`
|
|
117
|
+
|
|
118
|
+
Automatically injects the `navigator` context (language, platform, MIME types, etc.) in browser environments.
|
|
119
|
+
|
|
120
|
+
```typescript
|
|
121
|
+
import uaBrowser from 'ua-browser'
|
|
122
|
+
|
|
123
|
+
uaBrowser() // reads navigator.userAgent automatically
|
|
124
|
+
uaBrowser(customUA) // custom UA string, still injects browser context
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
### Named exports (tree-shakeable)
|
|
128
|
+
|
|
129
|
+
```typescript
|
|
130
|
+
import {
|
|
131
|
+
parseUA, // pure function, ideal for SSR / Node.js
|
|
132
|
+
getNavContext, // read current browser navigator context
|
|
133
|
+
getWindowsVersion, // async: accurately distinguish Windows 10 / 11
|
|
134
|
+
getLanguage, // extract browser language from NavContext
|
|
135
|
+
isWebview, // detect Android Webview (UA contains "; wv")
|
|
136
|
+
isWechatMiniapp, // detect WeChat Mini Program environment
|
|
137
|
+
detectBot, // standalone bot detection
|
|
138
|
+
detectArch, // standalone CPU architecture detection
|
|
139
|
+
detectHeadless, // standalone headless browser detection
|
|
140
|
+
VERSION, // current library version
|
|
141
|
+
} from 'ua-browser'
|
|
142
|
+
```
|
|
63
143
|
|
|
64
|
-
|
|
144
|
+
### Return value `EnvOption`
|
|
145
|
+
|
|
146
|
+
| Field | Type | Description |
|
|
65
147
|
| :-- | :-- | :-- |
|
|
66
|
-
| `browser` | `BrowserName` |
|
|
67
|
-
| `version` | `string` |
|
|
68
|
-
| `engine` | `EngineName` |
|
|
69
|
-
| `os` | `OsName` |
|
|
70
|
-
| `osVersion` | `string` |
|
|
71
|
-
| `device` | `DeviceName` |
|
|
72
|
-
| `arch` | `ArchName` | CPU
|
|
73
|
-
| `isWebview` | `boolean` |
|
|
74
|
-
| `isHeadless` | `boolean` |
|
|
75
|
-
| `isBot` | `boolean` |
|
|
76
|
-
| `botName` | `BotName` |
|
|
77
|
-
| `language` | `string` |
|
|
78
|
-
| `platform` | `string` |
|
|
148
|
+
| `browser` | `BrowserName` | Browser name |
|
|
149
|
+
| `version` | `string` | Browser version |
|
|
150
|
+
| `engine` | `EngineName` | Rendering engine |
|
|
151
|
+
| `os` | `OsName` | Operating system |
|
|
152
|
+
| `osVersion` | `string` | OS version |
|
|
153
|
+
| `device` | `DeviceName` | Device type: `Mobile` \| `Tablet` \| `TV` \| `PC` |
|
|
154
|
+
| `arch` | `ArchName` | CPU architecture |
|
|
155
|
+
| `isWebview` | `boolean` | Whether running in Android Webview |
|
|
156
|
+
| `isHeadless` | `boolean` | Whether running in a headless / automated browser |
|
|
157
|
+
| `isBot` | `boolean` | Whether the UA belongs to a bot / crawler |
|
|
158
|
+
| `botName` | `BotName` | Bot name |
|
|
159
|
+
| `language` | `string` | Browser language, e.g. `en-US` |
|
|
160
|
+
| `platform` | `string` | Platform identifier, e.g. `Win32` |
|
|
161
|
+
|
|
162
|
+
> All fields return `'unknown'` when undetected — never an empty string or `null`.
|
|
163
|
+
|
|
164
|
+
## Supported
|
|
165
|
+
|
|
166
|
+
Over 60 browsers, 17 operating systems, and 19 bot rules built in. See the **[full support list](https://yangtianxia.github.io/ua-browser/guide/support-list)**.
|
|
167
|
+
|
|
168
|
+
Highlights:
|
|
169
|
+
- **Browsers** — Chrome, Safari, Firefox, Edge, Samsung Internet, UC, WeChat, DingTalk, TikTok and more
|
|
170
|
+
- **OS** — Windows, macOS, Android, iOS, HarmonyOS, Tizen, KaiOS and more
|
|
171
|
+
- **AI bots** — GPTBot, ClaudeBot, PerplexityBot, CCBot and more
|
|
172
|
+
- **Devices** — Mobile, Tablet, TV (Samsung Smart TV, HbbTV), PC
|
|
79
173
|
|
|
80
174
|
## License
|
|
81
175
|
|
|
82
|
-
MIT
|
|
176
|
+
[MIT](./LICENSE) © yangtianxia
|
package/README.zh-CN.md
ADDED
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
# ua-browser
|
|
2
|
+
|
|
3
|
+
[](https://www.npmjs.com/package/ua-browser)
|
|
4
|
+
[](https://www.npmjs.com/package/ua-browser)
|
|
5
|
+
[](./LICENSE)
|
|
6
|
+
[](https://www.typescriptlang.org/)
|
|
7
|
+
|
|
8
|
+
通过 User Agent 检测浏览器、操作系统、设备类型、渲染内核、CPU 架构、爬虫及无头浏览器。零依赖,支持浏览器与 Node.js 双环境。
|
|
9
|
+
|
|
10
|
+
**[📖 文档](https://yangtianxia.github.io/ua-browser/)** · **[🎮 Playground](https://yangtianxia.github.io/ua-browser/playground)** · **[English](./README.md)**
|
|
11
|
+
|
|
12
|
+
## 特性
|
|
13
|
+
|
|
14
|
+
- **全面检测** — 浏览器、OS、渲染内核、设备类型(Mobile / Tablet / TV / PC)、CPU 架构、爬虫、无头浏览器
|
|
15
|
+
- **AI 爬虫识别** — 内置 GPTBot、ClaudeBot、PerplexityBot 等主流 AI 抓取机器人
|
|
16
|
+
- **零依赖** — 无任何运行时依赖,gzip 后体积极小
|
|
17
|
+
- **纯函数** — `parseUA()` 无全局状态,天然支持 SSR / Node.js
|
|
18
|
+
- **TypeScript** — 完整类型定义,`BrowserName`、`OsName` 等均为精确字面量联合类型
|
|
19
|
+
- **Tree-shakeable** — 所有功能按需导入,不引入多余代码
|
|
20
|
+
|
|
21
|
+
## 安装
|
|
22
|
+
|
|
23
|
+
```sh
|
|
24
|
+
npm i ua-browser
|
|
25
|
+
# pnpm
|
|
26
|
+
pnpm add ua-browser
|
|
27
|
+
# yarn
|
|
28
|
+
yarn add ua-browser
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
## 快速上手
|
|
32
|
+
|
|
33
|
+
```typescript
|
|
34
|
+
import uaBrowser from 'ua-browser'
|
|
35
|
+
|
|
36
|
+
const info = uaBrowser()
|
|
37
|
+
|
|
38
|
+
console.log(info)
|
|
39
|
+
// {
|
|
40
|
+
// browser: 'Chrome',
|
|
41
|
+
// version: '124.0.0.0',
|
|
42
|
+
// engine: 'Blink',
|
|
43
|
+
// os: 'Windows',
|
|
44
|
+
// osVersion: '10',
|
|
45
|
+
// device: 'PC',
|
|
46
|
+
// arch: 'x86_64',
|
|
47
|
+
// isWebview: false,
|
|
48
|
+
// isHeadless: false,
|
|
49
|
+
// isBot: false,
|
|
50
|
+
// botName: 'unknown',
|
|
51
|
+
// language: 'zh-CN',
|
|
52
|
+
// platform: 'Win32'
|
|
53
|
+
// }
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
> 传入自定义 UA 字符串:`uaBrowser('Mozilla/5.0 ...')`
|
|
57
|
+
|
|
58
|
+
## 使用
|
|
59
|
+
|
|
60
|
+
### 浏览器环境
|
|
61
|
+
|
|
62
|
+
```typescript
|
|
63
|
+
import uaBrowser from 'ua-browser'
|
|
64
|
+
|
|
65
|
+
const { browser, os, device } = uaBrowser()
|
|
66
|
+
|
|
67
|
+
if (device === 'Mobile') {
|
|
68
|
+
// 跳转移动版
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
if (browser === 'Wechat') {
|
|
72
|
+
// 微信内置浏览器逻辑
|
|
73
|
+
}
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
### Node.js / SSR
|
|
77
|
+
|
|
78
|
+
使用 `parseUA` 纯函数,传入请求头中的 UA 字符串:
|
|
79
|
+
|
|
80
|
+
```typescript
|
|
81
|
+
import { parseUA } from 'ua-browser'
|
|
82
|
+
|
|
83
|
+
const ua = req.headers['user-agent'] ?? ''
|
|
84
|
+
const { browser, os, isBot } = parseUA(ua)
|
|
85
|
+
|
|
86
|
+
if (isBot) {
|
|
87
|
+
// 拦截或放行爬虫
|
|
88
|
+
}
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
### CDN
|
|
92
|
+
|
|
93
|
+
```html
|
|
94
|
+
<script src="https://cdn.jsdelivr.net/npm/ua-browser/dist/index.min.js"></script>
|
|
95
|
+
<script>
|
|
96
|
+
const { browser, os } = uaBrowser()
|
|
97
|
+
</script>
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
### 精确区分 Windows 10 / 11
|
|
101
|
+
|
|
102
|
+
Windows 10 和 11 的 UA 字符串相同,需借助 Client Hints API 异步获取:
|
|
103
|
+
|
|
104
|
+
```typescript
|
|
105
|
+
import { parseUA, getWindowsVersion, getNavContext } from 'ua-browser'
|
|
106
|
+
|
|
107
|
+
const nav = getNavContext()
|
|
108
|
+
const windowsVersion = await getWindowsVersion(nav)
|
|
109
|
+
const result = parseUA(navigator.userAgent, { nav, windowsVersion })
|
|
110
|
+
|
|
111
|
+
console.log(result.osVersion) // '10' 或 '11'
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
## API
|
|
115
|
+
|
|
116
|
+
### 默认导出 `uaBrowser(ua?)`
|
|
117
|
+
|
|
118
|
+
在浏览器环境中自动注入 `navigator` 上下文(语言、平台、MIME 类型等)。
|
|
119
|
+
|
|
120
|
+
```typescript
|
|
121
|
+
import uaBrowser from 'ua-browser'
|
|
122
|
+
|
|
123
|
+
uaBrowser() // 自动读取 navigator.userAgent
|
|
124
|
+
uaBrowser(customUA) // 传入自定义 UA,仍注入当前浏览器上下文
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
### 命名导出(按需引入)
|
|
128
|
+
|
|
129
|
+
```typescript
|
|
130
|
+
import {
|
|
131
|
+
parseUA, // 纯函数,适合 SSR / Node.js
|
|
132
|
+
getNavContext, // 读取当前浏览器 navigator 上下文
|
|
133
|
+
getWindowsVersion, // 异步精确区分 Windows 10 / 11
|
|
134
|
+
getLanguage, // 从 NavContext 获取浏览器语言
|
|
135
|
+
isWebview, // 检测 Android Webview(UA 含 "; wv")
|
|
136
|
+
isWechatMiniapp, // 检测微信小程序运行环境
|
|
137
|
+
detectBot, // 独立爬虫检测
|
|
138
|
+
detectArch, // 独立 CPU 架构检测
|
|
139
|
+
detectHeadless, // 独立无头浏览器检测
|
|
140
|
+
VERSION, // 当前版本号
|
|
141
|
+
} from 'ua-browser'
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
### 返回值 `EnvOption`
|
|
145
|
+
|
|
146
|
+
| 字段 | 类型 | 说明 |
|
|
147
|
+
| :-- | :-- | :-- |
|
|
148
|
+
| `browser` | `BrowserName` | 浏览器名称 |
|
|
149
|
+
| `version` | `string` | 浏览器版本 |
|
|
150
|
+
| `engine` | `EngineName` | 渲染内核 |
|
|
151
|
+
| `os` | `OsName` | 操作系统 |
|
|
152
|
+
| `osVersion` | `string` | 系统版本 |
|
|
153
|
+
| `device` | `DeviceName` | 设备类型:`Mobile` \| `Tablet` \| `TV` \| `PC` |
|
|
154
|
+
| `arch` | `ArchName` | CPU 架构 |
|
|
155
|
+
| `isWebview` | `boolean` | 是否为 Android Webview |
|
|
156
|
+
| `isHeadless` | `boolean` | 是否为无头 / 自动化浏览器 |
|
|
157
|
+
| `isBot` | `boolean` | 是否为爬虫 / 机器人 |
|
|
158
|
+
| `botName` | `BotName` | 爬虫名称 |
|
|
159
|
+
| `language` | `string` | 浏览器语言,如 `zh-CN` |
|
|
160
|
+
| `platform` | `string` | 平台标识,如 `Win32` |
|
|
161
|
+
|
|
162
|
+
> 所有字段在无法识别时统一返回 `'unknown'`,不返回空字符串或 `null`。
|
|
163
|
+
|
|
164
|
+
## 支持范围
|
|
165
|
+
|
|
166
|
+
内置超过 60 种浏览器、17 种操作系统、19 种爬虫规则,详见 **[内置支持列表](https://yangtianxia.github.io/ua-browser/guide/support-list)**。
|
|
167
|
+
|
|
168
|
+
部分覆盖:
|
|
169
|
+
- **浏览器** — Chrome、Safari、Firefox、Edge、Samsung Internet、UC、微信、钉钉、抖音等
|
|
170
|
+
- **操作系统** — Windows、macOS、Android、iOS、HarmonyOS、Tizen、KaiOS 等
|
|
171
|
+
- **AI 爬虫** — GPTBot、ClaudeBot、PerplexityBot、CCBot 等
|
|
172
|
+
- **设备** — Mobile、Tablet、TV(含三星 Smart TV、HbbTV 标准)、PC
|
|
173
|
+
|
|
174
|
+
## License
|
|
175
|
+
|
|
176
|
+
[MIT](./LICENSE) © yangtianxia
|
package/dist/index.cjs
CHANGED
|
@@ -4,7 +4,7 @@ Object.defineProperty(exports, '__esModule', { value: true });
|
|
|
4
4
|
|
|
5
5
|
// package.json
|
|
6
6
|
var package_default = {
|
|
7
|
-
version: "1.0.
|
|
7
|
+
version: "1.0.1"};
|
|
8
8
|
|
|
9
9
|
// src/constants/browsers.ts
|
|
10
10
|
var BROWSER_DEFS = [
|
|
@@ -19,6 +19,9 @@ var BROWSER_DEFS = [
|
|
|
19
19
|
{ name: "Opera", priority: 70, detect: /(Opera|OPR|OPT)/, versionPattern: [/Opera\/([\d.]+)/, /OPR\/([\d.]+)/, /OPT\/([\d.]+)/] },
|
|
20
20
|
{ name: "Vivaldi", priority: 80, detect: /Vivaldi/, versionPattern: /Vivaldi\/([\d.]+)/ },
|
|
21
21
|
{ name: "Yandex", priority: 90, detect: /YaBrowser/, versionPattern: /YaBrowser\/([\d.]+)/ },
|
|
22
|
+
{ name: "Samsung Internet", priority: 92, detect: /SamsungBrowser/, versionPattern: /SamsungBrowser\/([\d.]+)/ },
|
|
23
|
+
{ name: "DuckDuckGo", priority: 94, detect: /DuckDuckGo\//, versionPattern: /DuckDuckGo\/([\d.]+)/ },
|
|
24
|
+
{ name: "Puffin", priority: 96, detect: /Puffin\//, versionPattern: /Puffin\/([\d.]+)/ },
|
|
22
25
|
{ name: "Arora", priority: 100, detect: /Arora/, versionPattern: /Arora\/([\d.]+)/ },
|
|
23
26
|
{ name: "Lunascape", priority: 110, detect: /Lunascape/, versionPattern: /Lunascape[\s]([\d.]+)/ },
|
|
24
27
|
{ name: "QupZilla", priority: 120, detect: /QupZilla/, versionPattern: /QupZilla[\s]([\d.]+)/ },
|
|
@@ -200,6 +203,7 @@ var OS_DEFS = [
|
|
|
200
203
|
{ name: "Ubuntu", detect: /Ubuntu/, versionPattern: null },
|
|
201
204
|
{ name: "Chrome OS", detect: /CrOS/, versionPattern: null },
|
|
202
205
|
{ name: "Linux", detect: /(Linux|X11)/, versionPattern: null },
|
|
206
|
+
{ name: "Tizen", detect: /Tizen/, versionPattern: /Tizen ([\d.]+)/ },
|
|
203
207
|
{ name: "iOS", detect: /like Mac OS X/, versionPattern: /OS ([\d_]+) like/ },
|
|
204
208
|
{ name: "MacOS", detect: /Macintosh/, versionPattern: /Mac OS X -?([\d_.]+)/ },
|
|
205
209
|
{
|
|
@@ -209,6 +213,7 @@ var OS_DEFS = [
|
|
|
209
213
|
versionLookup: { "10": "2" }
|
|
210
214
|
},
|
|
211
215
|
{ name: "Android", detect: /(Android|Adr)/, versionPattern: /(?:Android|Adr) ([\d.]+)/ },
|
|
216
|
+
{ name: "KaiOS", detect: /KAIOS/, versionPattern: /KAIOS\/([\d.]+)/ },
|
|
212
217
|
{
|
|
213
218
|
name: "Windows",
|
|
214
219
|
detect: /Windows/,
|
|
@@ -246,7 +251,8 @@ function detectOs(ua, windowsVersion) {
|
|
|
246
251
|
if (mapped !== null) {
|
|
247
252
|
osVersion = mapped;
|
|
248
253
|
} else if (matchedDef.name === "Windows") {
|
|
249
|
-
|
|
254
|
+
const n = parseInt(normalised, 10);
|
|
255
|
+
osVersion = isNaN(n) ? "unknown" : n.toString();
|
|
250
256
|
}
|
|
251
257
|
} else {
|
|
252
258
|
osVersion = normalised;
|
|
@@ -261,18 +267,24 @@ function detectOs(ua, windowsVersion) {
|
|
|
261
267
|
|
|
262
268
|
// src/constants/devices.ts
|
|
263
269
|
var DEVICE_DEFS = [
|
|
264
|
-
{ name: "Mobile", detect: /(Mobi|iPh
|
|
265
|
-
{ name: "Tablet", detect: /(Tablet|Pad
|
|
270
|
+
{ name: "Mobile", detect: /(Mobi|iPh)/ },
|
|
271
|
+
{ name: "Tablet", detect: /(Tablet|Pad)/ }
|
|
266
272
|
];
|
|
267
273
|
|
|
268
274
|
// src/detectors/device.ts
|
|
269
275
|
function detectDevice(ua, nav) {
|
|
276
|
+
if (/(SMART-TV|HbbTV|SmartTV|TV Safari|Android TV|GoogleTV)/.test(ua)) {
|
|
277
|
+
return "TV";
|
|
278
|
+
}
|
|
270
279
|
if ((nav == null ? void 0 : nav.platform) === "MacIntel" && nav.maxTouchPoints > 1) {
|
|
271
280
|
return "Tablet";
|
|
272
281
|
}
|
|
273
282
|
if (/iPad/.test(ua)) {
|
|
274
283
|
return "Tablet";
|
|
275
284
|
}
|
|
285
|
+
if (/Android/.test(ua) && !/Mobile/.test(ua)) {
|
|
286
|
+
return "Tablet";
|
|
287
|
+
}
|
|
276
288
|
for (const def of DEVICE_DEFS) {
|
|
277
289
|
if (def.detect.test(ua)) {
|
|
278
290
|
return def.name;
|
|
@@ -303,6 +315,12 @@ var BOT_DEFS = [
|
|
|
303
315
|
{ name: "SemrushBot", detect: /SemrushBot/ },
|
|
304
316
|
{ name: "AhrefsBot", detect: /AhrefsBot/ },
|
|
305
317
|
{ name: "MJ12bot", detect: /MJ12bot/ },
|
|
318
|
+
// AI / LLM crawlers
|
|
319
|
+
{ name: "GPTBot", detect: /GPTBot/ },
|
|
320
|
+
{ name: "ClaudeBot", detect: /ClaudeBot/ },
|
|
321
|
+
{ name: "PerplexityBot", detect: /PerplexityBot/ },
|
|
322
|
+
{ name: "CCBot", detect: /CCBot/ },
|
|
323
|
+
{ name: "AdsBot", detect: /AdsBot-Google/ },
|
|
306
324
|
// Generic catch-all (must be last)
|
|
307
325
|
{ name: "GenericBot", detect: /(bot|crawler|spider|crawling|scraper)/i }
|
|
308
326
|
];
|
|
@@ -336,7 +354,7 @@ function detectArch(ua) {
|
|
|
336
354
|
}
|
|
337
355
|
|
|
338
356
|
// src/detectors/headless.ts
|
|
339
|
-
var HEADLESS_PATTERN = /(HeadlessChrome|Headless|PhantomJS|Electron\/|Playwright)/;
|
|
357
|
+
var HEADLESS_PATTERN = /(HeadlessChrome|Headless|PhantomJS|Electron\/|Playwright|jsdom\/|Selenium)/;
|
|
340
358
|
function detectHeadless(ua) {
|
|
341
359
|
return HEADLESS_PATTERN.test(ua);
|
|
342
360
|
}
|
|
@@ -365,7 +383,7 @@ function getLanguage(nav) {
|
|
|
365
383
|
|
|
366
384
|
// src/parse.ts
|
|
367
385
|
function parseUA(ua, options = {}) {
|
|
368
|
-
var _a, _b, _c, _d, _e
|
|
386
|
+
var _a, _b, _c, _d, _e;
|
|
369
387
|
const { nav, windowsVersion } = options;
|
|
370
388
|
const { browser: rawBrowser, version: rawVersion } = detectBrowser(ua);
|
|
371
389
|
const { os, osVersion } = detectOs(ua, windowsVersion);
|
|
@@ -379,7 +397,8 @@ function parseUA(ua, options = {}) {
|
|
|
379
397
|
let version = rawVersion;
|
|
380
398
|
if (nav) {
|
|
381
399
|
const chromeGlobal = typeof chrome !== "undefined" ? chrome : void 0;
|
|
382
|
-
const
|
|
400
|
+
const chromeMatch = /Chrome\/([\d]+)/.exec(ua);
|
|
401
|
+
const chromeMajor = chromeMatch ? parseInt(chromeMatch[1], 10) : 0;
|
|
383
402
|
if (chromeGlobal) {
|
|
384
403
|
if (chromeGlobal.adblock2345 || chromeGlobal.common2345) {
|
|
385
404
|
browser = "2345Explorer";
|
|
@@ -395,7 +414,8 @@ function parseUA(ua, options = {}) {
|
|
|
395
414
|
}
|
|
396
415
|
}
|
|
397
416
|
if (is360) {
|
|
398
|
-
|
|
417
|
+
const saveDataEnabled = ((_b = nav.connection) == null ? void 0 : _b.saveData) === true;
|
|
418
|
+
if (getMimeType(nav, "application/gameplugin") || !saveDataEnabled) {
|
|
399
419
|
browser = "360SE";
|
|
400
420
|
} else {
|
|
401
421
|
browser = "360EE";
|
|
@@ -407,7 +427,8 @@ function parseUA(ua, options = {}) {
|
|
|
407
427
|
}
|
|
408
428
|
if (browser === "Baidu" && /(Opera|OPR|OPT)/.test(ua)) {
|
|
409
429
|
browser = "Opera";
|
|
410
|
-
|
|
430
|
+
const opVer = (_d = (_c = /OPR\/([\d.]+)/.exec(ua)) != null ? _c : /OPT\/([\d.]+)/.exec(ua)) != null ? _d : /Opera\/([\d.]+)/.exec(ua);
|
|
431
|
+
version = (_e = opVer == null ? void 0 : opVer[1]) != null ? _e : "unknown";
|
|
411
432
|
}
|
|
412
433
|
if (browser === "Chrome" && /\S+Browser\//.test(ua)) {
|
|
413
434
|
const m = /(\S+Browser)\/([\d.]+)/.exec(ua);
|
|
@@ -452,13 +473,13 @@ function parseUA(ua, options = {}) {
|
|
|
452
473
|
|
|
453
474
|
// src/utils/windows-version.ts
|
|
454
475
|
async function getWindowsVersion(nav) {
|
|
455
|
-
var _a
|
|
476
|
+
var _a;
|
|
456
477
|
if (!nav.userAgentData || nav.userAgentData.platform !== "Windows") {
|
|
457
478
|
return null;
|
|
458
479
|
}
|
|
459
480
|
try {
|
|
460
481
|
const data = await nav.userAgentData.getHighEntropyValues(["platformVersion"]);
|
|
461
|
-
const major = parseInt((
|
|
482
|
+
const major = parseInt(((_a = data["platformVersion"]) == null ? void 0 : _a.split(".")[0]) || "0", 10);
|
|
462
483
|
return major >= 13 ? "11" : "10";
|
|
463
484
|
} catch (e) {
|
|
464
485
|
return null;
|