@nexushub/client 1.1.8 → 1.1.11
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.cjs +62 -52
- package/dist/index.js +62 -52
- package/dist/react.cjs +62 -52
- package/dist/react.js +62 -52
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -939,7 +939,7 @@ var ContentEngine = class {
|
|
|
939
939
|
);
|
|
940
940
|
if (this.config.debug && duration > 100) {
|
|
941
941
|
console.warn(
|
|
942
|
-
`[
|
|
942
|
+
`[GN-Apex] \u26A0\uFE0F getPage("${slug}") took ${duration.toFixed(2)}ms`
|
|
943
943
|
);
|
|
944
944
|
}
|
|
945
945
|
return result;
|
|
@@ -976,7 +976,7 @@ var ContentEngine = class {
|
|
|
976
976
|
}
|
|
977
977
|
}
|
|
978
978
|
if (this.circuitBreaker.isOpen()) {
|
|
979
|
-
throw new Error("[
|
|
979
|
+
throw new Error("[GN-Apex] Circuit open. API is unavailable.");
|
|
980
980
|
}
|
|
981
981
|
try {
|
|
982
982
|
await this.rateLimiter.checkLimit();
|
|
@@ -993,21 +993,22 @@ var ContentEngine = class {
|
|
|
993
993
|
return includeMetadata ? data : data.data;
|
|
994
994
|
} catch (error) {
|
|
995
995
|
this.circuitBreaker.recordFailure();
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
996
|
+
try {
|
|
997
|
+
const local = await this.localCache.getPage(slug);
|
|
998
|
+
if (local) {
|
|
999
|
+
console.warn(
|
|
1000
|
+
`[GN-Apex] \u26A0\uFE0F Network timeout on '${slug}', successfully recovered from local cache.`
|
|
1001
|
+
);
|
|
1002
|
+
return includeMetadata ? {
|
|
1003
|
+
data: local,
|
|
1004
|
+
metadata: {
|
|
1005
|
+
timestamp: Date.now(),
|
|
1006
|
+
expiresAt: Infinity,
|
|
1007
|
+
tags: []
|
|
1008
|
+
}
|
|
1009
|
+
} : local;
|
|
1010
1010
|
}
|
|
1011
|
+
} catch {
|
|
1011
1012
|
}
|
|
1012
1013
|
throw this.normalizeError(error, `Failed to fetch page '${slug}'`);
|
|
1013
1014
|
}
|
|
@@ -1036,17 +1037,17 @@ var ContentEngine = class {
|
|
|
1036
1037
|
localCollection,
|
|
1037
1038
|
normalizedQuery
|
|
1038
1039
|
);
|
|
1039
|
-
return result;
|
|
1040
|
+
return includeMetadata ? result : result;
|
|
1040
1041
|
}
|
|
1041
1042
|
} catch {
|
|
1042
1043
|
}
|
|
1043
1044
|
}
|
|
1044
1045
|
if (this.circuitBreaker.isOpen()) {
|
|
1045
|
-
throw new Error("[
|
|
1046
|
+
throw new Error("[GN-Apex] Circuit open. API is unavailable.");
|
|
1046
1047
|
}
|
|
1047
1048
|
try {
|
|
1048
1049
|
await this.rateLimiter.checkLimit();
|
|
1049
|
-
const
|
|
1050
|
+
const entry = await this.backoff.execute(async () => {
|
|
1050
1051
|
return this.fetchCollection(
|
|
1051
1052
|
collectionId,
|
|
1052
1053
|
normalizedQuery,
|
|
@@ -1057,20 +1058,22 @@ var ContentEngine = class {
|
|
|
1057
1058
|
);
|
|
1058
1059
|
});
|
|
1059
1060
|
this.circuitBreaker.recordSuccess();
|
|
1060
|
-
return includeMetadata ?
|
|
1061
|
+
return includeMetadata ? entry : entry.data;
|
|
1061
1062
|
} catch (error) {
|
|
1062
1063
|
this.circuitBreaker.recordFailure();
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1064
|
+
try {
|
|
1065
|
+
const localCollection = await this.localCache.getCollection(collectionId);
|
|
1066
|
+
if (localCollection) {
|
|
1067
|
+
console.warn(
|
|
1068
|
+
`[GN-Apex] \u26A0\uFE0F Network timeout on '${collectionId}', successfully recovered from local cache.`
|
|
1069
|
+
);
|
|
1070
|
+
const result = this.applyLocalQuery(
|
|
1071
|
+
localCollection,
|
|
1072
|
+
normalizedQuery
|
|
1073
|
+
);
|
|
1074
|
+
return includeMetadata ? result : result;
|
|
1073
1075
|
}
|
|
1076
|
+
} catch {
|
|
1074
1077
|
}
|
|
1075
1078
|
throw this.normalizeError(
|
|
1076
1079
|
error,
|
|
@@ -1129,14 +1132,15 @@ var ContentEngine = class {
|
|
|
1129
1132
|
}
|
|
1130
1133
|
return data;
|
|
1131
1134
|
} catch (error) {
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1135
|
+
try {
|
|
1136
|
+
const localGlobals = await this.localCache.getGlobals();
|
|
1137
|
+
if (localGlobals) {
|
|
1138
|
+
console.warn(
|
|
1139
|
+
`[GN-Apex] \u26A0\uFE0F Network timeout on globals, successfully recovered from local cache.`
|
|
1140
|
+
);
|
|
1141
|
+
return localGlobals;
|
|
1139
1142
|
}
|
|
1143
|
+
} catch {
|
|
1140
1144
|
}
|
|
1141
1145
|
throw this.normalizeError(error, "Failed to fetch globals");
|
|
1142
1146
|
}
|
|
@@ -1287,7 +1291,7 @@ var ContentEngine = class {
|
|
|
1287
1291
|
};
|
|
1288
1292
|
}
|
|
1289
1293
|
writeCache(key, data, options) {
|
|
1290
|
-
const ttlSeconds = options.revalidate === false ?
|
|
1294
|
+
const ttlSeconds = options.revalidate === false ? 5 : Math.max(1, options.revalidate);
|
|
1291
1295
|
if (this.cacheStrategy === "memory") {
|
|
1292
1296
|
this.memoryCache.set(key, data, {
|
|
1293
1297
|
tags: options.tags,
|
|
@@ -1450,7 +1454,7 @@ var ContentEngine = class {
|
|
|
1450
1454
|
}
|
|
1451
1455
|
async fetchWithTimeout(url, options = {}) {
|
|
1452
1456
|
const {
|
|
1453
|
-
timeout = this.config.timeout ||
|
|
1457
|
+
timeout = this.config.timeout || 25e3,
|
|
1454
1458
|
tags = [],
|
|
1455
1459
|
revalidate,
|
|
1456
1460
|
forceRefresh = false,
|
|
@@ -1628,7 +1632,6 @@ var VitalsCollector = class {
|
|
|
1628
1632
|
tcp_connect: navEntry.connectEnd - navEntry.connectStart,
|
|
1629
1633
|
request_time: navEntry.responseEnd - navEntry.requestStart,
|
|
1630
1634
|
dom_load: navEntry.domComplete - navEntry.domInteractive,
|
|
1631
|
-
// NEW: raw fields matching Rust NavigationTiming struct
|
|
1632
1635
|
domain_lookup_start: navEntry.domainLookupStart,
|
|
1633
1636
|
domain_lookup_end: navEntry.domainLookupEnd,
|
|
1634
1637
|
connect_start: navEntry.connectStart,
|
|
@@ -1641,8 +1644,10 @@ var VitalsCollector = class {
|
|
|
1641
1644
|
"resource"
|
|
1642
1645
|
);
|
|
1643
1646
|
if (resourceEntries.length > 0) {
|
|
1644
|
-
this.metrics.resources = resourceEntries.filter(
|
|
1645
|
-
name
|
|
1647
|
+
this.metrics.resources = resourceEntries.filter(
|
|
1648
|
+
(r) => !r.name.includes("/api/collect") && !r.name.includes("/analytics") && !r.name.includes("sentry.gnapex.com")
|
|
1649
|
+
).sort((a, b) => b.duration - a.duration).slice(0, 5).map((r) => ({
|
|
1650
|
+
name: r.name.length > 120 ? r.name.substring(0, 120) + "..." : r.name,
|
|
1646
1651
|
initiatorType: r.initiatorType,
|
|
1647
1652
|
duration: Math.round(r.duration),
|
|
1648
1653
|
transferSize: r.transferSize > 0 ? r.transferSize : void 0,
|
|
@@ -1674,7 +1679,7 @@ var VitalsCollector = class {
|
|
|
1674
1679
|
var vitalsCollector = new VitalsCollector();
|
|
1675
1680
|
var initVitals = (_tracker) => {
|
|
1676
1681
|
if (process.env.NODE_ENV === "development") {
|
|
1677
|
-
console.log("[
|
|
1682
|
+
console.log("[GN-Apex] Web Vitals monitoring active");
|
|
1678
1683
|
}
|
|
1679
1684
|
};
|
|
1680
1685
|
|
|
@@ -1827,7 +1832,8 @@ var Tracker = class {
|
|
|
1827
1832
|
this.anonymousId = "";
|
|
1828
1833
|
this.isFlushing = false;
|
|
1829
1834
|
this.flushPromise = null;
|
|
1830
|
-
|
|
1835
|
+
// 🛡️ Batch size set to 10 to keep payloads strictly under Actix 32KB limit
|
|
1836
|
+
this.batchSize = 10;
|
|
1831
1837
|
this.config = config;
|
|
1832
1838
|
this.endpoint = `${this.config.analyticsUrl}/api/collect`;
|
|
1833
1839
|
this.circuitBreaker = new CircuitBreaker();
|
|
@@ -1839,7 +1845,7 @@ var Tracker = class {
|
|
|
1839
1845
|
}
|
|
1840
1846
|
async initSession() {
|
|
1841
1847
|
this.visitorId = await getVisitorId(
|
|
1842
|
-
this.config.privacy?.fingerprinting ??
|
|
1848
|
+
this.config.privacy?.fingerprinting ?? true
|
|
1843
1849
|
);
|
|
1844
1850
|
let anonId = safeGetItem("nexus_anon_id");
|
|
1845
1851
|
if (!anonId) {
|
|
@@ -1865,10 +1871,11 @@ var Tracker = class {
|
|
|
1865
1871
|
if (typeof window === "undefined") return;
|
|
1866
1872
|
safeSetItem("nexus_last_active", Date.now().toString());
|
|
1867
1873
|
const entropy = await getDeviceEntropy(
|
|
1868
|
-
this.config.privacy?.fingerprinting ??
|
|
1874
|
+
this.config.privacy?.fingerprinting ?? true
|
|
1869
1875
|
);
|
|
1870
|
-
const
|
|
1871
|
-
const
|
|
1876
|
+
const isPageView = eventType === "page_view" || eventType === "performance";
|
|
1877
|
+
const perfMetrics = isPageView ? vitalsCollector.getMetricsSnapshot() : void 0;
|
|
1878
|
+
const utmParams = isPageView ? extractUtmParams(window.location.href) : void 0;
|
|
1872
1879
|
const payload = {
|
|
1873
1880
|
projectId: this.config.projectId,
|
|
1874
1881
|
sessionId: this.sessionId,
|
|
@@ -1877,10 +1884,9 @@ var Tracker = class {
|
|
|
1877
1884
|
messageId: generateUUID(),
|
|
1878
1885
|
sentAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
1879
1886
|
version: SDK_VERSION,
|
|
1880
|
-
// Dynamically synced to SDK 1.1.0
|
|
1881
1887
|
url: window.location.href,
|
|
1882
|
-
referrer: document.referrer,
|
|
1883
|
-
userAgent: window.navigator.userAgent,
|
|
1888
|
+
referrer: isPageView ? document.referrer : void 0,
|
|
1889
|
+
userAgent: isPageView ? window.navigator.userAgent : void 0,
|
|
1884
1890
|
screenWidth: window.screen.width,
|
|
1885
1891
|
screenHeight: window.screen.height,
|
|
1886
1892
|
language: window.navigator.language,
|
|
@@ -1943,6 +1949,10 @@ var Tracker = class {
|
|
|
1943
1949
|
} catch {
|
|
1944
1950
|
response = void 0;
|
|
1945
1951
|
}
|
|
1952
|
+
if (response && response.status === 413) {
|
|
1953
|
+
await eventStorage.remove(storedEvents.map((e) => e.id));
|
|
1954
|
+
return;
|
|
1955
|
+
}
|
|
1946
1956
|
if (!response || response.status === 404 || response.status === 405) {
|
|
1947
1957
|
const results = await Promise.allSettled(
|
|
1948
1958
|
payloads.map(
|
|
@@ -1955,7 +1965,7 @@ var Tracker = class {
|
|
|
1955
1965
|
)
|
|
1956
1966
|
);
|
|
1957
1967
|
const successIds = results.flatMap(
|
|
1958
|
-
(r, i) => r.status === "fulfilled" && r.value.ok ? [storedEvents[i].id] : []
|
|
1968
|
+
(r, i) => r.status === "fulfilled" && (r.value.ok || r.value.status === 413) ? [storedEvents[i].id] : []
|
|
1959
1969
|
);
|
|
1960
1970
|
if (successIds.length) await eventStorage.remove(successIds);
|
|
1961
1971
|
if (successIds.length === storedEvents.length) {
|
package/dist/index.js
CHANGED
|
@@ -883,7 +883,7 @@ var ContentEngine = class {
|
|
|
883
883
|
);
|
|
884
884
|
if (this.config.debug && duration > 100) {
|
|
885
885
|
console.warn(
|
|
886
|
-
`[
|
|
886
|
+
`[GN-Apex] \u26A0\uFE0F getPage("${slug}") took ${duration.toFixed(2)}ms`
|
|
887
887
|
);
|
|
888
888
|
}
|
|
889
889
|
return result;
|
|
@@ -920,7 +920,7 @@ var ContentEngine = class {
|
|
|
920
920
|
}
|
|
921
921
|
}
|
|
922
922
|
if (this.circuitBreaker.isOpen()) {
|
|
923
|
-
throw new Error("[
|
|
923
|
+
throw new Error("[GN-Apex] Circuit open. API is unavailable.");
|
|
924
924
|
}
|
|
925
925
|
try {
|
|
926
926
|
await this.rateLimiter.checkLimit();
|
|
@@ -937,21 +937,22 @@ var ContentEngine = class {
|
|
|
937
937
|
return includeMetadata ? data : data.data;
|
|
938
938
|
} catch (error) {
|
|
939
939
|
this.circuitBreaker.recordFailure();
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
940
|
+
try {
|
|
941
|
+
const local = await this.localCache.getPage(slug);
|
|
942
|
+
if (local) {
|
|
943
|
+
console.warn(
|
|
944
|
+
`[GN-Apex] \u26A0\uFE0F Network timeout on '${slug}', successfully recovered from local cache.`
|
|
945
|
+
);
|
|
946
|
+
return includeMetadata ? {
|
|
947
|
+
data: local,
|
|
948
|
+
metadata: {
|
|
949
|
+
timestamp: Date.now(),
|
|
950
|
+
expiresAt: Infinity,
|
|
951
|
+
tags: []
|
|
952
|
+
}
|
|
953
|
+
} : local;
|
|
954
954
|
}
|
|
955
|
+
} catch {
|
|
955
956
|
}
|
|
956
957
|
throw this.normalizeError(error, `Failed to fetch page '${slug}'`);
|
|
957
958
|
}
|
|
@@ -980,17 +981,17 @@ var ContentEngine = class {
|
|
|
980
981
|
localCollection,
|
|
981
982
|
normalizedQuery
|
|
982
983
|
);
|
|
983
|
-
return result;
|
|
984
|
+
return includeMetadata ? result : result;
|
|
984
985
|
}
|
|
985
986
|
} catch {
|
|
986
987
|
}
|
|
987
988
|
}
|
|
988
989
|
if (this.circuitBreaker.isOpen()) {
|
|
989
|
-
throw new Error("[
|
|
990
|
+
throw new Error("[GN-Apex] Circuit open. API is unavailable.");
|
|
990
991
|
}
|
|
991
992
|
try {
|
|
992
993
|
await this.rateLimiter.checkLimit();
|
|
993
|
-
const
|
|
994
|
+
const entry = await this.backoff.execute(async () => {
|
|
994
995
|
return this.fetchCollection(
|
|
995
996
|
collectionId,
|
|
996
997
|
normalizedQuery,
|
|
@@ -1001,20 +1002,22 @@ var ContentEngine = class {
|
|
|
1001
1002
|
);
|
|
1002
1003
|
});
|
|
1003
1004
|
this.circuitBreaker.recordSuccess();
|
|
1004
|
-
return includeMetadata ?
|
|
1005
|
+
return includeMetadata ? entry : entry.data;
|
|
1005
1006
|
} catch (error) {
|
|
1006
1007
|
this.circuitBreaker.recordFailure();
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1008
|
+
try {
|
|
1009
|
+
const localCollection = await this.localCache.getCollection(collectionId);
|
|
1010
|
+
if (localCollection) {
|
|
1011
|
+
console.warn(
|
|
1012
|
+
`[GN-Apex] \u26A0\uFE0F Network timeout on '${collectionId}', successfully recovered from local cache.`
|
|
1013
|
+
);
|
|
1014
|
+
const result = this.applyLocalQuery(
|
|
1015
|
+
localCollection,
|
|
1016
|
+
normalizedQuery
|
|
1017
|
+
);
|
|
1018
|
+
return includeMetadata ? result : result;
|
|
1017
1019
|
}
|
|
1020
|
+
} catch {
|
|
1018
1021
|
}
|
|
1019
1022
|
throw this.normalizeError(
|
|
1020
1023
|
error,
|
|
@@ -1073,14 +1076,15 @@ var ContentEngine = class {
|
|
|
1073
1076
|
}
|
|
1074
1077
|
return data;
|
|
1075
1078
|
} catch (error) {
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1079
|
+
try {
|
|
1080
|
+
const localGlobals = await this.localCache.getGlobals();
|
|
1081
|
+
if (localGlobals) {
|
|
1082
|
+
console.warn(
|
|
1083
|
+
`[GN-Apex] \u26A0\uFE0F Network timeout on globals, successfully recovered from local cache.`
|
|
1084
|
+
);
|
|
1085
|
+
return localGlobals;
|
|
1083
1086
|
}
|
|
1087
|
+
} catch {
|
|
1084
1088
|
}
|
|
1085
1089
|
throw this.normalizeError(error, "Failed to fetch globals");
|
|
1086
1090
|
}
|
|
@@ -1231,7 +1235,7 @@ var ContentEngine = class {
|
|
|
1231
1235
|
};
|
|
1232
1236
|
}
|
|
1233
1237
|
writeCache(key, data, options) {
|
|
1234
|
-
const ttlSeconds = options.revalidate === false ?
|
|
1238
|
+
const ttlSeconds = options.revalidate === false ? 5 : Math.max(1, options.revalidate);
|
|
1235
1239
|
if (this.cacheStrategy === "memory") {
|
|
1236
1240
|
this.memoryCache.set(key, data, {
|
|
1237
1241
|
tags: options.tags,
|
|
@@ -1394,7 +1398,7 @@ var ContentEngine = class {
|
|
|
1394
1398
|
}
|
|
1395
1399
|
async fetchWithTimeout(url, options = {}) {
|
|
1396
1400
|
const {
|
|
1397
|
-
timeout = this.config.timeout ||
|
|
1401
|
+
timeout = this.config.timeout || 25e3,
|
|
1398
1402
|
tags = [],
|
|
1399
1403
|
revalidate,
|
|
1400
1404
|
forceRefresh = false,
|
|
@@ -1572,7 +1576,6 @@ var VitalsCollector = class {
|
|
|
1572
1576
|
tcp_connect: navEntry.connectEnd - navEntry.connectStart,
|
|
1573
1577
|
request_time: navEntry.responseEnd - navEntry.requestStart,
|
|
1574
1578
|
dom_load: navEntry.domComplete - navEntry.domInteractive,
|
|
1575
|
-
// NEW: raw fields matching Rust NavigationTiming struct
|
|
1576
1579
|
domain_lookup_start: navEntry.domainLookupStart,
|
|
1577
1580
|
domain_lookup_end: navEntry.domainLookupEnd,
|
|
1578
1581
|
connect_start: navEntry.connectStart,
|
|
@@ -1585,8 +1588,10 @@ var VitalsCollector = class {
|
|
|
1585
1588
|
"resource"
|
|
1586
1589
|
);
|
|
1587
1590
|
if (resourceEntries.length > 0) {
|
|
1588
|
-
this.metrics.resources = resourceEntries.filter(
|
|
1589
|
-
name
|
|
1591
|
+
this.metrics.resources = resourceEntries.filter(
|
|
1592
|
+
(r) => !r.name.includes("/api/collect") && !r.name.includes("/analytics") && !r.name.includes("sentry.gnapex.com")
|
|
1593
|
+
).sort((a, b) => b.duration - a.duration).slice(0, 5).map((r) => ({
|
|
1594
|
+
name: r.name.length > 120 ? r.name.substring(0, 120) + "..." : r.name,
|
|
1590
1595
|
initiatorType: r.initiatorType,
|
|
1591
1596
|
duration: Math.round(r.duration),
|
|
1592
1597
|
transferSize: r.transferSize > 0 ? r.transferSize : void 0,
|
|
@@ -1618,7 +1623,7 @@ var VitalsCollector = class {
|
|
|
1618
1623
|
var vitalsCollector = new VitalsCollector();
|
|
1619
1624
|
var initVitals = (_tracker) => {
|
|
1620
1625
|
if (process.env.NODE_ENV === "development") {
|
|
1621
|
-
console.log("[
|
|
1626
|
+
console.log("[GN-Apex] Web Vitals monitoring active");
|
|
1622
1627
|
}
|
|
1623
1628
|
};
|
|
1624
1629
|
|
|
@@ -1771,7 +1776,8 @@ var Tracker = class {
|
|
|
1771
1776
|
this.anonymousId = "";
|
|
1772
1777
|
this.isFlushing = false;
|
|
1773
1778
|
this.flushPromise = null;
|
|
1774
|
-
|
|
1779
|
+
// 🛡️ Batch size set to 10 to keep payloads strictly under Actix 32KB limit
|
|
1780
|
+
this.batchSize = 10;
|
|
1775
1781
|
this.config = config;
|
|
1776
1782
|
this.endpoint = `${this.config.analyticsUrl}/api/collect`;
|
|
1777
1783
|
this.circuitBreaker = new CircuitBreaker();
|
|
@@ -1783,7 +1789,7 @@ var Tracker = class {
|
|
|
1783
1789
|
}
|
|
1784
1790
|
async initSession() {
|
|
1785
1791
|
this.visitorId = await getVisitorId(
|
|
1786
|
-
this.config.privacy?.fingerprinting ??
|
|
1792
|
+
this.config.privacy?.fingerprinting ?? true
|
|
1787
1793
|
);
|
|
1788
1794
|
let anonId = safeGetItem("nexus_anon_id");
|
|
1789
1795
|
if (!anonId) {
|
|
@@ -1809,10 +1815,11 @@ var Tracker = class {
|
|
|
1809
1815
|
if (typeof window === "undefined") return;
|
|
1810
1816
|
safeSetItem("nexus_last_active", Date.now().toString());
|
|
1811
1817
|
const entropy = await getDeviceEntropy(
|
|
1812
|
-
this.config.privacy?.fingerprinting ??
|
|
1818
|
+
this.config.privacy?.fingerprinting ?? true
|
|
1813
1819
|
);
|
|
1814
|
-
const
|
|
1815
|
-
const
|
|
1820
|
+
const isPageView = eventType === "page_view" || eventType === "performance";
|
|
1821
|
+
const perfMetrics = isPageView ? vitalsCollector.getMetricsSnapshot() : void 0;
|
|
1822
|
+
const utmParams = isPageView ? extractUtmParams(window.location.href) : void 0;
|
|
1816
1823
|
const payload = {
|
|
1817
1824
|
projectId: this.config.projectId,
|
|
1818
1825
|
sessionId: this.sessionId,
|
|
@@ -1821,10 +1828,9 @@ var Tracker = class {
|
|
|
1821
1828
|
messageId: generateUUID(),
|
|
1822
1829
|
sentAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
1823
1830
|
version: SDK_VERSION,
|
|
1824
|
-
// Dynamically synced to SDK 1.1.0
|
|
1825
1831
|
url: window.location.href,
|
|
1826
|
-
referrer: document.referrer,
|
|
1827
|
-
userAgent: window.navigator.userAgent,
|
|
1832
|
+
referrer: isPageView ? document.referrer : void 0,
|
|
1833
|
+
userAgent: isPageView ? window.navigator.userAgent : void 0,
|
|
1828
1834
|
screenWidth: window.screen.width,
|
|
1829
1835
|
screenHeight: window.screen.height,
|
|
1830
1836
|
language: window.navigator.language,
|
|
@@ -1887,6 +1893,10 @@ var Tracker = class {
|
|
|
1887
1893
|
} catch {
|
|
1888
1894
|
response = void 0;
|
|
1889
1895
|
}
|
|
1896
|
+
if (response && response.status === 413) {
|
|
1897
|
+
await eventStorage.remove(storedEvents.map((e) => e.id));
|
|
1898
|
+
return;
|
|
1899
|
+
}
|
|
1890
1900
|
if (!response || response.status === 404 || response.status === 405) {
|
|
1891
1901
|
const results = await Promise.allSettled(
|
|
1892
1902
|
payloads.map(
|
|
@@ -1899,7 +1909,7 @@ var Tracker = class {
|
|
|
1899
1909
|
)
|
|
1900
1910
|
);
|
|
1901
1911
|
const successIds = results.flatMap(
|
|
1902
|
-
(r, i) => r.status === "fulfilled" && r.value.ok ? [storedEvents[i].id] : []
|
|
1912
|
+
(r, i) => r.status === "fulfilled" && (r.value.ok || r.value.status === 413) ? [storedEvents[i].id] : []
|
|
1903
1913
|
);
|
|
1904
1914
|
if (successIds.length) await eventStorage.remove(successIds);
|
|
1905
1915
|
if (successIds.length === storedEvents.length) {
|
package/dist/react.cjs
CHANGED
|
@@ -865,7 +865,7 @@ var ContentEngine = class {
|
|
|
865
865
|
);
|
|
866
866
|
if (this.config.debug && duration > 100) {
|
|
867
867
|
console.warn(
|
|
868
|
-
`[
|
|
868
|
+
`[GN-Apex] \u26A0\uFE0F getPage("${slug}") took ${duration.toFixed(2)}ms`
|
|
869
869
|
);
|
|
870
870
|
}
|
|
871
871
|
return result;
|
|
@@ -902,7 +902,7 @@ var ContentEngine = class {
|
|
|
902
902
|
}
|
|
903
903
|
}
|
|
904
904
|
if (this.circuitBreaker.isOpen()) {
|
|
905
|
-
throw new Error("[
|
|
905
|
+
throw new Error("[GN-Apex] Circuit open. API is unavailable.");
|
|
906
906
|
}
|
|
907
907
|
try {
|
|
908
908
|
await this.rateLimiter.checkLimit();
|
|
@@ -919,21 +919,22 @@ var ContentEngine = class {
|
|
|
919
919
|
return includeMetadata ? data : data.data;
|
|
920
920
|
} catch (error) {
|
|
921
921
|
this.circuitBreaker.recordFailure();
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
922
|
+
try {
|
|
923
|
+
const local = await this.localCache.getPage(slug);
|
|
924
|
+
if (local) {
|
|
925
|
+
console.warn(
|
|
926
|
+
`[GN-Apex] \u26A0\uFE0F Network timeout on '${slug}', successfully recovered from local cache.`
|
|
927
|
+
);
|
|
928
|
+
return includeMetadata ? {
|
|
929
|
+
data: local,
|
|
930
|
+
metadata: {
|
|
931
|
+
timestamp: Date.now(),
|
|
932
|
+
expiresAt: Infinity,
|
|
933
|
+
tags: []
|
|
934
|
+
}
|
|
935
|
+
} : local;
|
|
936
936
|
}
|
|
937
|
+
} catch (e7) {
|
|
937
938
|
}
|
|
938
939
|
throw this.normalizeError(error, `Failed to fetch page '${slug}'`);
|
|
939
940
|
}
|
|
@@ -962,17 +963,17 @@ var ContentEngine = class {
|
|
|
962
963
|
localCollection,
|
|
963
964
|
normalizedQuery
|
|
964
965
|
);
|
|
965
|
-
return result;
|
|
966
|
+
return includeMetadata ? result : result;
|
|
966
967
|
}
|
|
967
968
|
} catch (e8) {
|
|
968
969
|
}
|
|
969
970
|
}
|
|
970
971
|
if (this.circuitBreaker.isOpen()) {
|
|
971
|
-
throw new Error("[
|
|
972
|
+
throw new Error("[GN-Apex] Circuit open. API is unavailable.");
|
|
972
973
|
}
|
|
973
974
|
try {
|
|
974
975
|
await this.rateLimiter.checkLimit();
|
|
975
|
-
const
|
|
976
|
+
const entry = await this.backoff.execute(async () => {
|
|
976
977
|
return this.fetchCollection(
|
|
977
978
|
collectionId,
|
|
978
979
|
normalizedQuery,
|
|
@@ -983,20 +984,22 @@ var ContentEngine = class {
|
|
|
983
984
|
);
|
|
984
985
|
});
|
|
985
986
|
this.circuitBreaker.recordSuccess();
|
|
986
|
-
return includeMetadata ?
|
|
987
|
+
return includeMetadata ? entry : entry.data;
|
|
987
988
|
} catch (error) {
|
|
988
989
|
this.circuitBreaker.recordFailure();
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
990
|
+
try {
|
|
991
|
+
const localCollection = await this.localCache.getCollection(collectionId);
|
|
992
|
+
if (localCollection) {
|
|
993
|
+
console.warn(
|
|
994
|
+
`[GN-Apex] \u26A0\uFE0F Network timeout on '${collectionId}', successfully recovered from local cache.`
|
|
995
|
+
);
|
|
996
|
+
const result = this.applyLocalQuery(
|
|
997
|
+
localCollection,
|
|
998
|
+
normalizedQuery
|
|
999
|
+
);
|
|
1000
|
+
return includeMetadata ? result : result;
|
|
999
1001
|
}
|
|
1002
|
+
} catch (e9) {
|
|
1000
1003
|
}
|
|
1001
1004
|
throw this.normalizeError(
|
|
1002
1005
|
error,
|
|
@@ -1055,14 +1058,15 @@ var ContentEngine = class {
|
|
|
1055
1058
|
}
|
|
1056
1059
|
return data;
|
|
1057
1060
|
} catch (error) {
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1061
|
+
try {
|
|
1062
|
+
const localGlobals = await this.localCache.getGlobals();
|
|
1063
|
+
if (localGlobals) {
|
|
1064
|
+
console.warn(
|
|
1065
|
+
`[GN-Apex] \u26A0\uFE0F Network timeout on globals, successfully recovered from local cache.`
|
|
1066
|
+
);
|
|
1067
|
+
return localGlobals;
|
|
1065
1068
|
}
|
|
1069
|
+
} catch (e11) {
|
|
1066
1070
|
}
|
|
1067
1071
|
throw this.normalizeError(error, "Failed to fetch globals");
|
|
1068
1072
|
}
|
|
@@ -1213,7 +1217,7 @@ var ContentEngine = class {
|
|
|
1213
1217
|
};
|
|
1214
1218
|
}
|
|
1215
1219
|
writeCache(key, data, options) {
|
|
1216
|
-
const ttlSeconds = options.revalidate === false ?
|
|
1220
|
+
const ttlSeconds = options.revalidate === false ? 5 : Math.max(1, options.revalidate);
|
|
1217
1221
|
if (this.cacheStrategy === "memory") {
|
|
1218
1222
|
this.memoryCache.set(key, data, {
|
|
1219
1223
|
tags: options.tags,
|
|
@@ -1376,7 +1380,7 @@ var ContentEngine = class {
|
|
|
1376
1380
|
}
|
|
1377
1381
|
async fetchWithTimeout(url, options = {}) {
|
|
1378
1382
|
const {
|
|
1379
|
-
timeout = this.config.timeout ||
|
|
1383
|
+
timeout = this.config.timeout || 25e3,
|
|
1380
1384
|
tags = [],
|
|
1381
1385
|
revalidate,
|
|
1382
1386
|
forceRefresh = false,
|
|
@@ -1551,7 +1555,6 @@ var VitalsCollector = class {
|
|
|
1551
1555
|
tcp_connect: navEntry.connectEnd - navEntry.connectStart,
|
|
1552
1556
|
request_time: navEntry.responseEnd - navEntry.requestStart,
|
|
1553
1557
|
dom_load: navEntry.domComplete - navEntry.domInteractive,
|
|
1554
|
-
// NEW: raw fields matching Rust NavigationTiming struct
|
|
1555
1558
|
domain_lookup_start: navEntry.domainLookupStart,
|
|
1556
1559
|
domain_lookup_end: navEntry.domainLookupEnd,
|
|
1557
1560
|
connect_start: navEntry.connectStart,
|
|
@@ -1564,8 +1567,10 @@ var VitalsCollector = class {
|
|
|
1564
1567
|
"resource"
|
|
1565
1568
|
);
|
|
1566
1569
|
if (resourceEntries.length > 0) {
|
|
1567
|
-
this.metrics.resources = resourceEntries.filter(
|
|
1568
|
-
name
|
|
1570
|
+
this.metrics.resources = resourceEntries.filter(
|
|
1571
|
+
(r) => !r.name.includes("/api/collect") && !r.name.includes("/analytics") && !r.name.includes("sentry.gnapex.com")
|
|
1572
|
+
).sort((a, b) => b.duration - a.duration).slice(0, 5).map((r) => ({
|
|
1573
|
+
name: r.name.length > 120 ? r.name.substring(0, 120) + "..." : r.name,
|
|
1569
1574
|
initiatorType: r.initiatorType,
|
|
1570
1575
|
duration: Math.round(r.duration),
|
|
1571
1576
|
transferSize: r.transferSize > 0 ? r.transferSize : void 0,
|
|
@@ -1597,7 +1602,7 @@ var VitalsCollector = class {
|
|
|
1597
1602
|
var vitalsCollector = new VitalsCollector();
|
|
1598
1603
|
var initVitals = (_tracker) => {
|
|
1599
1604
|
if (process.env.NODE_ENV === "development") {
|
|
1600
|
-
console.log("[
|
|
1605
|
+
console.log("[GN-Apex] Web Vitals monitoring active");
|
|
1601
1606
|
}
|
|
1602
1607
|
};
|
|
1603
1608
|
|
|
@@ -1750,7 +1755,8 @@ var Tracker = class {
|
|
|
1750
1755
|
this.anonymousId = "";
|
|
1751
1756
|
this.isFlushing = false;
|
|
1752
1757
|
this.flushPromise = null;
|
|
1753
|
-
|
|
1758
|
+
// 🛡️ Batch size set to 10 to keep payloads strictly under Actix 32KB limit
|
|
1759
|
+
this.batchSize = 10;
|
|
1754
1760
|
this.config = config;
|
|
1755
1761
|
this.endpoint = `${this.config.analyticsUrl}/api/collect`;
|
|
1756
1762
|
this.circuitBreaker = new CircuitBreaker();
|
|
@@ -1762,7 +1768,7 @@ var Tracker = class {
|
|
|
1762
1768
|
}
|
|
1763
1769
|
async initSession() {
|
|
1764
1770
|
this.visitorId = await getVisitorId(
|
|
1765
|
-
_nullishCoalesce(_optionalChain([this, 'access', _27 => _27.config, 'access', _28 => _28.privacy, 'optionalAccess', _29 => _29.fingerprinting]), () => (
|
|
1771
|
+
_nullishCoalesce(_optionalChain([this, 'access', _27 => _27.config, 'access', _28 => _28.privacy, 'optionalAccess', _29 => _29.fingerprinting]), () => ( true))
|
|
1766
1772
|
);
|
|
1767
1773
|
let anonId = safeGetItem("nexus_anon_id");
|
|
1768
1774
|
if (!anonId) {
|
|
@@ -1788,10 +1794,11 @@ var Tracker = class {
|
|
|
1788
1794
|
if (typeof window === "undefined") return;
|
|
1789
1795
|
safeSetItem("nexus_last_active", Date.now().toString());
|
|
1790
1796
|
const entropy = await getDeviceEntropy(
|
|
1791
|
-
_nullishCoalesce(_optionalChain([this, 'access', _30 => _30.config, 'access', _31 => _31.privacy, 'optionalAccess', _32 => _32.fingerprinting]), () => (
|
|
1797
|
+
_nullishCoalesce(_optionalChain([this, 'access', _30 => _30.config, 'access', _31 => _31.privacy, 'optionalAccess', _32 => _32.fingerprinting]), () => ( true))
|
|
1792
1798
|
);
|
|
1793
|
-
const
|
|
1794
|
-
const
|
|
1799
|
+
const isPageView = eventType === "page_view" || eventType === "performance";
|
|
1800
|
+
const perfMetrics = isPageView ? vitalsCollector.getMetricsSnapshot() : void 0;
|
|
1801
|
+
const utmParams = isPageView ? extractUtmParams(window.location.href) : void 0;
|
|
1795
1802
|
const payload = {
|
|
1796
1803
|
projectId: this.config.projectId,
|
|
1797
1804
|
sessionId: this.sessionId,
|
|
@@ -1800,10 +1807,9 @@ var Tracker = class {
|
|
|
1800
1807
|
messageId: generateUUID(),
|
|
1801
1808
|
sentAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
1802
1809
|
version: _chunkOP3LNZPCcjs.SDK_VERSION,
|
|
1803
|
-
// Dynamically synced to SDK 1.1.0
|
|
1804
1810
|
url: window.location.href,
|
|
1805
|
-
referrer: document.referrer,
|
|
1806
|
-
userAgent: window.navigator.userAgent,
|
|
1811
|
+
referrer: isPageView ? document.referrer : void 0,
|
|
1812
|
+
userAgent: isPageView ? window.navigator.userAgent : void 0,
|
|
1807
1813
|
screenWidth: window.screen.width,
|
|
1808
1814
|
screenHeight: window.screen.height,
|
|
1809
1815
|
language: window.navigator.language,
|
|
@@ -1866,6 +1872,10 @@ var Tracker = class {
|
|
|
1866
1872
|
} catch (e17) {
|
|
1867
1873
|
response = void 0;
|
|
1868
1874
|
}
|
|
1875
|
+
if (response && response.status === 413) {
|
|
1876
|
+
await eventStorage.remove(storedEvents.map((e) => e.id));
|
|
1877
|
+
return;
|
|
1878
|
+
}
|
|
1869
1879
|
if (!response || response.status === 404 || response.status === 405) {
|
|
1870
1880
|
const results = await Promise.allSettled(
|
|
1871
1881
|
payloads.map(
|
|
@@ -1878,7 +1888,7 @@ var Tracker = class {
|
|
|
1878
1888
|
)
|
|
1879
1889
|
);
|
|
1880
1890
|
const successIds = results.flatMap(
|
|
1881
|
-
(r, i) => r.status === "fulfilled" && r.value.ok ? [storedEvents[i].id] : []
|
|
1891
|
+
(r, i) => r.status === "fulfilled" && (r.value.ok || r.value.status === 413) ? [storedEvents[i].id] : []
|
|
1882
1892
|
);
|
|
1883
1893
|
if (successIds.length) await eventStorage.remove(successIds);
|
|
1884
1894
|
if (successIds.length === storedEvents.length) {
|
package/dist/react.js
CHANGED
|
@@ -865,7 +865,7 @@ var ContentEngine = class {
|
|
|
865
865
|
);
|
|
866
866
|
if (this.config.debug && duration > 100) {
|
|
867
867
|
console.warn(
|
|
868
|
-
`[
|
|
868
|
+
`[GN-Apex] \u26A0\uFE0F getPage("${slug}") took ${duration.toFixed(2)}ms`
|
|
869
869
|
);
|
|
870
870
|
}
|
|
871
871
|
return result;
|
|
@@ -902,7 +902,7 @@ var ContentEngine = class {
|
|
|
902
902
|
}
|
|
903
903
|
}
|
|
904
904
|
if (this.circuitBreaker.isOpen()) {
|
|
905
|
-
throw new Error("[
|
|
905
|
+
throw new Error("[GN-Apex] Circuit open. API is unavailable.");
|
|
906
906
|
}
|
|
907
907
|
try {
|
|
908
908
|
await this.rateLimiter.checkLimit();
|
|
@@ -919,21 +919,22 @@ var ContentEngine = class {
|
|
|
919
919
|
return includeMetadata ? data : data.data;
|
|
920
920
|
} catch (error) {
|
|
921
921
|
this.circuitBreaker.recordFailure();
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
922
|
+
try {
|
|
923
|
+
const local = await this.localCache.getPage(slug);
|
|
924
|
+
if (local) {
|
|
925
|
+
console.warn(
|
|
926
|
+
`[GN-Apex] \u26A0\uFE0F Network timeout on '${slug}', successfully recovered from local cache.`
|
|
927
|
+
);
|
|
928
|
+
return includeMetadata ? {
|
|
929
|
+
data: local,
|
|
930
|
+
metadata: {
|
|
931
|
+
timestamp: Date.now(),
|
|
932
|
+
expiresAt: Infinity,
|
|
933
|
+
tags: []
|
|
934
|
+
}
|
|
935
|
+
} : local;
|
|
936
936
|
}
|
|
937
|
+
} catch {
|
|
937
938
|
}
|
|
938
939
|
throw this.normalizeError(error, `Failed to fetch page '${slug}'`);
|
|
939
940
|
}
|
|
@@ -962,17 +963,17 @@ var ContentEngine = class {
|
|
|
962
963
|
localCollection,
|
|
963
964
|
normalizedQuery
|
|
964
965
|
);
|
|
965
|
-
return result;
|
|
966
|
+
return includeMetadata ? result : result;
|
|
966
967
|
}
|
|
967
968
|
} catch {
|
|
968
969
|
}
|
|
969
970
|
}
|
|
970
971
|
if (this.circuitBreaker.isOpen()) {
|
|
971
|
-
throw new Error("[
|
|
972
|
+
throw new Error("[GN-Apex] Circuit open. API is unavailable.");
|
|
972
973
|
}
|
|
973
974
|
try {
|
|
974
975
|
await this.rateLimiter.checkLimit();
|
|
975
|
-
const
|
|
976
|
+
const entry = await this.backoff.execute(async () => {
|
|
976
977
|
return this.fetchCollection(
|
|
977
978
|
collectionId,
|
|
978
979
|
normalizedQuery,
|
|
@@ -983,20 +984,22 @@ var ContentEngine = class {
|
|
|
983
984
|
);
|
|
984
985
|
});
|
|
985
986
|
this.circuitBreaker.recordSuccess();
|
|
986
|
-
return includeMetadata ?
|
|
987
|
+
return includeMetadata ? entry : entry.data;
|
|
987
988
|
} catch (error) {
|
|
988
989
|
this.circuitBreaker.recordFailure();
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
990
|
+
try {
|
|
991
|
+
const localCollection = await this.localCache.getCollection(collectionId);
|
|
992
|
+
if (localCollection) {
|
|
993
|
+
console.warn(
|
|
994
|
+
`[GN-Apex] \u26A0\uFE0F Network timeout on '${collectionId}', successfully recovered from local cache.`
|
|
995
|
+
);
|
|
996
|
+
const result = this.applyLocalQuery(
|
|
997
|
+
localCollection,
|
|
998
|
+
normalizedQuery
|
|
999
|
+
);
|
|
1000
|
+
return includeMetadata ? result : result;
|
|
999
1001
|
}
|
|
1002
|
+
} catch {
|
|
1000
1003
|
}
|
|
1001
1004
|
throw this.normalizeError(
|
|
1002
1005
|
error,
|
|
@@ -1055,14 +1058,15 @@ var ContentEngine = class {
|
|
|
1055
1058
|
}
|
|
1056
1059
|
return data;
|
|
1057
1060
|
} catch (error) {
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1061
|
+
try {
|
|
1062
|
+
const localGlobals = await this.localCache.getGlobals();
|
|
1063
|
+
if (localGlobals) {
|
|
1064
|
+
console.warn(
|
|
1065
|
+
`[GN-Apex] \u26A0\uFE0F Network timeout on globals, successfully recovered from local cache.`
|
|
1066
|
+
);
|
|
1067
|
+
return localGlobals;
|
|
1065
1068
|
}
|
|
1069
|
+
} catch {
|
|
1066
1070
|
}
|
|
1067
1071
|
throw this.normalizeError(error, "Failed to fetch globals");
|
|
1068
1072
|
}
|
|
@@ -1213,7 +1217,7 @@ var ContentEngine = class {
|
|
|
1213
1217
|
};
|
|
1214
1218
|
}
|
|
1215
1219
|
writeCache(key, data, options) {
|
|
1216
|
-
const ttlSeconds = options.revalidate === false ?
|
|
1220
|
+
const ttlSeconds = options.revalidate === false ? 5 : Math.max(1, options.revalidate);
|
|
1217
1221
|
if (this.cacheStrategy === "memory") {
|
|
1218
1222
|
this.memoryCache.set(key, data, {
|
|
1219
1223
|
tags: options.tags,
|
|
@@ -1376,7 +1380,7 @@ var ContentEngine = class {
|
|
|
1376
1380
|
}
|
|
1377
1381
|
async fetchWithTimeout(url, options = {}) {
|
|
1378
1382
|
const {
|
|
1379
|
-
timeout = this.config.timeout ||
|
|
1383
|
+
timeout = this.config.timeout || 25e3,
|
|
1380
1384
|
tags = [],
|
|
1381
1385
|
revalidate,
|
|
1382
1386
|
forceRefresh = false,
|
|
@@ -1551,7 +1555,6 @@ var VitalsCollector = class {
|
|
|
1551
1555
|
tcp_connect: navEntry.connectEnd - navEntry.connectStart,
|
|
1552
1556
|
request_time: navEntry.responseEnd - navEntry.requestStart,
|
|
1553
1557
|
dom_load: navEntry.domComplete - navEntry.domInteractive,
|
|
1554
|
-
// NEW: raw fields matching Rust NavigationTiming struct
|
|
1555
1558
|
domain_lookup_start: navEntry.domainLookupStart,
|
|
1556
1559
|
domain_lookup_end: navEntry.domainLookupEnd,
|
|
1557
1560
|
connect_start: navEntry.connectStart,
|
|
@@ -1564,8 +1567,10 @@ var VitalsCollector = class {
|
|
|
1564
1567
|
"resource"
|
|
1565
1568
|
);
|
|
1566
1569
|
if (resourceEntries.length > 0) {
|
|
1567
|
-
this.metrics.resources = resourceEntries.filter(
|
|
1568
|
-
name
|
|
1570
|
+
this.metrics.resources = resourceEntries.filter(
|
|
1571
|
+
(r) => !r.name.includes("/api/collect") && !r.name.includes("/analytics") && !r.name.includes("sentry.gnapex.com")
|
|
1572
|
+
).sort((a, b) => b.duration - a.duration).slice(0, 5).map((r) => ({
|
|
1573
|
+
name: r.name.length > 120 ? r.name.substring(0, 120) + "..." : r.name,
|
|
1569
1574
|
initiatorType: r.initiatorType,
|
|
1570
1575
|
duration: Math.round(r.duration),
|
|
1571
1576
|
transferSize: r.transferSize > 0 ? r.transferSize : void 0,
|
|
@@ -1597,7 +1602,7 @@ var VitalsCollector = class {
|
|
|
1597
1602
|
var vitalsCollector = new VitalsCollector();
|
|
1598
1603
|
var initVitals = (_tracker) => {
|
|
1599
1604
|
if (process.env.NODE_ENV === "development") {
|
|
1600
|
-
console.log("[
|
|
1605
|
+
console.log("[GN-Apex] Web Vitals monitoring active");
|
|
1601
1606
|
}
|
|
1602
1607
|
};
|
|
1603
1608
|
|
|
@@ -1750,7 +1755,8 @@ var Tracker = class {
|
|
|
1750
1755
|
this.anonymousId = "";
|
|
1751
1756
|
this.isFlushing = false;
|
|
1752
1757
|
this.flushPromise = null;
|
|
1753
|
-
|
|
1758
|
+
// 🛡️ Batch size set to 10 to keep payloads strictly under Actix 32KB limit
|
|
1759
|
+
this.batchSize = 10;
|
|
1754
1760
|
this.config = config;
|
|
1755
1761
|
this.endpoint = `${this.config.analyticsUrl}/api/collect`;
|
|
1756
1762
|
this.circuitBreaker = new CircuitBreaker();
|
|
@@ -1762,7 +1768,7 @@ var Tracker = class {
|
|
|
1762
1768
|
}
|
|
1763
1769
|
async initSession() {
|
|
1764
1770
|
this.visitorId = await getVisitorId(
|
|
1765
|
-
this.config.privacy?.fingerprinting ??
|
|
1771
|
+
this.config.privacy?.fingerprinting ?? true
|
|
1766
1772
|
);
|
|
1767
1773
|
let anonId = safeGetItem("nexus_anon_id");
|
|
1768
1774
|
if (!anonId) {
|
|
@@ -1788,10 +1794,11 @@ var Tracker = class {
|
|
|
1788
1794
|
if (typeof window === "undefined") return;
|
|
1789
1795
|
safeSetItem("nexus_last_active", Date.now().toString());
|
|
1790
1796
|
const entropy = await getDeviceEntropy(
|
|
1791
|
-
this.config.privacy?.fingerprinting ??
|
|
1797
|
+
this.config.privacy?.fingerprinting ?? true
|
|
1792
1798
|
);
|
|
1793
|
-
const
|
|
1794
|
-
const
|
|
1799
|
+
const isPageView = eventType === "page_view" || eventType === "performance";
|
|
1800
|
+
const perfMetrics = isPageView ? vitalsCollector.getMetricsSnapshot() : void 0;
|
|
1801
|
+
const utmParams = isPageView ? extractUtmParams(window.location.href) : void 0;
|
|
1795
1802
|
const payload = {
|
|
1796
1803
|
projectId: this.config.projectId,
|
|
1797
1804
|
sessionId: this.sessionId,
|
|
@@ -1800,10 +1807,9 @@ var Tracker = class {
|
|
|
1800
1807
|
messageId: generateUUID(),
|
|
1801
1808
|
sentAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
1802
1809
|
version: SDK_VERSION,
|
|
1803
|
-
// Dynamically synced to SDK 1.1.0
|
|
1804
1810
|
url: window.location.href,
|
|
1805
|
-
referrer: document.referrer,
|
|
1806
|
-
userAgent: window.navigator.userAgent,
|
|
1811
|
+
referrer: isPageView ? document.referrer : void 0,
|
|
1812
|
+
userAgent: isPageView ? window.navigator.userAgent : void 0,
|
|
1807
1813
|
screenWidth: window.screen.width,
|
|
1808
1814
|
screenHeight: window.screen.height,
|
|
1809
1815
|
language: window.navigator.language,
|
|
@@ -1866,6 +1872,10 @@ var Tracker = class {
|
|
|
1866
1872
|
} catch {
|
|
1867
1873
|
response = void 0;
|
|
1868
1874
|
}
|
|
1875
|
+
if (response && response.status === 413) {
|
|
1876
|
+
await eventStorage.remove(storedEvents.map((e) => e.id));
|
|
1877
|
+
return;
|
|
1878
|
+
}
|
|
1869
1879
|
if (!response || response.status === 404 || response.status === 405) {
|
|
1870
1880
|
const results = await Promise.allSettled(
|
|
1871
1881
|
payloads.map(
|
|
@@ -1878,7 +1888,7 @@ var Tracker = class {
|
|
|
1878
1888
|
)
|
|
1879
1889
|
);
|
|
1880
1890
|
const successIds = results.flatMap(
|
|
1881
|
-
(r, i) => r.status === "fulfilled" && r.value.ok ? [storedEvents[i].id] : []
|
|
1891
|
+
(r, i) => r.status === "fulfilled" && (r.value.ok || r.value.status === 413) ? [storedEvents[i].id] : []
|
|
1882
1892
|
);
|
|
1883
1893
|
if (successIds.length) await eventStorage.remove(successIds);
|
|
1884
1894
|
if (successIds.length === storedEvents.length) {
|