countly-sdk-web 26.1.0 → 26.1.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/CHANGELOG.md CHANGED
@@ -1,3 +1,7 @@
1
+ ## 26.1.1
2
+
3
+ - Improved device metric detection capabilities.
4
+
1
5
  ## 26.1.0
2
6
 
3
7
  - Added support for SBS flags:
@@ -15,7 +15,7 @@ function initMain(name, version) {
15
15
  }
16
16
 
17
17
  const SDK_NAME = "javascript_native_web";
18
- const SDK_VERSION = "26.1.0";
18
+ const SDK_VERSION = "26.1.1";
19
19
 
20
20
  // tests
21
21
  describe("Bridged SDK Utilities Tests", () => {
@@ -3,7 +3,7 @@
3
3
  var Countly = require("../../lib/countly");
4
4
  var hp = require("../support/helper.js");
5
5
  const SDK_NAME = "javascript_native_web";
6
- const SDK_VERSION = "26.1.0";
6
+ const SDK_VERSION = "26.1.1";
7
7
 
8
8
  function initMain(name, version) {
9
9
  Countly.init({
@@ -0,0 +1,63 @@
1
+ <!doctype html>
2
+ <html>
3
+
4
+ <head>
5
+ <meta charset="utf-8">
6
+ <title>Countly Unified Async Loader</title>
7
+ <link rel="stylesheet" type="text/css" href="./style/style.css">
8
+ <script type="text/javascript">
9
+ (function(l,t){function y(c){return function(){p.push([c].concat(Array.prototype.slice.call(arguments,0)));return d}}function u(c,a,e){e=y(e||a);e.__isCountlyStub=!0;c[a]=e}function z(c){if(!v&&!m){m=!0;var a=t.createElement("script");a.type="text/javascript";a.async=!0;a.src=c;a.crossOrigin="anonymous";a.onload=function(){v=!0;m=!1;var h=l.Countly;h&&"function"===typeof h.init&&h.init(w||{});h=l.Countly;var x=p.slice();p=[];for(var q=0;q<x.length;q++){var b=x[q],f=h,A=b.slice(1);b=b[0].split(".");
10
+ for(var r=0;r<b.length-1;r++)f=f&&f[b[r]];b=b[b.length-1];b=f&&f[b];"function"!==typeof b||b.__isCountlyStub||b.apply(f,A||[])}};a.onerror=function(){m=!1;console.error("Countly loader failed to load SDK from:",c)};var e=t.getElementsByTagName("script")[0];e.parentNode.insertBefore(a,e)}}var d=l.Countly||(l.Countly={}),p=[],m=!1,v=!1,w=null;d.__clyBootstrap={version:"1.0.0",name:"countly-unified-loader"};for(var n="track_sessions track_pageview track_performance add_event user_details track_errors track_forms track_clicks track_scrolls track_links recordError change_id set_id uploadUserProfilePicture content.enterContentZone content.refreshContentZone content.exitContentZone feedback.showNPS feedback.showSurvey feedback.showRating userData.set userData.set_once userData.increment userData.increment_by userData.multiply userData.max userData.min userData.push userData.push_unique userData.pull userData.unset userData.save".split(" "),
11
+ k=0;k<n.length;k++){var g=n[k].split(".");2===g.length?(d[g[0]]=d[g[0]]||{},u(d[g[0]],g[1],n[k])):u(d,g[0],n[k])}d.init=function(c,a){"object"===typeof c&&(a=c||{},c=a.app_key);a=a||{};c&&(a.app_key=c);for(var e in a)Object.prototype.hasOwnProperty.call(a,e)&&(d[e]=a[e]);"YOUR_APP_KEY"!==d.app_key&&"https://your.server.ly"!==d.url||console.warn("Please do not use default set of app key and server url");w=a;z(d.sdk_url||"https://cdn.jsdelivr.net/npm/countly-sdk-web@latest/lib/countly.min.js");return d}})(window,
12
+ document);
13
+
14
+ Countly.init("YOUR_APP_KEY", {
15
+ url: "https://YOUR_SERVER_URL",
16
+ debug: true,
17
+ clear_stored_id: true
18
+ });
19
+
20
+ Countly.track_sessions();
21
+ Countly.track_pageview();
22
+ Countly.content.enterContentZone();
23
+
24
+ function clickEvent() {
25
+ Countly.add_event({
26
+ key: "buttonClick",
27
+ segmentation: {
28
+ id: "id"
29
+ }
30
+ });
31
+ }
32
+
33
+ function uploadProfilePicture() {
34
+ var fileInput = document.getElementById("profilePicInput");
35
+ var file = fileInput.files[0];
36
+ if (!file) {
37
+ alert("Please select an image file.");
38
+ return;
39
+ }
40
+ Countly.uploadUserProfilePicture(file);
41
+ }
42
+ </script>
43
+ </head>
44
+
45
+ <body>
46
+ <div id="header">
47
+ <h1>Countly Unified Async Loader</h1>
48
+ <img id="logo" src="./images/logo.png">
49
+ </div>
50
+
51
+ <center>
52
+ <img src="./images/team_countly.jpg" id="wallpaper" />
53
+ <br />
54
+ <input type="button" id="testButton" onclick="clickEvent()" value="Test Button">
55
+ <br /><br />
56
+ <input type="file" id="profilePicInput" accept="image/*">
57
+ <br /><br />
58
+ <input type="button" onclick="uploadProfilePicture()" value="Upload Profile Picture">
59
+ <p><a href="https://countly.com/">Countly</a></p>
60
+ </center>
61
+ </body>
62
+
63
+ </html>
@@ -0,0 +1,152 @@
1
+ (function (w, d) {
2
+ var c = w.Countly || (w.Countly = {});
3
+ var bootstrapMeta = {
4
+ version: "1.0.0",
5
+ name: "countly-unified-loader"
6
+ };
7
+ var pendingCalls = [];
8
+ var isLoading = false;
9
+ var isLoaded = false;
10
+ var initConfig = null;
11
+
12
+ c.__clyBootstrap = bootstrapMeta;
13
+
14
+ function queueCall(methodPath) {
15
+ return function () {
16
+ pendingCalls.push([methodPath].concat(Array.prototype.slice.call(arguments, 0)));
17
+ return c;
18
+ };
19
+ }
20
+
21
+ function addStub(target, methodName, methodPath) {
22
+ var stub = queueCall(methodPath || methodName);
23
+ stub.__isCountlyStub = true;
24
+ target[methodName] = stub;
25
+ }
26
+
27
+ function invokeMethod(root, methodPath, args) {
28
+ var chunks = methodPath.split(".");
29
+ var context = root;
30
+ for (var idx = 0; idx < chunks.length - 1; idx++) {
31
+ context = context && context[chunks[idx]];
32
+ }
33
+ var methodName = chunks[chunks.length - 1];
34
+ var method = context && context[methodName];
35
+ if (typeof method === "function" && !method.__isCountlyStub) {
36
+ method.apply(context, args || []);
37
+ }
38
+ }
39
+
40
+ function flushPendingCalls() {
41
+ var live = w.Countly;
42
+ var queue = pendingCalls.slice();
43
+ pendingCalls = [];
44
+ for (var idx = 0; idx < queue.length; idx++) {
45
+ var call = queue[idx];
46
+ invokeMethod(live, call[0], call.slice(1));
47
+ }
48
+ }
49
+
50
+ function loadSdk(scriptUrl) {
51
+ if (isLoaded || isLoading) {
52
+ return;
53
+ }
54
+ isLoading = true;
55
+
56
+ var script = d.createElement("script");
57
+ script.type = "text/javascript";
58
+ script.async = true;
59
+ script.src = scriptUrl;
60
+ script.crossOrigin = "anonymous";
61
+ script.onload = function () {
62
+ isLoaded = true;
63
+ isLoading = false;
64
+
65
+ var live = w.Countly;
66
+ if (live && typeof live.init === "function") {
67
+ live.init(initConfig || {});
68
+ }
69
+ flushPendingCalls();
70
+ };
71
+ script.onerror = function () {
72
+ isLoading = false;
73
+ console.error("Countly loader failed to load SDK from:", scriptUrl);
74
+ };
75
+
76
+ var first = d.getElementsByTagName("script")[0];
77
+ first.parentNode.insertBefore(script, first);
78
+ }
79
+
80
+ var methods = [
81
+ "track_sessions",
82
+ "track_pageview",
83
+ "track_performance",
84
+ "add_event",
85
+ "user_details",
86
+ "track_errors",
87
+ "track_forms",
88
+ "track_clicks",
89
+ "track_scrolls",
90
+ "track_links",
91
+ "recordError",
92
+ "change_id",
93
+ "set_id",
94
+ "uploadUserProfilePicture",
95
+ "content.enterContentZone",
96
+ "content.refreshContentZone",
97
+ "content.exitContentZone",
98
+ "feedback.showNPS",
99
+ "feedback.showSurvey",
100
+ "feedback.showRating",
101
+ "userData.set",
102
+ "userData.set_once",
103
+ "userData.increment",
104
+ "userData.increment_by",
105
+ "userData.multiply",
106
+ "userData.max",
107
+ "userData.min",
108
+ "userData.push",
109
+ "userData.push_unique",
110
+ "userData.pull",
111
+ "userData.unset",
112
+ "userData.save"
113
+ ];
114
+
115
+ for (var i = 0; i < methods.length; i++) {
116
+ var parts = methods[i].split(".");
117
+ if (parts.length === 2) {
118
+ c[parts[0]] = c[parts[0]] || {};
119
+ addStub(c[parts[0]], parts[1], methods[i]);
120
+ }
121
+ else {
122
+ addStub(c, parts[0], methods[i]);
123
+ }
124
+ }
125
+
126
+ c.init = function (appKey, config) {
127
+ if (typeof appKey === "object") {
128
+ config = appKey || {};
129
+ appKey = config.app_key;
130
+ }
131
+ config = config || {};
132
+
133
+ if (appKey) {
134
+ config.app_key = appKey;
135
+ }
136
+
137
+ for (var key in config) {
138
+ if (Object.prototype.hasOwnProperty.call(config, key)) {
139
+ c[key] = config[key];
140
+ }
141
+ }
142
+
143
+ if (c.app_key === "YOUR_APP_KEY" || c.url === "https://your.server.ly") {
144
+ console.warn("Please do not use default set of app key and server url");
145
+ }
146
+
147
+ initConfig = config;
148
+ var sdkUrl = c.sdk_url || "https://cdn.jsdelivr.net/npm/countly-sdk-web@latest/lib/countly.min.js";
149
+ loadSdk(sdkUrl);
150
+ return c;
151
+ };
152
+ })(window, document);
@@ -0,0 +1,4 @@
1
+ (function(l,t){function y(c){return function(){p.push([c].concat(Array.prototype.slice.call(arguments,0)));return d}}function u(c,a,e){e=y(e||a);e.__isCountlyStub=!0;c[a]=e}function z(c){if(!v&&!m){m=!0;var a=t.createElement("script");a.type="text/javascript";a.async=!0;a.src=c;a.crossOrigin="anonymous";a.onload=function(){v=!0;m=!1;var h=l.Countly;h&&"function"===typeof h.init&&h.init(w||{});h=l.Countly;var x=p.slice();p=[];for(var q=0;q<x.length;q++){var b=x[q],f=h,A=b.slice(1);b=b[0].split(".");
2
+ for(var r=0;r<b.length-1;r++)f=f&&f[b[r]];b=b[b.length-1];b=f&&f[b];"function"!==typeof b||b.__isCountlyStub||b.apply(f,A||[])}};a.onerror=function(){m=!1;console.error("Countly loader failed to load SDK from:",c)};var e=t.getElementsByTagName("script")[0];e.parentNode.insertBefore(a,e)}}var d=l.Countly||(l.Countly={}),p=[],m=!1,v=!1,w=null;d.__clyBootstrap={version:"1.0.0",name:"countly-unified-loader"};for(var n="track_sessions track_pageview track_performance add_event user_details track_errors track_forms track_clicks track_scrolls track_links recordError change_id set_id uploadUserProfilePicture content.enterContentZone content.refreshContentZone content.exitContentZone feedback.showNPS feedback.showSurvey feedback.showRating userData.set userData.set_once userData.increment userData.increment_by userData.multiply userData.max userData.min userData.push userData.push_unique userData.pull userData.unset userData.save".split(" "),
3
+ k=0;k<n.length;k++){var g=n[k].split(".");2===g.length?(d[g[0]]=d[g[0]]||{},u(d[g[0]],g[1],n[k])):u(d,g[0],n[k])}d.init=function(c,a){"object"===typeof c&&(a=c||{},c=a.app_key);a=a||{};c&&(a.app_key=c);for(var e in a)Object.prototype.hasOwnProperty.call(a,e)&&(d[e]=a[e]);"YOUR_APP_KEY"!==d.app_key&&"https://your.server.ly"!==d.url||console.warn("Please do not use default set of app key and server url");w=a;z(d.sdk_url||"https://cdn.jsdelivr.net/npm/countly-sdk-web@latest/lib/countly.min.js");return d}})(window,
4
+ document);
package/lib/countly.js CHANGED
@@ -350,7 +350,7 @@
350
350
  backoffCount: "cly_hc_backoff_count",
351
351
  consecutiveBackoffCount: "cly_hc_consecutive_backoff_count"
352
352
  });
353
- var SDK_VERSION = "26.1.0";
353
+ var SDK_VERSION = "26.1.1";
354
354
  var SDK_NAME = "javascript_native_web";
355
355
 
356
356
  // Using this on document.referrer would return an array with 17 elements in it. The 12th element (array[11]) would be the path we are looking for. Others would be things like password and such (use https://regex101.com/ to check more)
@@ -759,6 +759,109 @@
759
759
  return ua;
760
760
  }
761
761
 
762
+ /**
763
+ * Parse Windows version from UA-CH platformVersion
764
+ * Chromium based browsers use platformVersion major >= 13 for Windows 11 and lower values for Windows 10.
765
+ *
766
+ * @param {string} platformVersion - platformVersion value from userAgentData.getHighEntropyValues
767
+ * @returns {string|null} "11", "10" or null if not parsable
768
+ */
769
+ function parseWindowsVersionFromPlatformVersion(platformVersion) {
770
+ if (typeof platformVersion !== "string" || !platformVersion) {
771
+ return null;
772
+ }
773
+ var major = parseInt(platformVersion.split(".")[0], 10);
774
+ if (isNaN(major)) {
775
+ return null;
776
+ }
777
+ return major >= 13 ? "11" : "10";
778
+ }
779
+
780
+ /**
781
+ * Retrieve User-Agent Client Hints (high entropy values) when available.
782
+ *
783
+ * @param {Object} uaDataOverride - optional userAgentData override for testing
784
+ * @returns {Promise<Object|null>} resolved hints object or null
785
+ */
786
+ function getUserAgentClientHintsInternal(uaData) {
787
+ if (!uaData || typeof uaData.getHighEntropyValues !== "function") {
788
+ return Promise.resolve(null);
789
+ }
790
+ return uaData.getHighEntropyValues(["platform", "platformVersion", "architecture", "bitness", "model", "uaFullVersion", "fullVersionList"]).then(function (values) {
791
+ if (!values || _typeof(values) !== "object") {
792
+ return null;
793
+ }
794
+ var browserName = null;
795
+ var browserVersion = null;
796
+ var versionList = Array.isArray(values.fullVersionList) ? values.fullVersionList : [];
797
+ var fallbackList = Array.isArray(uaData.brands) ? uaData.brands : [];
798
+ var normalizeBrand = function normalizeBrand(brand) {
799
+ return typeof brand === "string" ? brand.toLowerCase().replace(/[^a-z0-9]/g, "") : "";
800
+ };
801
+ var isGreaseBrand = function isGreaseBrand(brand) {
802
+ var normalized = normalizeBrand(brand);
803
+ return normalized === "notabrand" || normalized === "notabrand99" || normalized.indexOf("notabrand") === 0;
804
+ };
805
+ var isChromiumBrand = function isChromiumBrand(brand) {
806
+ return normalizeBrand(brand) === "chromium";
807
+ };
808
+ var pickEntry = function pickEntry(list, allowChromiumFallback) {
809
+ return list.find(function (entry) {
810
+ if (!entry || !entry.brand) {
811
+ return false;
812
+ }
813
+ if (isGreaseBrand(entry.brand)) {
814
+ return false;
815
+ }
816
+ if (!allowChromiumFallback && isChromiumBrand(entry.brand)) {
817
+ return false;
818
+ }
819
+ return true;
820
+ });
821
+ };
822
+ var browserEntry = pickEntry(versionList, false) || pickEntry(fallbackList, false) || pickEntry(versionList, true) || pickEntry(fallbackList, true);
823
+ if (browserEntry) {
824
+ browserName = browserEntry.brand || null;
825
+ browserVersion = browserEntry.version || null;
826
+ }
827
+ var parsed = {
828
+ platform: values.platform || uaData.platform || null,
829
+ platformVersion: values.platformVersion || null,
830
+ architecture: values.architecture || null,
831
+ bitness: values.bitness || null,
832
+ model: values.model || null,
833
+ uaFullVersion: values.uaFullVersion || null,
834
+ fullVersionList: values.fullVersionList || null,
835
+ browserName: browserName,
836
+ browserVersion: browserVersion,
837
+ windowsVersion: null
838
+ };
839
+ if (parsed.platform && parsed.platform.toLowerCase() === "windows") {
840
+ parsed.windowsVersion = parseWindowsVersionFromPlatformVersion(parsed.platformVersion);
841
+ }
842
+ return parsed;
843
+ })["catch"](function () {
844
+ return null;
845
+ });
846
+ }
847
+ var prefetchedUserAgentClientHintsPromise = null;
848
+ if (isBrowser && typeof navigator !== "undefined" && navigator.userAgentData && typeof navigator.userAgentData.getHighEntropyValues === "function") {
849
+ prefetchedUserAgentClientHintsPromise = getUserAgentClientHintsInternal(navigator.userAgentData);
850
+ }
851
+ function getUserAgentClientHints(uaDataOverride) {
852
+ if (uaDataOverride) {
853
+ return getUserAgentClientHintsInternal(uaDataOverride);
854
+ }
855
+ if (prefetchedUserAgentClientHintsPromise) {
856
+ return prefetchedUserAgentClientHintsPromise;
857
+ }
858
+ if (isBrowser && typeof navigator !== "undefined" && navigator.userAgentData && typeof navigator.userAgentData.getHighEntropyValues === "function") {
859
+ prefetchedUserAgentClientHintsPromise = getUserAgentClientHintsInternal(navigator.userAgentData);
860
+ return prefetchedUserAgentClientHintsPromise;
861
+ }
862
+ return Promise.resolve(null);
863
+ }
864
+
762
865
  /**
763
866
  * Returns device type information according to user agent string
764
867
  * @memberof Countly._internals
@@ -1092,6 +1195,13 @@
1092
1195
  var _journeyTriggerPending = /*#__PURE__*/new WeakMap();
1093
1196
  var _journeyPendingEventIds = /*#__PURE__*/new WeakMap();
1094
1197
  var _fakeRequestHandler = /*#__PURE__*/new WeakMap();
1198
+ var _uaClientHints = /*#__PURE__*/new WeakMap();
1199
+ var _uaClientHintsStatus = /*#__PURE__*/new WeakMap();
1200
+ var _clientHintsPromise = /*#__PURE__*/new WeakMap();
1201
+ var _pendingRequestBuffer = /*#__PURE__*/new WeakMap();
1202
+ var _clientHintsBufferTimeoutId = /*#__PURE__*/new WeakMap();
1203
+ var _initializeClientHints = /*#__PURE__*/new WeakMap();
1204
+ var _flushPendingRequestBuffer = /*#__PURE__*/new WeakMap();
1095
1205
  var _getAndSetServerConfig = /*#__PURE__*/new WeakMap();
1096
1206
  var _populateServerConfig = /*#__PURE__*/new WeakMap();
1097
1207
  var _initialize = /*#__PURE__*/new WeakMap();
@@ -1141,6 +1251,7 @@
1141
1251
  var _getStoredIdOrGenerateId = /*#__PURE__*/new WeakMap();
1142
1252
  var _isUUID = /*#__PURE__*/new WeakMap();
1143
1253
  var _getUA = /*#__PURE__*/new WeakMap();
1254
+ var _getBrowserInfoFromUA = /*#__PURE__*/new WeakMap();
1144
1255
  var _getMetrics = /*#__PURE__*/new WeakMap();
1145
1256
  var _getResolution = /*#__PURE__*/new WeakMap();
1146
1257
  var _isReferrerUsable = /*#__PURE__*/new WeakMap();
@@ -1280,6 +1391,89 @@
1280
1391
  _classPrivateFieldInitSpec(this, _journeyTriggerPending, void 0);
1281
1392
  _classPrivateFieldInitSpec(this, _journeyPendingEventIds, void 0);
1282
1393
  _classPrivateFieldInitSpec(this, _fakeRequestHandler, void 0);
1394
+ _classPrivateFieldInitSpec(this, _uaClientHints, void 0);
1395
+ _classPrivateFieldInitSpec(this, _uaClientHintsStatus, void 0);
1396
+ _classPrivateFieldInitSpec(this, _clientHintsPromise, void 0);
1397
+ _classPrivateFieldInitSpec(this, _pendingRequestBuffer, void 0);
1398
+ _classPrivateFieldInitSpec(this, _clientHintsBufferTimeoutId, void 0);
1399
+ /**
1400
+ * Fetch User-Agent Client Hints and cache values for metrics enrichment.
1401
+ * @private
1402
+ */
1403
+ _classPrivateFieldInitSpec(this, _initializeClientHints, function () {
1404
+ if (!isBrowser) {
1405
+ _classPrivateFieldSet2(_uaClientHintsStatus, _this, "unavailable");
1406
+ _classPrivateFieldSet2(_pendingRequestBuffer, _this, null); // no buffering needed
1407
+ return;
1408
+ }
1409
+ var uaRaw = currentUserAgentString();
1410
+ var uaDataAvailable = typeof navigator !== "undefined" && !!navigator.userAgentData;
1411
+ var getHighEntropyValuesAvailable = uaDataAvailable && typeof navigator.userAgentData.getHighEntropyValues === "function";
1412
+ var uaDataPlatform = uaDataAvailable ? navigator.userAgentData.platform : undefined;
1413
+ var uaDataBrands = uaDataAvailable ? navigator.userAgentData.brands : undefined;
1414
+ _classPrivateFieldGet2(_log, _this).call(_this, logLevelEnums.DEBUG, "ua_logic, raw ua string:[" + uaRaw + "]");
1415
+ _classPrivateFieldGet2(_log, _this).call(_this, logLevelEnums.DEBUG, "ua_logic, userAgentData available:[" + uaDataAvailable + "], getHighEntropyValues available:[" + getHighEntropyValuesAvailable + "]");
1416
+ _classPrivateFieldGet2(_log, _this).call(_this, logLevelEnums.DEBUG, "ua_logic, userAgentData low-entropy platform:[" + uaDataPlatform + "], brands:[" + JSON.stringify(uaDataBrands) + "]");
1417
+ _classPrivateFieldSet2(_uaClientHintsStatus, _this, "pending");
1418
+ _classPrivateFieldSet2(_pendingRequestBuffer, _this, []); // enable request buffering until hints resolve
1419
+
1420
+ // Safety timeout: flush buffer even if hints never resolve (e.g. API blocked)
1421
+ _classPrivateFieldSet2(_clientHintsBufferTimeoutId, _this, setTimeout(function () {
1422
+ if (_classPrivateFieldGet2(_pendingRequestBuffer, _this) !== null) {
1423
+ _classPrivateFieldGet2(_log, _this).call(_this, logLevelEnums.WARNING, "ua_logic, client hints resolution timed out after 5s, flushing pending requests with available metrics");
1424
+ _classPrivateFieldGet2(_flushPendingRequestBuffer, _this).call(_this);
1425
+ }
1426
+ }, 1000));
1427
+ _classPrivateFieldSet2(_clientHintsPromise, _this, getUserAgentClientHints().then(function (clientHints) {
1428
+ if (clientHints && _typeof(clientHints) === "object") {
1429
+ _classPrivateFieldSet2(_uaClientHints, _this, clientHints);
1430
+ _classPrivateFieldSet2(_uaClientHintsStatus, _this, "resolved");
1431
+ _classPrivateFieldGet2(_log, _this).call(_this, logLevelEnums.DEBUG, "ua_logic, high-entropy hints resolved:[" + JSON.stringify(clientHints) + "]");
1432
+ } else {
1433
+ _classPrivateFieldSet2(_uaClientHintsStatus, _this, "unavailable");
1434
+ _classPrivateFieldGet2(_log, _this).call(_this, logLevelEnums.DEBUG, "ua_logic, high-entropy hints unavailable or not returned");
1435
+ }
1436
+ })["catch"](function (err) {
1437
+ _classPrivateFieldSet2(_uaClientHints, _this, null);
1438
+ _classPrivateFieldSet2(_uaClientHintsStatus, _this, "failed");
1439
+ _classPrivateFieldGet2(_log, _this).call(_this, logLevelEnums.DEBUG, "ua_logic, high-entropy hints fetch failed:[" + err + "]");
1440
+ })["finally"](function () {
1441
+ _classPrivateFieldGet2(_flushPendingRequestBuffer, _this).call(_this);
1442
+ }));
1443
+ });
1444
+ /**
1445
+ * Flush pending request buffer after client hints resolution.
1446
+ * Re-computes metrics for any buffered begin_session request so that
1447
+ * high-entropy Client Hints values are included. All other buffered
1448
+ * requests are pushed to the queue unchanged, preserving order.
1449
+ * @private
1450
+ */
1451
+ _classPrivateFieldInitSpec(this, _flushPendingRequestBuffer, function () {
1452
+ // Clear safety timeout
1453
+ if (_classPrivateFieldGet2(_clientHintsBufferTimeoutId, _this)) {
1454
+ clearTimeout(_classPrivateFieldGet2(_clientHintsBufferTimeoutId, _this));
1455
+ _classPrivateFieldSet2(_clientHintsBufferTimeoutId, _this, null);
1456
+ }
1457
+ var buffer = _classPrivateFieldGet2(_pendingRequestBuffer, _this);
1458
+ _classPrivateFieldSet2(_pendingRequestBuffer, _this, null); // disable buffering — subsequent calls go directly to queue
1459
+
1460
+ if (!buffer || buffer.length === 0) {
1461
+ return;
1462
+ }
1463
+ _classPrivateFieldGet2(_log, _this).call(_this, logLevelEnums.DEBUG, "ua_logic, flushing [" + buffer.length + "] pending request(s) after client hints resolution");
1464
+ for (var i = 0; i < buffer.length; i++) {
1465
+ var request = buffer[i];
1466
+ // Re-compute metrics for begin_session requests with now-resolved hints
1467
+ if (request.begin_session) {
1468
+ request.metrics = JSON.stringify(_classPrivateFieldGet2(_getMetrics, _this).call(_this));
1469
+ }
1470
+ if (_classPrivateFieldGet2(_requestQueue, _this).length > _classPrivateFieldGet2(_SCSizeReqQueue, _this)) {
1471
+ _classPrivateFieldGet2(_requestQueue, _this).shift();
1472
+ }
1473
+ _classPrivateFieldGet2(_requestQueue, _this).push(request);
1474
+ }
1475
+ _classPrivateFieldGet2(_setValueInStorage, _this).call(_this, "cly_queue", _classPrivateFieldGet2(_requestQueue, _this), true);
1476
+ });
1283
1477
  /**
1284
1478
  * Fetch and set server configuration
1285
1479
  * Retrieves server-side settings and behavior configurations
@@ -2003,6 +2197,14 @@
2003
2197
  _classPrivateFieldSet2(_journeyTriggerInProgress, _this, undefined);
2004
2198
  _classPrivateFieldSet2(_journeyTriggerPending, _this, undefined);
2005
2199
  _classPrivateFieldSet2(_journeyPendingEventIds, _this, undefined);
2200
+ if (_classPrivateFieldGet2(_clientHintsBufferTimeoutId, _this)) {
2201
+ clearTimeout(_classPrivateFieldGet2(_clientHintsBufferTimeoutId, _this));
2202
+ _classPrivateFieldSet2(_clientHintsBufferTimeoutId, _this, null);
2203
+ }
2204
+ _classPrivateFieldSet2(_pendingRequestBuffer, _this, null);
2205
+ _classPrivateFieldSet2(_clientHintsPromise, _this, null);
2206
+ _classPrivateFieldSet2(_uaClientHints, _this, null);
2207
+ _classPrivateFieldSet2(_uaClientHintsStatus, _this, "not_started");
2006
2208
  });
2007
2209
  /**
2008
2210
  * Returns the SDK version string currently in use
@@ -2731,6 +2933,11 @@
2731
2933
  return _regenerator().w(function (_context2) {
2732
2934
  while (1) switch (_context2.n) {
2733
2935
  case 0:
2936
+ // Flush any buffered requests (e.g. held while client hints were resolving)
2937
+ // into the real request queue so they can be sent before the content request.
2938
+ if (_classPrivateFieldGet2(_pendingRequestBuffer, _this) !== null) {
2939
+ _classPrivateFieldGet2(_flushPendingRequestBuffer, _this).call(_this);
2940
+ }
2734
2941
  initialQueueLength = _classPrivateFieldGet2(_requestQueue, _this).length;
2735
2942
  if (!(initialQueueLength === 0)) {
2736
2943
  _context2.n = 1;
@@ -5836,6 +6043,12 @@
5836
6043
  return;
5837
6044
  }
5838
6045
  _classPrivateFieldGet2(_prepareRequest, _this).call(_this, request);
6046
+
6047
+ // Buffer requests while client hints are still resolving
6048
+ if (_classPrivateFieldGet2(_pendingRequestBuffer, _this) !== null) {
6049
+ _classPrivateFieldGet2(_pendingRequestBuffer, _this).push(request);
6050
+ return;
6051
+ }
5839
6052
  if (_classPrivateFieldGet2(_requestQueue, _this).length > _classPrivateFieldGet2(_SCSizeReqQueue, _this)) {
5840
6053
  _classPrivateFieldGet2(_requestQueue, _this).shift();
5841
6054
  }
@@ -6089,6 +6302,49 @@
6089
6302
  }
6090
6303
  return currentUserAgentString();
6091
6304
  });
6305
+ /**
6306
+ * Basic browser name/version parsing fallback from UA string.
6307
+ * @private
6308
+ * @param {string} ua - raw user agent string
6309
+ * @returns {{name: string|null, version: string|null}}
6310
+ */
6311
+ _classPrivateFieldInitSpec(this, _getBrowserInfoFromUA, function (ua) {
6312
+ if (!ua || typeof ua !== "string") {
6313
+ return {
6314
+ name: null,
6315
+ version: null
6316
+ };
6317
+ }
6318
+ var patterns = [{
6319
+ name: "Edge",
6320
+ regex: /Edg\/([\d\.]+)/
6321
+ }, {
6322
+ name: "Opera",
6323
+ regex: /OPR\/([\d\.]+)/
6324
+ }, {
6325
+ name: "Chrome",
6326
+ regex: /Chrome\/([\d\.]+)/
6327
+ }, {
6328
+ name: "Firefox",
6329
+ regex: /Firefox\/([\d\.]+)/
6330
+ }, {
6331
+ name: "Safari",
6332
+ regex: /Version\/([\d\.]+).*Safari/
6333
+ }];
6334
+ for (var i = 0; i < patterns.length; i++) {
6335
+ var match = ua.match(patterns[i].regex);
6336
+ if (match && match[1]) {
6337
+ return {
6338
+ name: patterns[i].name,
6339
+ version: match[1]
6340
+ };
6341
+ }
6342
+ }
6343
+ return {
6344
+ name: null,
6345
+ version: null
6346
+ };
6347
+ });
6092
6348
  /**
6093
6349
  * Get metrics of the browser or config object
6094
6350
  * @memberof Countly._internals
@@ -6118,6 +6374,55 @@
6118
6374
  if (typeof locale !== "undefined") {
6119
6375
  metrics._locale = metrics._locale || locale;
6120
6376
  }
6377
+ if (isBrowser && navigator.userAgentData && navigator.userAgentData.platform) {
6378
+ metrics._os = metrics._os || navigator.userAgentData.platform;
6379
+ }
6380
+ var detectedDeviceType = userAgentDeviceDetection();
6381
+ if (detectedDeviceType === "phone") {
6382
+ detectedDeviceType = "mobile";
6383
+ }
6384
+ metrics._device_type = metrics._device_type || detectedDeviceType;
6385
+ if (_classPrivateFieldGet2(_uaClientHints, _this) && _typeof(_classPrivateFieldGet2(_uaClientHints, _this)) === "object") {
6386
+ if (_classPrivateFieldGet2(_uaClientHints, _this).platform) {
6387
+ metrics._os = metrics._os || _classPrivateFieldGet2(_uaClientHints, _this).platform;
6388
+ }
6389
+ var osVersionFromHints = _classPrivateFieldGet2(_uaClientHints, _this).windowsVersion || _classPrivateFieldGet2(_uaClientHints, _this).platformVersion;
6390
+ if (osVersionFromHints) {
6391
+ metrics._os_version = metrics._os_version || osVersionFromHints;
6392
+ }
6393
+ if (_classPrivateFieldGet2(_uaClientHints, _this).model) {
6394
+ metrics._device = metrics._device || _classPrivateFieldGet2(_uaClientHints, _this).model;
6395
+ }
6396
+ if (_classPrivateFieldGet2(_uaClientHints, _this).browserName) {
6397
+ metrics._browser = metrics._browser || _classPrivateFieldGet2(_uaClientHints, _this).browserName;
6398
+ }
6399
+ if (_classPrivateFieldGet2(_uaClientHints, _this).browserVersion) {
6400
+ metrics._browser_version = metrics._browser_version || _classPrivateFieldGet2(_uaClientHints, _this).browserVersion;
6401
+ }
6402
+ if (_classPrivateFieldGet2(_uaClientHints, _this).windowsVersion) {
6403
+ metrics._os = metrics._os || "Windows";
6404
+ metrics._os_version = metrics._os_version || _classPrivateFieldGet2(_uaClientHints, _this).windowsVersion;
6405
+ }
6406
+ _classPrivateFieldGet2(_log, _this).call(_this, logLevelEnums.DEBUG, "ua_logic, metrics enriched from hints:[" + JSON.stringify({
6407
+ _os: metrics._os,
6408
+ _os_version: metrics._os_version,
6409
+ _device: metrics._device,
6410
+ _device_type: metrics._device_type,
6411
+ _browser: metrics._browser,
6412
+ _browser_version: metrics._browser_version
6413
+ }) + "]");
6414
+ } else {
6415
+ if (_classPrivateFieldGet2(_uaClientHintsStatus, _this) === "pending") {
6416
+ _classPrivateFieldGet2(_log, _this).call(_this, logLevelEnums.DEBUG, "ua_logic, high-entropy hints are still pending, using fallback metrics for now");
6417
+ } else {
6418
+ _classPrivateFieldGet2(_log, _this).call(_this, logLevelEnums.DEBUG, "ua_logic, no high-entropy hints available, using UA fallback parsing");
6419
+ }
6420
+ }
6421
+ if (!metrics._browser || !metrics._browser_version) {
6422
+ var browserInfo = _classPrivateFieldGet2(_getBrowserInfoFromUA, _this).call(_this, metrics._ua);
6423
+ metrics._browser = metrics._browser || browserInfo.name;
6424
+ metrics._browser_version = metrics._browser_version || browserInfo.version;
6425
+ }
6121
6426
  if (_classPrivateFieldGet2(_isReferrerUsable, _this).call(_this)) {
6122
6427
  metrics._store = metrics._store || document.referrer;
6123
6428
  }
@@ -7332,6 +7637,11 @@
7332
7637
  _classPrivateFieldSet2(_journeyTriggerPending, this, false);
7333
7638
  _classPrivateFieldSet2(_journeyPendingEventIds, this, new Set());
7334
7639
  _classPrivateFieldSet2(_fakeRequestHandler, this, getConfig("fake_request_handler", _ob, null));
7640
+ _classPrivateFieldSet2(_uaClientHints, this, null);
7641
+ _classPrivateFieldSet2(_uaClientHintsStatus, this, "not_started");
7642
+ _classPrivateFieldSet2(_clientHintsPromise, this, null);
7643
+ _classPrivateFieldSet2(_pendingRequestBuffer, this, null);
7644
+ _classPrivateFieldSet2(_clientHintsBufferTimeoutId, this, null);
7335
7645
  this.app_key = getConfig("app_key", _ob, null);
7336
7646
  this.url = stripTrailingSlash(getConfig("url", _ob, ""));
7337
7647
  this.serialize = getConfig("serialize", _ob, Countly.serialize);
@@ -7359,6 +7669,7 @@
7359
7669
  for (var it = 0; it < Countly.features.length; it++) {
7360
7670
  _classPrivateFieldGet2(_consents, this)[Countly.features[it]] = {};
7361
7671
  }
7672
+ _classPrivateFieldGet2(_initializeClientHints, this).call(this);
7362
7673
  _classPrivateFieldGet2(_initialize, this).call(this, _ob);
7363
7674
 
7364
7675
  // start SDK