ua-browser 1.4.0-beta.1 → 1.4.0

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/dist/index.mjs CHANGED
@@ -1,6 +1,85 @@
1
1
  // package.json
2
2
  var package_default = {
3
- version: "1.4.0-beta.1"};
3
+ version: "1.4.0"};
4
+
5
+ // src/constants/os.ts
6
+ var OS_DEFS = [
7
+ { name: "WebOS", detect: /hpwOS/, versionPattern: /hpwOS\/([\d.]+)/ },
8
+ { name: "Symbian", detect: /Symbian/, versionPattern: null },
9
+ { name: "MeeGo", detect: /MeeGo/, versionPattern: null },
10
+ { name: "BlackBerry", detect: /(BlackBerry|RIM)/, versionPattern: null },
11
+ { name: "FreeBSD", detect: /FreeBSD/, versionPattern: null },
12
+ { name: "Debian", detect: /Debian/, versionPattern: /Debian\/([\d.]+)/ },
13
+ { name: "Ubuntu", detect: /Ubuntu/, versionPattern: null },
14
+ // Linux must come before Chrome OS: Chrome OS UAs contain "X11", so Linux matches first,
15
+ // then Chrome OS overrides it.
16
+ { name: "Linux", detect: /(Linux|X11)/, versionPattern: null },
17
+ { name: "Chrome OS", detect: /CrOS/, versionPattern: null },
18
+ { name: "Tizen", detect: /Tizen/, versionPattern: /Tizen ([\d.]+)/ },
19
+ { name: "iOS", detect: /like Mac OS X/, versionPattern: /OS ([\d_]+) like/ },
20
+ {
21
+ name: "MacOS",
22
+ detect: /Macintosh/,
23
+ versionPattern: /Mac OS X -?([\d_.]+)/,
24
+ versionNames: {
25
+ "10.9": "Mavericks",
26
+ "10.10": "Yosemite",
27
+ "10.11": "El Capitan",
28
+ "10.12": "Sierra",
29
+ "10.13": "High Sierra",
30
+ "10.14": "Mojave",
31
+ "10.15": "Catalina",
32
+ "11": "Big Sur",
33
+ "12": "Monterey",
34
+ "13": "Ventura",
35
+ "14": "Sonoma",
36
+ "15": "Sequoia"
37
+ }
38
+ },
39
+ // visionOS / tvOS must come AFTER iOS: their UAs also contain "like Mac OS X",
40
+ // so they need to override iOS via the last-match-wins iteration.
41
+ { name: "visionOS", detect: /visionOS/, versionPattern: /visionOS ([\d_]+)/ },
42
+ { name: "tvOS", detect: /Apple TV/, versionPattern: /OS ([\d_]+) like/ },
43
+ { name: "Android", detect: /(Android|Adr)/, versionPattern: /(?:Android|Adr) ([\d.]+)/ },
44
+ // HarmonyOS must come after Android: HarmonyOS UAs include "Android", so Android matches
45
+ // first, then HarmonyOS overrides it. versionPattern tries direct extraction first (5.0+
46
+ // pure HarmonyOS UAs don't have Android token), then falls back to Android version + lookup.
47
+ {
48
+ name: "HarmonyOS",
49
+ detect: /HarmonyOS/,
50
+ versionPattern: [/HarmonyOS[\s/]([\d.]+)/, /Android ([\d.]+)[;)]/],
51
+ versionLookup: { "10": "2", "11": "3", "12": "3", "13": "4" }
52
+ },
53
+ // OpenHarmony (open-source base) must come after HarmonyOS to override any earlier match.
54
+ { name: "OpenHarmony", detect: /OpenHarmony/, versionPattern: /OpenHarmony[\s/]([\d.]+)/ },
55
+ { name: "KaiOS", detect: /KAIOS/, versionPattern: /KAIOS\/([\d.]+)/ },
56
+ // Windows must come before Windows Phone: Windows Phone UAs contain "Windows", so Windows
57
+ // matches first, then Windows Phone overrides it.
58
+ {
59
+ name: "Windows",
60
+ detect: /Windows/,
61
+ versionPattern: /Windows NT ([\d.]+)/,
62
+ versionLookup: {
63
+ "10": "10",
64
+ "6.4": "10",
65
+ "6.3": "8.1",
66
+ "6.2": "8",
67
+ "6.1": "7",
68
+ "6.0": "Vista",
69
+ "5.2": "XP",
70
+ "5.1": "XP",
71
+ "5.0": "2000"
72
+ },
73
+ versionNames: {
74
+ "7": "Windows 7",
75
+ "8": "Windows 8",
76
+ "8.1": "Windows 8.1",
77
+ "10": "Windows 10",
78
+ "11": "Windows 11"
79
+ }
80
+ },
81
+ { name: "Windows Phone", detect: /(IEMobile|Windows Phone)/, versionPattern: /Windows Phone(?: OS)? ([\d.]+)/ }
82
+ ];
4
83
 
5
84
  // src/constants/browsers.ts
6
85
  var BROWSER_DEFS = [
@@ -147,7 +226,7 @@ function detectBrowser(ua) {
147
226
  }
148
227
  }
149
228
  }
150
- if (!best) return { browser: "unknown", version: "unknown" };
229
+ if (!best) return { browser: "unknown", version: "unknown", browserType: "unknown", priority: 0 };
151
230
  let version = null;
152
231
  if (best.chromeLookup) {
153
232
  version = lookupFromChromeVersion(ua, best.chromeLookup);
@@ -156,7 +235,9 @@ function detectBrowser(ua) {
156
235
  const patterns = Array.isArray(best.versionPattern) ? best.versionPattern : [best.versionPattern];
157
236
  version = extractVersionFromPatterns(ua, patterns);
158
237
  }
159
- return { browser: best.name, version: version != null ? version : "unknown" };
238
+ const p = best.priority;
239
+ const browserType = p >= 500 ? "app" : p >= 300 ? "brand" : "browser";
240
+ return { browser: best.name, version: version != null ? version : "unknown", browserType, priority: p };
160
241
  }
161
242
 
162
243
  // src/constants/engines.ts
@@ -172,8 +253,17 @@ var ENGINE_DEFS = [
172
253
  ];
173
254
 
174
255
  // src/detectors/engine.ts
256
+ var ENGINE_VERSION_RE = {
257
+ WebKit: /AppleWebKit\/([\d.]+)/,
258
+ Blink: /AppleWebKit\/([\d.]+)/,
259
+ ArkWeb: /AppleWebKit\/([\d.]+)/,
260
+ Gecko: /Gecko\/([\d.]+)/,
261
+ Trident: /Trident\/([\d.]+)/,
262
+ Presto: /Presto\/([\d.]+)/,
263
+ KHTML: /KHTML\/([\d.]+)/
264
+ };
175
265
  function detectEngine(ua, browser, version) {
176
- var _a, _b;
266
+ var _a, _b, _c, _d;
177
267
  if (browser === void 0 || version === void 0) {
178
268
  const b = detectBrowser(ua);
179
269
  browser = browser != null ? browser : b.browser;
@@ -195,64 +285,19 @@ function detectEngine(ua, browser, version) {
195
285
  if (browser === "Edge") {
196
286
  engine = parseInt(version, 10) > 75 ? "Blink" : "EdgeHTML";
197
287
  }
198
- return engine;
288
+ const engineVersion = ENGINE_VERSION_RE[engine] ? (_d = (_c = ENGINE_VERSION_RE[engine].exec(ua)) == null ? void 0 : _c[1]) != null ? _d : "unknown" : "unknown";
289
+ return { engine, engineVersion };
199
290
  }
200
291
 
201
- // src/constants/os.ts
202
- var OS_DEFS = [
203
- { name: "WebOS", detect: /hpwOS/, versionPattern: /hpwOS\/([\d.]+)/ },
204
- { name: "Symbian", detect: /Symbian/, versionPattern: null },
205
- { name: "MeeGo", detect: /MeeGo/, versionPattern: null },
206
- { name: "BlackBerry", detect: /(BlackBerry|RIM)/, versionPattern: null },
207
- { name: "FreeBSD", detect: /FreeBSD/, versionPattern: null },
208
- { name: "Debian", detect: /Debian/, versionPattern: /Debian\/([\d.]+)/ },
209
- { name: "Ubuntu", detect: /Ubuntu/, versionPattern: null },
210
- // Linux must come before Chrome OS: Chrome OS UAs contain "X11", so Linux matches first,
211
- // then Chrome OS overrides it.
212
- { name: "Linux", detect: /(Linux|X11)/, versionPattern: null },
213
- { name: "Chrome OS", detect: /CrOS/, versionPattern: null },
214
- { name: "Tizen", detect: /Tizen/, versionPattern: /Tizen ([\d.]+)/ },
215
- { name: "iOS", detect: /like Mac OS X/, versionPattern: /OS ([\d_]+) like/ },
216
- { name: "MacOS", detect: /Macintosh/, versionPattern: /Mac OS X -?([\d_.]+)/ },
217
- // visionOS / tvOS must come AFTER iOS: their UAs also contain "like Mac OS X",
218
- // so they need to override iOS via the last-match-wins iteration.
219
- { name: "visionOS", detect: /visionOS/, versionPattern: /visionOS ([\d_]+)/ },
220
- { name: "tvOS", detect: /Apple TV/, versionPattern: /OS ([\d_]+) like/ },
221
- { name: "Android", detect: /(Android|Adr)/, versionPattern: /(?:Android|Adr) ([\d.]+)/ },
222
- // HarmonyOS must come after Android: HarmonyOS UAs include "Android", so Android matches
223
- // first, then HarmonyOS overrides it. versionPattern tries direct extraction first (5.0+
224
- // pure HarmonyOS UAs don't have Android token), then falls back to Android version + lookup.
225
- {
226
- name: "HarmonyOS",
227
- detect: /HarmonyOS/,
228
- versionPattern: [/HarmonyOS[\s/]([\d.]+)/, /Android ([\d.]+)[;)]/],
229
- versionLookup: { "10": "2", "11": "3", "12": "3", "13": "4" }
230
- },
231
- // OpenHarmony (open-source base) must come after HarmonyOS to override any earlier match.
232
- { name: "OpenHarmony", detect: /OpenHarmony/, versionPattern: /OpenHarmony[\s/]([\d.]+)/ },
233
- { name: "KaiOS", detect: /KAIOS/, versionPattern: /KAIOS\/([\d.]+)/ },
234
- // Windows must come before Windows Phone: Windows Phone UAs contain "Windows", so Windows
235
- // matches first, then Windows Phone overrides it.
236
- {
237
- name: "Windows",
238
- detect: /Windows/,
239
- versionPattern: /Windows NT ([\d.]+)/,
240
- versionLookup: {
241
- "10": "10",
242
- "6.4": "10",
243
- "6.3": "8.1",
244
- "6.2": "8",
245
- "6.1": "7",
246
- "6.0": "Vista",
247
- "5.2": "XP",
248
- "5.1": "XP",
249
- "5.0": "2000"
250
- }
251
- },
252
- { name: "Windows Phone", detect: /(IEMobile|Windows Phone)/, versionPattern: /Windows Phone(?: OS)? ([\d.]+)/ }
253
- ];
254
-
255
292
  // src/detectors/os.ts
293
+ function lookupVersionName(map, version) {
294
+ const parts = version.split(".");
295
+ for (let len = parts.length; len >= 1; len--) {
296
+ const key = parts.slice(0, len).join(".");
297
+ if (Object.prototype.hasOwnProperty.call(map, key)) return map[key];
298
+ }
299
+ return "unknown";
300
+ }
256
301
  function detectOs(ua, windowsVersion) {
257
302
  let matchedDef = null;
258
303
  for (const def of OS_DEFS) {
@@ -260,7 +305,7 @@ function detectOs(ua, windowsVersion) {
260
305
  matchedDef = def;
261
306
  }
262
307
  }
263
- if (!matchedDef) return { os: "unknown", osVersion: "unknown" };
308
+ if (!matchedDef) return { os: "unknown", osVersion: "unknown", osVersionName: "unknown" };
264
309
  let osVersion = "unknown";
265
310
  if (matchedDef.versionPattern) {
266
311
  const raw = Array.isArray(matchedDef.versionPattern) ? extractVersionFromPatterns(ua, matchedDef.versionPattern) : extractVersion(ua, matchedDef.versionPattern);
@@ -284,7 +329,8 @@ function detectOs(ua, windowsVersion) {
284
329
  if (matchedDef.name === "Windows" && windowsVersion) {
285
330
  osVersion = windowsVersion;
286
331
  }
287
- return { os: matchedDef.name, osVersion };
332
+ const osVersionName = matchedDef.versionNames ? lookupVersionName(matchedDef.versionNames, osVersion) : "unknown";
333
+ return { os: matchedDef.name, osVersion, osVersionName };
288
334
  }
289
335
 
290
336
  // src/constants/devices.ts
@@ -349,57 +395,93 @@ function detectDevice(ua, nav) {
349
395
  }
350
396
  return (_b = (_a = hwDetect()) != null ? _a : uaDetect()) != null ? _b : "PC";
351
397
  }
398
+ var VENDOR_MAP = [
399
+ [/^SM-|^GT-|^SGH-|^SCH-|^SHW-|^SPH-|^SAMSUNG /i, "Samsung"],
400
+ [/^Pixel |^Nexus /, "Google"],
401
+ [/^moto |^motorola /i, "Motorola"],
402
+ [/^HONOR /i, "Honor"],
403
+ [/^ELS-|^LYA-|^HMA-|^VOG-|^ANA-|^CLT-|^JNY-|^NOH-|^PLK-|^BAH-|^BKL-|^COL-|^DUB-|^FIG-|^KIW-|^MAR-|^VTR-|^WAS-/i, "Huawei"],
404
+ [/^CPH/, "OPPO"],
405
+ [/^RMX/, "Realme"],
406
+ [/^V\d{4}[A-Z]|^vivo /i, "Vivo"],
407
+ [/^iqoo/i, "Vivo"],
408
+ [/^Redmi |^POCO |^Mi /, "Xiaomi"],
409
+ [/^2\d{9}|^2\d{3}[A-Z]/, "Xiaomi"],
410
+ [/^OnePlus |^IN2|^KB2|^LE2/i, "OnePlus"],
411
+ [/^LM-|^LGE |^LG-/i, "LG"],
412
+ [/^HTC/i, "HTC"],
413
+ [/^Nokia/i, "Nokia"],
414
+ [/^XQ-/, "Sony"],
415
+ [/^ASUS_|^ZB6|^ZS6|^ZE[56]/i, "Asus"],
416
+ [/^Quest /i, "Meta"]
417
+ ];
418
+ var ANDROID_MODEL_RE = /Android [0-9.]+;(?:\s*U;)?(?:\s*[a-z]{2}[-_][a-zA-Z]{2,4};)?\s*([^;)]+?)(?:\s+Build\/|[;)])/;
419
+ function detectVendorModel(ua) {
420
+ if (/visionOS/.test(ua)) return { vendor: "Apple", model: "Apple Vision Pro" };
421
+ if (/iPhone/.test(ua)) return { vendor: "Apple", model: "iPhone" };
422
+ if (/iPad/.test(ua)) return { vendor: "Apple", model: "iPad" };
423
+ if (/iPod/.test(ua)) return { vendor: "Apple", model: "iPod touch" };
424
+ const m = ANDROID_MODEL_RE.exec(ua);
425
+ if (m) {
426
+ const model = m[1].trim();
427
+ for (const [re, vendor] of VENDOR_MAP) {
428
+ if (re.test(model)) return { vendor, model };
429
+ }
430
+ return { vendor: "unknown", model };
431
+ }
432
+ return { vendor: "unknown", model: "unknown" };
433
+ }
352
434
 
353
435
  // src/constants/bots.ts
354
436
  var BOT_DEFS = [
355
437
  // Search engines
356
- { name: "Googlebot", detect: /Googlebot/ },
357
- { name: "Bingbot", detect: /(bingbot|BingPreview)/ },
358
- { name: "Baiduspider", detect: /(Baiduspider|BaiduMobaider)/ },
359
- { name: "Bytespider", detect: /Bytespider/ },
360
- { name: "YandexBot", detect: /YandexBot/ },
361
- { name: "DuckDuckBot", detect: /DuckDuckBot/ },
362
- { name: "Slurp", detect: /Slurp/ },
363
- { name: "Sogou", detect: /(Sogou|sogou).*[Ss]pider/ },
364
- { name: "360Spider", detect: /360Spider/ },
365
- { name: "PetalBot", detect: /PetalBot/ },
366
- { name: "Applebot-Extended", detect: /Applebot-Extended/ },
367
- { name: "Applebot", detect: /Applebot/ },
438
+ { name: "Googlebot", detect: /Googlebot/, category: "search-engine" },
439
+ { name: "Bingbot", detect: /(bingbot|BingPreview)/, category: "search-engine" },
440
+ { name: "Baiduspider", detect: /(Baiduspider|BaiduMobaider)/, category: "search-engine" },
441
+ { name: "Bytespider", detect: /Bytespider/, category: "search-engine" },
442
+ { name: "YandexBot", detect: /YandexBot/, category: "search-engine" },
443
+ { name: "DuckDuckBot", detect: /DuckDuckBot/, category: "search-engine" },
444
+ { name: "Slurp", detect: /Slurp/, category: "search-engine" },
445
+ { name: "Sogou", detect: /(Sogou|sogou).*[Ss]pider/, category: "search-engine" },
446
+ { name: "360Spider", detect: /360Spider/, category: "search-engine" },
447
+ { name: "PetalBot", detect: /PetalBot/, category: "search-engine" },
448
+ { name: "Applebot-Extended", detect: /Applebot-Extended/, category: "search-engine" },
449
+ { name: "Applebot", detect: /Applebot/, category: "search-engine" },
368
450
  // Social media crawlers
369
- { name: "Facebookbot", detect: /(facebookexternalhit|FacebookBot)/ },
370
- { name: "Twitterbot", detect: /Twitterbot/ },
371
- { name: "LinkedInBot", detect: /LinkedInBot/ },
372
- { name: "PinterestBot", detect: /Pinterest/ },
451
+ { name: "Facebookbot", detect: /(facebookexternalhit|FacebookBot)/, category: "social" },
452
+ { name: "Twitterbot", detect: /Twitterbot/, category: "social" },
453
+ { name: "LinkedInBot", detect: /LinkedInBot/, category: "social" },
454
+ { name: "PinterestBot", detect: /Pinterest/, category: "social" },
373
455
  // Messaging link preview bots
374
- { name: "Slackbot", detect: /Slackbot/ },
375
- { name: "Discordbot", detect: /Discordbot/ },
376
- { name: "TelegramBot", detect: /TelegramBot/ },
377
- { name: "WhatsApp", detect: /WhatsApp/ },
456
+ { name: "Slackbot", detect: /Slackbot/, category: "link-preview" },
457
+ { name: "Discordbot", detect: /Discordbot/, category: "link-preview" },
458
+ { name: "TelegramBot", detect: /TelegramBot/, category: "link-preview" },
459
+ { name: "WhatsApp", detect: /WhatsApp/, category: "link-preview" },
378
460
  // SEO tools
379
- { name: "SemrushBot", detect: /SemrushBot/ },
380
- { name: "AhrefsBot", detect: /AhrefsBot/ },
381
- { name: "MJ12bot", detect: /MJ12bot/ },
382
- { name: "ScreamingFrog", detect: /Screaming Frog/ },
383
- { name: "DataForSeoBot", detect: /DataForSeoBot/ },
461
+ { name: "SemrushBot", detect: /SemrushBot/, category: "seo-tool" },
462
+ { name: "AhrefsBot", detect: /AhrefsBot/, category: "seo-tool" },
463
+ { name: "MJ12bot", detect: /MJ12bot/, category: "seo-tool" },
464
+ { name: "ScreamingFrog", detect: /Screaming Frog/, category: "seo-tool" },
465
+ { name: "DataForSeoBot", detect: /DataForSeoBot/, category: "seo-tool" },
384
466
  // AI / LLM crawlers
385
- { name: "GPTBot", detect: /GPTBot/ },
386
- { name: "OAI-SearchBot", detect: /OAI-SearchBot/ },
387
- { name: "ChatGPT-User", detect: /ChatGPT-User/ },
388
- { name: "ClaudeBot", detect: /ClaudeBot/ },
389
- { name: "PerplexityBot", detect: /PerplexityBot/ },
390
- { name: "CCBot", detect: /CCBot/ },
391
- { name: "AdsBot", detect: /AdsBot-Google/ },
392
- { name: "Google-Extended", detect: /Google-Extended/ },
393
- { name: "Meta-ExternalAgent", detect: /meta-externalagent/i },
394
- { name: "Amazonbot", detect: /Amazonbot/ },
395
- { name: "Diffbot", detect: /Diffbot/ },
396
- { name: "cohere-ai", detect: /cohere-ai/ },
397
- { name: "YouBot", detect: /YouBot/ },
467
+ { name: "GPTBot", detect: /GPTBot/, category: "ai-llm" },
468
+ { name: "OAI-SearchBot", detect: /OAI-SearchBot/, category: "ai-llm" },
469
+ { name: "ChatGPT-User", detect: /ChatGPT-User/, category: "ai-llm" },
470
+ { name: "ClaudeBot", detect: /ClaudeBot/, category: "ai-llm" },
471
+ { name: "PerplexityBot", detect: /PerplexityBot/, category: "ai-llm" },
472
+ { name: "CCBot", detect: /CCBot/, category: "ai-llm" },
473
+ { name: "AdsBot", detect: /AdsBot-Google/, category: "ai-llm" },
474
+ { name: "Google-Extended", detect: /Google-Extended/, category: "ai-llm" },
475
+ { name: "Meta-ExternalAgent", detect: /meta-externalagent/i, category: "ai-llm" },
476
+ { name: "Amazonbot", detect: /Amazonbot/, category: "ai-llm" },
477
+ { name: "Diffbot", detect: /Diffbot/, category: "ai-llm" },
478
+ { name: "cohere-ai", detect: /cohere-ai/, category: "ai-llm" },
479
+ { name: "YouBot", detect: /YouBot/, category: "ai-llm" },
398
480
  // Monitoring / archiving
399
- { name: "UptimeRobot", detect: /UptimeRobot/ },
400
- { name: "ia_archiver", detect: /ia_archiver/ },
481
+ { name: "UptimeRobot", detect: /UptimeRobot/, category: "monitoring" },
482
+ { name: "ia_archiver", detect: /ia_archiver/, category: "monitoring" },
401
483
  // Generic catch-all (must be last)
402
- { name: "GenericBot", detect: /(bot|crawler|spider|crawling|scraper)/i }
484
+ { name: "GenericBot", detect: /(bot|crawler|spider|crawling|scraper)/i, category: "generic" }
403
485
  ];
404
486
 
405
487
  // src/detectors/bot.ts
@@ -407,10 +489,10 @@ function detectBot(ua, customDefs) {
407
489
  const defs = customDefs ? [...BOT_DEFS.slice(0, -1), ...customDefs, BOT_DEFS[BOT_DEFS.length - 1]] : BOT_DEFS;
408
490
  for (const def of defs) {
409
491
  if (def.detect.test(ua)) {
410
- return { isBot: true, botName: def.name };
492
+ return { isBot: true, botName: def.name, botCategory: def.category };
411
493
  }
412
494
  }
413
- return { isBot: false, botName: "unknown" };
495
+ return { isBot: false, botName: "unknown", botCategory: "unknown" };
414
496
  }
415
497
 
416
498
  // src/constants/arch.ts
@@ -577,14 +659,15 @@ function parseUA(ua, options = {}) {
577
659
  var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p;
578
660
  const effectiveNav = (_a = options.ctx) != null ? _a : options.nav;
579
661
  const effectiveWindowsVersion = (_c = (_b = options.ctx) == null ? void 0 : _b.windowsVersion) != null ? _c : options.windowsVersion;
580
- const { browser: rawBrowser, version: rawVersion } = detectBrowser(ua);
581
- const { os: rawOs, osVersion: rawOsVersion } = detectOs(ua, effectiveWindowsVersion);
662
+ const { browser: rawBrowser, version: rawVersion, browserType } = detectBrowser(ua);
663
+ const { os: rawOs, osVersion: rawOsVersion, osVersionName } = detectOs(ua, effectiveWindowsVersion);
582
664
  let os = rawOs;
583
665
  let osVersion = rawOsVersion;
584
666
  const device = detectDevice(ua, effectiveNav);
667
+ const { vendor, model } = detectVendorModel(ua);
585
668
  const arch = detectArch(ua, (_d = options.ctx) != null ? _d : effectiveNav);
586
669
  const nav = effectiveNav;
587
- const { isBot, botName } = detectBot(ua, options.customBotDefs);
670
+ const { isBot, botName, botCategory } = detectBot(ua, options.customBotDefs);
588
671
  const isHeadless = detectHeadless(ua);
589
672
  const language = options.language || ((nav == null ? void 0 : nav.language) || (nav == null ? void 0 : nav.browserLanguage) ? getLanguage(nav) : "") || languageFromUA(ua);
590
673
  const platform = (nav == null ? void 0 : nav.platform) || platformFromUA(ua);
@@ -681,22 +764,39 @@ function parseUA(ua, options = {}) {
681
764
  }
682
765
  }
683
766
  }
684
- const engine = detectEngine(ua, browser, version);
767
+ const { engine, engineVersion } = detectEngine(ua, browser, version);
685
768
  const versionMajor = parseInt((_l = version.split(".")[0]) != null ? _l : "0", 10) || 0;
686
769
  const connectionType = (_p = (_o = (_n = (_m = options.ctx) != null ? _m : options.nav) == null ? void 0 : _n.connection) == null ? void 0 : _o.effectiveType) != null ? _p : "unknown";
770
+ const finalOsVersionName = os === "MacOS" || os === "Windows" ? (() => {
771
+ var _a2;
772
+ const map = (_a2 = OS_DEFS.find((d) => d.name === os)) == null ? void 0 : _a2.versionNames;
773
+ if (!map) return "unknown";
774
+ const parts = osVersion.split(".");
775
+ for (let len = parts.length; len >= 1; len--) {
776
+ const key = parts.slice(0, len).join(".");
777
+ if (Object.prototype.hasOwnProperty.call(map, key)) return map[key];
778
+ }
779
+ return "unknown";
780
+ })() : osVersionName;
687
781
  return {
688
782
  browser,
689
783
  version,
690
784
  versionMajor,
785
+ browserType: browser === "Brave" ? "browser" : browserType,
691
786
  engine,
787
+ engineVersion,
692
788
  os,
693
789
  osVersion,
790
+ osVersionName: finalOsVersionName,
694
791
  device,
792
+ vendor,
793
+ model,
695
794
  arch,
696
795
  isWebview: isWebview(ua),
697
796
  isHeadless,
698
797
  isBot,
699
798
  botName,
799
+ botCategory,
700
800
  language,
701
801
  platform,
702
802
  connectionType
@@ -956,6 +1056,6 @@ uaBrowser.getLanguage = () => getLanguage(getNavContext());
956
1056
  uaBrowser.VERSION = VERSION;
957
1057
  var src_default = uaBrowser;
958
1058
 
959
- export { ACCEPT_CH, VERSION, src_default as default, detectArch, detectBot, detectBrowser, detectDevice, detectEngine, detectHeadless, detectOs as detectOS, getEnvContext, getLanguage, getNavContext, getWindowsVersion, isWebview, parseHeaders, parseUA, satisfies };
1059
+ export { ACCEPT_CH, VERSION, src_default as default, detectArch, detectBot, detectBrowser, detectDevice, detectEngine, detectHeadless, detectOs as detectOS, detectVendorModel, getEnvContext, getLanguage, getNavContext, getWindowsVersion, isWebview, parseHeaders, parseUA, satisfies };
960
1060
  //# sourceMappingURL=index.mjs.map
961
1061
  //# sourceMappingURL=index.mjs.map