ua-browser 1.4.0 → 1.4.2

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,24 +1,23 @@
1
1
  // package.json
2
2
  var package_default = {
3
- version: "1.4.0"};
3
+ version: "1.4.2"};
4
4
 
5
5
  // src/constants/os.ts
6
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/ },
7
+ { name: "WebOS", priority: 20, detect: /hpwOS/, versionPattern: /hpwOS\/([\d.]+)/ },
8
+ { name: "Symbian", priority: 20, detect: /Symbian/, versionPattern: null },
9
+ { name: "MeeGo", priority: 20, detect: /MeeGo/, versionPattern: null },
10
+ { name: "BlackBerry", priority: 20, detect: /(BlackBerry|RIM)/, versionPattern: null },
11
+ { name: "FreeBSD", priority: 20, detect: /FreeBSD/, versionPattern: null },
12
+ { name: "Debian", priority: 20, detect: /Debian/, versionPattern: /Debian\/([\d.]+)/ },
13
+ { name: "Ubuntu", priority: 20, detect: /Ubuntu/, versionPattern: null },
14
+ { name: "Linux", priority: 10, detect: /(Linux|X11)/, versionPattern: null },
15
+ { name: "Chrome OS", priority: 30, detect: /CrOS/, versionPattern: null },
16
+ { name: "Tizen", priority: 20, detect: /Tizen/, versionPattern: /Tizen ([\d.]+)/ },
17
+ { name: "iOS", priority: 20, detect: /like Mac OS X/, versionPattern: /OS ([\d_]+) like/ },
20
18
  {
21
19
  name: "MacOS",
20
+ priority: 20,
22
21
  detect: /Macintosh/,
23
22
  versionPattern: /Mac OS X -?([\d_.]+)/,
24
23
  versionNames: {
@@ -36,27 +35,21 @@ var OS_DEFS = [
36
35
  "15": "Sequoia"
37
36
  }
38
37
  },
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.
38
+ { name: "visionOS", priority: 30, detect: /visionOS/, versionPattern: /visionOS ([\d_]+)/ },
39
+ { name: "tvOS", priority: 30, detect: /Apple TV/, versionPattern: /OS ([\d_]+) like/ },
40
+ { name: "Android", priority: 20, detect: /(Android|Adr)/, versionPattern: /(?:Android|Adr) ([\d.]+)/ },
47
41
  {
48
42
  name: "HarmonyOS",
43
+ priority: 30,
49
44
  detect: /HarmonyOS/,
50
45
  versionPattern: [/HarmonyOS[\s/]([\d.]+)/, /Android ([\d.]+)[;)]/],
51
- versionLookup: { "10": "2", "11": "3", "12": "3", "13": "4" }
46
+ versionLookup: { "10": "2", "11": "3", "12": "3", "13": "4", "14": "4" }
52
47
  },
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.
48
+ { name: "OpenHarmony", priority: 30, detect: /OpenHarmony/, versionPattern: /OpenHarmony[\s/]([\d.]+)/ },
49
+ { name: "KaiOS", priority: 30, detect: /KAIOS/, versionPattern: /KAIOS\/([\d.]+)/ },
58
50
  {
59
51
  name: "Windows",
52
+ priority: 10,
60
53
  detect: /Windows/,
61
54
  versionPattern: /Windows NT ([\d.]+)/,
62
55
  versionLookup: {
@@ -78,7 +71,7 @@ var OS_DEFS = [
78
71
  "11": "Windows 11"
79
72
  }
80
73
  },
81
- { name: "Windows Phone", detect: /(IEMobile|Windows Phone)/, versionPattern: /Windows Phone(?: OS)? ([\d.]+)/ }
74
+ { name: "Windows Phone", priority: 30, detect: /(IEMobile|Windows Phone)/, versionPattern: /Windows Phone(?: OS)? ([\d.]+)/ }
82
75
  ];
83
76
 
84
77
  // src/constants/browsers.ts
@@ -300,9 +293,11 @@ function lookupVersionName(map, version) {
300
293
  }
301
294
  function detectOs(ua, windowsVersion) {
302
295
  let matchedDef = null;
296
+ let bestPriority = -1;
303
297
  for (const def of OS_DEFS) {
304
- if (def.detect.test(ua)) {
298
+ if (def.detect.test(ua) && def.priority > bestPriority) {
305
299
  matchedDef = def;
300
+ bestPriority = def.priority;
306
301
  }
307
302
  }
308
303
  if (!matchedDef) return { os: "unknown", osVersion: "unknown", osVersionName: "unknown" };
@@ -451,7 +446,7 @@ var BOT_DEFS = [
451
446
  { name: "Facebookbot", detect: /(facebookexternalhit|FacebookBot)/, category: "social" },
452
447
  { name: "Twitterbot", detect: /Twitterbot/, category: "social" },
453
448
  { name: "LinkedInBot", detect: /LinkedInBot/, category: "social" },
454
- { name: "PinterestBot", detect: /Pinterest/, category: "social" },
449
+ { name: "PinterestBot", detect: /Pinterestbot/i, category: "social" },
455
450
  // Messaging link preview bots
456
451
  { name: "Slackbot", detect: /Slackbot/, category: "link-preview" },
457
452
  { name: "Discordbot", detect: /Discordbot/, category: "link-preview" },
@@ -468,14 +463,19 @@ var BOT_DEFS = [
468
463
  { name: "OAI-SearchBot", detect: /OAI-SearchBot/, category: "ai-llm" },
469
464
  { name: "ChatGPT-User", detect: /ChatGPT-User/, category: "ai-llm" },
470
465
  { name: "ClaudeBot", detect: /ClaudeBot/, category: "ai-llm" },
466
+ { name: "Claude-User", detect: /Claude-User/, category: "ai-llm" },
467
+ { name: "Claude-SearchBot", detect: /Claude-SearchBot/, category: "ai-llm" },
471
468
  { name: "PerplexityBot", detect: /PerplexityBot/, category: "ai-llm" },
472
469
  { name: "CCBot", detect: /CCBot/, category: "ai-llm" },
473
- { name: "AdsBot", detect: /AdsBot-Google/, category: "ai-llm" },
470
+ { name: "AdsBot", detect: /AdsBot-Google/, category: "search-engine" },
474
471
  { name: "Google-Extended", detect: /Google-Extended/, category: "ai-llm" },
475
472
  { name: "Meta-ExternalAgent", detect: /meta-externalagent/i, category: "ai-llm" },
476
473
  { name: "Amazonbot", detect: /Amazonbot/, category: "ai-llm" },
477
474
  { name: "Diffbot", detect: /Diffbot/, category: "ai-llm" },
478
475
  { name: "cohere-ai", detect: /cohere-ai/, category: "ai-llm" },
476
+ { name: "MistralAI-User", detect: /MistralAI-User/, category: "ai-llm" },
477
+ { name: "DeepSeekBot", detect: /DeepSeekBot/, category: "ai-llm" },
478
+ { name: "XAI-Crawler", detect: /XAI-Crawler/, category: "ai-llm" },
479
479
  { name: "YouBot", detect: /YouBot/, category: "ai-llm" },
480
480
  // Monitoring / archiving
481
481
  { name: "UptimeRobot", detect: /UptimeRobot/, category: "monitoring" },
@@ -580,6 +580,7 @@ var BRAND_TO_BROWSER = [
580
580
  ["Microsoft Edge", "Edge"],
581
581
  ["Opera", "Opera"],
582
582
  ["Vivaldi", "Vivaldi"],
583
+ ["Brave", "Brave"],
583
584
  ["Google Chrome", "Chrome"],
584
585
  ["Chromium", "Chromium"]
585
586
  ];
@@ -644,6 +645,82 @@ function normalizeBCP47(raw) {
644
645
  return p.toUpperCase();
645
646
  }).join("-");
646
647
  }
648
+ var ISO_639_1 = /* @__PURE__ */ new Set([
649
+ "af",
650
+ "am",
651
+ "ar",
652
+ "az",
653
+ "be",
654
+ "bg",
655
+ "bn",
656
+ "bs",
657
+ "ca",
658
+ "cs",
659
+ "cy",
660
+ "da",
661
+ "de",
662
+ "el",
663
+ "en",
664
+ "es",
665
+ "et",
666
+ "eu",
667
+ "fa",
668
+ "fi",
669
+ "fr",
670
+ "ga",
671
+ "gl",
672
+ "gu",
673
+ "he",
674
+ "hi",
675
+ "hr",
676
+ "hu",
677
+ "hy",
678
+ "id",
679
+ "is",
680
+ "it",
681
+ "ja",
682
+ "ka",
683
+ "kk",
684
+ "km",
685
+ "kn",
686
+ "ko",
687
+ "lt",
688
+ "lv",
689
+ "mk",
690
+ "ml",
691
+ "mn",
692
+ "mr",
693
+ "ms",
694
+ "mt",
695
+ "my",
696
+ "nb",
697
+ "ne",
698
+ "nl",
699
+ "no",
700
+ "pa",
701
+ "pl",
702
+ "pt",
703
+ "ro",
704
+ "ru",
705
+ "si",
706
+ "sk",
707
+ "sl",
708
+ "sq",
709
+ "sr",
710
+ "sv",
711
+ "sw",
712
+ "ta",
713
+ "te",
714
+ "th",
715
+ "tl",
716
+ "tr",
717
+ "uk",
718
+ "ur",
719
+ "uz",
720
+ "vi",
721
+ "zh",
722
+ "zu"
723
+ ]);
647
724
  function languageFromUA(ua) {
648
725
  const kwMatch = /\bLanguage\/([a-zA-Z]{2,3}(?:[-_][a-zA-Z]{2,4}){1,2})\b/i.exec(ua);
649
726
  if (kwMatch) return normalizeBCP47(kwMatch[1]);
@@ -653,6 +730,10 @@ function languageFromUA(ua) {
653
730
  const parts = m[1].replace(/_/g, "-").split("-");
654
731
  if (parts.length >= 2) return normalizeBCP47(m[1]);
655
732
  }
733
+ const bare = /[;(]\s*([a-z]{2,3})\s*[;)]/g;
734
+ while ((m = bare.exec(ua)) !== null) {
735
+ if (ISO_639_1.has(m[1])) return m[1];
736
+ }
656
737
  return "unknown";
657
738
  }
658
739
  function parseUA(ua, options = {}) {
@@ -709,20 +790,8 @@ function parseUA(ua, options = {}) {
709
790
  const opVer = (_h = (_g = /OPR\/([\d.]+)/.exec(ua)) != null ? _g : /OPT\/([\d.]+)/.exec(ua)) != null ? _h : /Opera\/([\d.]+)/.exec(ua);
710
791
  version = (_i = opVer == null ? void 0 : opVer[1]) != null ? _i : "unknown";
711
792
  }
712
- if (browser === "Chrome" && /\S+Browser\//.test(ua)) {
713
- const m = /(\S+Browser)\/([\d.]+)/.exec(ua);
714
- if (m) {
715
- browser = m[1];
716
- version = m[2];
717
- }
718
- }
719
- if (browser === "Firefox" && nav) {
720
- try {
721
- if (typeof clientInformation !== "undefined" || typeof u2f === "undefined") {
722
- browser = "Firefox Nightly";
723
- }
724
- } catch (e) {
725
- }
793
+ if (browser === "Firefox" && /Firefox\/[\d.]+a\d/.test(ua)) {
794
+ browser = "Firefox Nightly";
726
795
  }
727
796
  if (os === "iOS" && browser === "Safari") {
728
797
  const m = /Version\/([\d.]+)/.exec(ua);
@@ -765,7 +834,8 @@ function parseUA(ua, options = {}) {
765
834
  }
766
835
  }
767
836
  const { engine, engineVersion } = detectEngine(ua, browser, version);
768
- const versionMajor = parseInt((_l = version.split(".")[0]) != null ? _l : "0", 10) || 0;
837
+ const major = parseInt((_l = version.split(".")[0]) != null ? _l : "", 10);
838
+ const versionMajor = Number.isNaN(major) ? 0 : major;
769
839
  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
840
  const finalOsVersionName = os === "MacOS" || os === "Windows" ? (() => {
771
841
  var _a2;
@@ -1006,7 +1076,7 @@ function deriveWindowsVersion2(platformVersion) {
1006
1076
  return isNaN(major) ? null : major >= 13 ? "11" : "10";
1007
1077
  }
1008
1078
  function parseHeaders(headers) {
1009
- var _a, _b, _c, _d, _e;
1079
+ var _a, _b, _c, _d, _e, _f;
1010
1080
  const normalised = {};
1011
1081
  for (const key of Object.keys(headers)) {
1012
1082
  normalised[key.toLowerCase()] = headers[key];
@@ -1023,12 +1093,24 @@ function parseHeaders(headers) {
1023
1093
  const model = unquote(get("sec-ch-ua-model"));
1024
1094
  const platformVersion = unquote(get("sec-ch-ua-platform-version"));
1025
1095
  const platform = (_e = unquote(get("sec-ch-ua-platform"))) != null ? _e : "";
1096
+ const fullVersionListRaw = get("sec-ch-ua-full-version-list");
1097
+ const fullVersionList = [];
1098
+ if (fullVersionListRaw) {
1099
+ const re = /"([^"]+)";v="([^"]+)"/g;
1100
+ let m;
1101
+ while ((m = re.exec(fullVersionListRaw)) !== null) {
1102
+ fullVersionList.push({ brand: m[1], version: m[2] });
1103
+ }
1104
+ }
1026
1105
  const highEntropyData = {};
1027
1106
  if (architecture !== void 0) highEntropyData.architecture = architecture;
1028
1107
  if (bitness !== void 0) highEntropyData.bitness = bitness;
1029
1108
  if (model !== void 0) highEntropyData.model = model;
1030
1109
  if (platformVersion !== void 0) highEntropyData.platformVersion = platformVersion;
1110
+ if (fullVersionList.length > 0) highEntropyData.fullVersionList = fullVersionList;
1031
1111
  const isMobile = get("sec-ch-ua-mobile") === "?1";
1112
+ const secCHUA = (_f = get("sec-ch-ua")) != null ? _f : "";
1113
+ const hasBrave = /"Brave"/.test(secCHUA);
1032
1114
  const windowsVersion = platform === "Windows" ? deriveWindowsVersion2(platformVersion) : null;
1033
1115
  const ctx = {
1034
1116
  userAgent: ua,
@@ -1036,7 +1118,8 @@ function parseHeaders(headers) {
1036
1118
  language,
1037
1119
  maxTouchPoints: isMobile ? 1 : 0,
1038
1120
  highEntropyData: Object.keys(highEntropyData).length > 0 ? highEntropyData : void 0,
1039
- windowsVersion
1121
+ windowsVersion,
1122
+ hasBrave
1040
1123
  };
1041
1124
  return parseUA(ua, { ctx });
1042
1125
  }