@tracelog/lib 0.0.4 → 0.0.6
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/browser/tracelog.js
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
var E = /* @__PURE__ */ ((
|
|
2
|
-
const
|
|
1
|
+
var E = /* @__PURE__ */ ((r) => (r.Mobile = "mobile", r.Tablet = "tablet", r.Desktop = "desktop", r.Unknown = "unknown", r))(E || {});
|
|
2
|
+
const B = {};
|
|
3
3
|
class p {
|
|
4
4
|
get(e) {
|
|
5
|
-
return
|
|
5
|
+
return B[e];
|
|
6
6
|
}
|
|
7
7
|
set(e, t) {
|
|
8
|
-
const s =
|
|
9
|
-
|
|
8
|
+
const s = B[e];
|
|
9
|
+
B[e] = t, (e === "sessionId" || e === "config" || e === "hasStartSession") && i.debug("StateManager", "Critical state updated", {
|
|
10
10
|
key: e,
|
|
11
11
|
oldValue: e === "config" ? !!s : s,
|
|
12
12
|
newValue: e === "config" ? !!t : t
|
|
@@ -98,16 +98,16 @@ class Re extends p {
|
|
|
98
98
|
return "log";
|
|
99
99
|
}
|
|
100
100
|
}
|
|
101
|
-
logMessage(e, t, s,
|
|
101
|
+
logMessage(e, t, s, n) {
|
|
102
102
|
if (!this.shouldShowLog(e))
|
|
103
103
|
return;
|
|
104
104
|
const a = this.formatMessage(t, s), o = this.getConsoleMethod(e);
|
|
105
|
-
|
|
105
|
+
n !== void 0 ? console[o](a, n) : console[o](a);
|
|
106
106
|
}
|
|
107
107
|
/**
|
|
108
108
|
* Dispatches tracelog:log events for E2E testing and development debugging
|
|
109
109
|
*/
|
|
110
|
-
dispatchEvent(e, t, s,
|
|
110
|
+
dispatchEvent(e, t, s, n) {
|
|
111
111
|
if (!(typeof window > "u" || typeof CustomEvent > "u"))
|
|
112
112
|
try {
|
|
113
113
|
const a = new CustomEvent("tracelog:log", {
|
|
@@ -116,12 +116,12 @@ class Re extends p {
|
|
|
116
116
|
level: e,
|
|
117
117
|
namespace: t,
|
|
118
118
|
message: s,
|
|
119
|
-
data:
|
|
119
|
+
data: n
|
|
120
120
|
}
|
|
121
121
|
});
|
|
122
122
|
window.dispatchEvent(a);
|
|
123
123
|
} catch {
|
|
124
|
-
console.log(`[TraceLog:${t}] ${s}`,
|
|
124
|
+
console.log(`[TraceLog:${t}] ${s}`, n);
|
|
125
125
|
}
|
|
126
126
|
}
|
|
127
127
|
}
|
|
@@ -132,39 +132,39 @@ const ke = () => {
|
|
|
132
132
|
}, we = () => {
|
|
133
133
|
try {
|
|
134
134
|
i.debug("DeviceDetector", "Starting device detection");
|
|
135
|
-
const
|
|
136
|
-
if (
|
|
135
|
+
const r = navigator;
|
|
136
|
+
if (r.userAgentData && typeof r.userAgentData.mobile == "boolean") {
|
|
137
137
|
if (i.debug("DeviceDetector", "Using modern User-Agent Client Hints API", {
|
|
138
|
-
mobile:
|
|
139
|
-
platform:
|
|
140
|
-
}),
|
|
138
|
+
mobile: r.userAgentData.mobile,
|
|
139
|
+
platform: r.userAgentData.platform
|
|
140
|
+
}), r.userAgentData.platform && /ipad|tablet/i.test(r.userAgentData.platform))
|
|
141
141
|
return i.debug("DeviceDetector", "Device detected as tablet via platform hint"), E.Tablet;
|
|
142
|
-
const d =
|
|
142
|
+
const d = r.userAgentData.mobile ? E.Mobile : E.Desktop;
|
|
143
143
|
return i.debug("DeviceDetector", "Device detected via User-Agent hints", { result: d }), d;
|
|
144
144
|
}
|
|
145
145
|
i.debug("DeviceDetector", "Using fallback detection methods"), ke();
|
|
146
|
-
const e = window.innerWidth, t = J?.matches ?? !1, s = Ee?.matches ?? !1,
|
|
146
|
+
const e = window.innerWidth, t = J?.matches ?? !1, s = Ee?.matches ?? !1, n = "ontouchstart" in window || navigator.maxTouchPoints > 0, a = navigator.userAgent.toLowerCase(), o = /mobile|android|iphone|ipod|blackberry|iemobile|opera mini/.test(a), l = /tablet|ipad|android(?!.*mobile)/.test(a), c = {
|
|
147
147
|
width: e,
|
|
148
148
|
hasCoarsePointer: t,
|
|
149
149
|
hasNoHover: s,
|
|
150
|
-
hasTouchSupport:
|
|
150
|
+
hasTouchSupport: n,
|
|
151
151
|
isMobileUA: o,
|
|
152
152
|
isTabletUA: l,
|
|
153
153
|
maxTouchPoints: navigator.maxTouchPoints
|
|
154
154
|
};
|
|
155
|
-
return e <= 767 || o &&
|
|
156
|
-
} catch (
|
|
155
|
+
return e <= 767 || o && n ? (i.debug("DeviceDetector", "Device detected as mobile", c), E.Mobile) : e >= 768 && e <= 1024 || l || t && s && n ? (i.debug("DeviceDetector", "Device detected as tablet", c), E.Tablet) : (i.debug("DeviceDetector", "Device detected as desktop", c), E.Desktop);
|
|
156
|
+
} catch (r) {
|
|
157
157
|
return i.warn("DeviceDetector", "Device detection failed, defaulting to desktop", {
|
|
158
|
-
error:
|
|
158
|
+
error: r instanceof Error ? r.message : r
|
|
159
159
|
}), E.Desktop;
|
|
160
160
|
}
|
|
161
|
-
}, Ne = 2, Ue = 10, Ie = 1, ne = 500, Z = 3e4, ee = 864e5, re = 120, ae = 8 * 1024, oe = 10, ce = 10, _ = 255, M = 1e3, W = 100, le = 3, N = 2,
|
|
161
|
+
}, Ne = 2, Ue = 10, Ie = 1, ne = 500, Z = 3e4, ee = 864e5, re = 120, ae = 8 * 1024, oe = 10, ce = 10, _ = 255, M = 1e3, W = 100, le = 3, N = 2, He = 4, Pe = 0.75, De = 0.2, xe = 2e3, Oe = 1e3, Fe = 10, F = 10, R = 15 * 60 * 1e3, ze = 3e4, Te = 1e3, Me = 250, Ve = 2e3, de = 1e3, $e = 1e4, je = 2500, he = 1e3, ue = 3e4, ge = 1e3, Ge = 24, Qe = 24 * 60 * 60 * 1e3, qe = Te, Be = 5e3, We = 2e3, Xe = 2, Ke = 3, X = 24 * 60 * 60 * 1e3, K = 2 * 60 * 1e3, Ae = {
|
|
162
162
|
samplingRate: Ie,
|
|
163
163
|
tags: [],
|
|
164
164
|
excludedUrlPaths: []
|
|
165
|
-
}, Ye = (
|
|
165
|
+
}, Ye = (r) => ({
|
|
166
166
|
...Ae,
|
|
167
|
-
...
|
|
167
|
+
...r,
|
|
168
168
|
sessionTimeout: R,
|
|
169
169
|
allowHttp: !1
|
|
170
170
|
}), z = "data-tl", fe = [
|
|
@@ -233,7 +233,7 @@ const ke = () => {
|
|
|
233
233
|
/<iframe\b[^<]*(?:(?!<\/iframe>)<[^<]*)*<\/iframe>/gi,
|
|
234
234
|
/<embed\b[^>]*>/gi,
|
|
235
235
|
/<object\b[^<]*(?:(?!<\/object>)<[^<]*)*<\/object>/gi
|
|
236
|
-
], S = "tl", ve = (
|
|
236
|
+
], S = "tl", ve = (r) => r ? `${S}:${r}:uid` : `${S}:uid`, et = (r) => r ? `${S}:${r}:queue` : `${S}:queue`, tt = (r) => r ? `${S}:${r}:session` : `${S}:session`, Y = (r) => r ? `${S}:${r}:cross_tab_session` : `${S}:cross_tab_session`, Se = (r, e) => `${S}:${r}:tab:${e}:info`, V = (r) => r ? `${S}:${r}:recovery` : `${S}:recovery`, st = (r) => r ? `${S}:${r}:broadcast` : `${S}:broadcast`, it = /* @__PURE__ */ new Set([
|
|
237
237
|
"mode",
|
|
238
238
|
"tags",
|
|
239
239
|
"samplingRate",
|
|
@@ -259,12 +259,12 @@ const ke = () => {
|
|
|
259
259
|
url: window.location.href,
|
|
260
260
|
search: window.location.search
|
|
261
261
|
});
|
|
262
|
-
const
|
|
262
|
+
const r = new URLSearchParams(window.location.search), e = {};
|
|
263
263
|
Je.forEach((s) => {
|
|
264
|
-
const
|
|
265
|
-
if (
|
|
264
|
+
const n = r.get(s);
|
|
265
|
+
if (n) {
|
|
266
266
|
const a = s.split("utm_")[1];
|
|
267
|
-
e[a] =
|
|
267
|
+
e[a] = n, i.debug("UTMParams", "Found UTM parameter", { param: s, key: a, value: n });
|
|
268
268
|
}
|
|
269
269
|
});
|
|
270
270
|
const t = Object.keys(e).length ? e : void 0;
|
|
@@ -273,13 +273,13 @@ const ke = () => {
|
|
|
273
273
|
parameters: Object.keys(t)
|
|
274
274
|
}) : i.debug("UTMParams", "No UTM parameters found in URL"), t;
|
|
275
275
|
}, $ = () => {
|
|
276
|
-
const
|
|
276
|
+
const r = "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, (e) => {
|
|
277
277
|
const t = Math.random() * 16 | 0;
|
|
278
278
|
return (e === "x" ? t : t & 3 | 8).toString(16);
|
|
279
279
|
});
|
|
280
|
-
return i.verbose("UUIDUtils", "Generated new UUID", { uuid:
|
|
280
|
+
return i.verbose("UUIDUtils", "Generated new UUID", { uuid: r }), r;
|
|
281
281
|
};
|
|
282
|
-
var C = /* @__PURE__ */ ((
|
|
282
|
+
var C = /* @__PURE__ */ ((r) => (r.HttpSkip = "http-skip", r.HttpLocal = "http-local", r))(C || {}), h = /* @__PURE__ */ ((r) => (r.PAGE_VIEW = "page_view", r.CLICK = "click", r.SCROLL = "scroll", r.SESSION_START = "session_start", r.SESSION_END = "session_end", r.CUSTOM = "custom", r.WEB_VITALS = "web_vitals", r.ERROR = "error", r))(h || {}), j = /* @__PURE__ */ ((r) => (r.UP = "up", r.DOWN = "down", r))(j || {}), D = /* @__PURE__ */ ((r) => (r.JS_ERROR = "js_error", r.PROMISE_REJECTION = "promise_rejection", r.NETWORK_ERROR = "network_error", r))(D || {}), L = /* @__PURE__ */ ((r) => (r.QA = "qa", r.DEBUG = "debug", r))(L || {}), G = /* @__PURE__ */ ((r) => (r.AND = "AND", r.OR = "OR", r))(G || {}), m = /* @__PURE__ */ ((r) => (r.URL_MATCHES = "url_matches", r.ELEMENT_MATCHES = "element_matches", r.DEVICE_TYPE = "device_type", r.ELEMENT_TEXT = "element_text", r.ELEMENT_ATTRIBUTE = "element_attribute", r.UTM_SOURCE = "utm_source", r.UTM_MEDIUM = "utm_medium", r.UTM_CAMPAIGN = "utm_campaign", r))(m || {}), f = /* @__PURE__ */ ((r) => (r.EQUALS = "equals", r.CONTAINS = "contains", r.STARTS_WITH = "starts_with", r.ENDS_WITH = "ends_with", r.REGEX = "regex", r.GREATER_THAN = "greater_than", r.LESS_THAN = "less_than", r.EXISTS = "exists", r.NOT_EXISTS = "not_exists", r))(f || {});
|
|
283
283
|
class x extends Error {
|
|
284
284
|
constructor(e, t, s) {
|
|
285
285
|
super(e), this.errorCode = t, this.layer = s, this.name = this.constructor.name, Error.captureStackTrace && Error.captureStackTrace(this, this.constructor);
|
|
@@ -290,7 +290,7 @@ class Q extends x {
|
|
|
290
290
|
super(e, "PROJECT_ID_INVALID", t);
|
|
291
291
|
}
|
|
292
292
|
}
|
|
293
|
-
class
|
|
293
|
+
class P extends x {
|
|
294
294
|
constructor(e, t = "config") {
|
|
295
295
|
super(e, "APP_CONFIG_INVALID", t);
|
|
296
296
|
}
|
|
@@ -310,54 +310,54 @@ class ye extends x {
|
|
|
310
310
|
super(e, "INTEGRATION_INVALID", t);
|
|
311
311
|
}
|
|
312
312
|
}
|
|
313
|
-
const ot = (
|
|
314
|
-
if (!
|
|
315
|
-
throw i.clientError("ConfigValidation", "Configuration must be an object", { config:
|
|
316
|
-
if (!("id" in
|
|
313
|
+
const ot = (r) => {
|
|
314
|
+
if (!r || typeof r != "object")
|
|
315
|
+
throw i.clientError("ConfigValidation", "Configuration must be an object", { config: r }), new P("Configuration must be an object", "config");
|
|
316
|
+
if (!("id" in r))
|
|
317
317
|
throw i.clientError("ConfigValidation", "Project ID is missing from configuration"), new Q(w.MISSING_PROJECT_ID, "config");
|
|
318
|
-
if (
|
|
318
|
+
if (r.id === null || r.id === void 0 || typeof r.id != "string")
|
|
319
319
|
throw i.clientError("ConfigValidation", "Project ID must be a non-empty string", {
|
|
320
|
-
providedId:
|
|
321
|
-
type: typeof
|
|
320
|
+
providedId: r.id,
|
|
321
|
+
type: typeof r.id
|
|
322
322
|
}), new Q(w.MISSING_PROJECT_ID, "config");
|
|
323
|
-
if (
|
|
323
|
+
if (r.sessionTimeout !== void 0 && (typeof r.sessionTimeout != "number" || r.sessionTimeout < Z || r.sessionTimeout > ee))
|
|
324
324
|
throw i.clientError("ConfigValidation", "Invalid session timeout", {
|
|
325
|
-
provided:
|
|
325
|
+
provided: r.sessionTimeout,
|
|
326
326
|
min: Z,
|
|
327
327
|
max: ee
|
|
328
328
|
}), new rt(w.INVALID_SESSION_TIMEOUT, "config");
|
|
329
|
-
if (
|
|
329
|
+
if (r.globalMetadata !== void 0 && (typeof r.globalMetadata != "object" || r.globalMetadata === null))
|
|
330
330
|
throw i.clientError("ConfigValidation", "Global metadata must be an object", {
|
|
331
|
-
provided:
|
|
332
|
-
type: typeof
|
|
333
|
-
}), new
|
|
334
|
-
if (
|
|
335
|
-
if (!Array.isArray(
|
|
331
|
+
provided: r.globalMetadata,
|
|
332
|
+
type: typeof r.globalMetadata
|
|
333
|
+
}), new P(w.INVALID_GLOBAL_METADATA, "config");
|
|
334
|
+
if (r.scrollContainerSelectors !== void 0 && ct(r.scrollContainerSelectors), r.integrations && lt(r.integrations), r.sensitiveQueryParams !== void 0) {
|
|
335
|
+
if (!Array.isArray(r.sensitiveQueryParams))
|
|
336
336
|
throw i.clientError("ConfigValidation", "Sensitive query params must be an array", {
|
|
337
|
-
provided:
|
|
338
|
-
type: typeof
|
|
339
|
-
}), new
|
|
340
|
-
for (const e of
|
|
337
|
+
provided: r.sensitiveQueryParams,
|
|
338
|
+
type: typeof r.sensitiveQueryParams
|
|
339
|
+
}), new P(w.INVALID_SENSITIVE_QUERY_PARAMS, "config");
|
|
340
|
+
for (const e of r.sensitiveQueryParams)
|
|
341
341
|
if (typeof e != "string")
|
|
342
342
|
throw i.clientError("ConfigValidation", "All sensitive query params must be strings", {
|
|
343
343
|
param: e,
|
|
344
344
|
type: typeof e
|
|
345
|
-
}), new
|
|
345
|
+
}), new P("All sensitive query params must be strings", "config");
|
|
346
346
|
}
|
|
347
|
-
if (
|
|
347
|
+
if (r.errorSampling !== void 0 && (typeof r.errorSampling != "number" || r.errorSampling < 0 || r.errorSampling > 1))
|
|
348
348
|
throw i.clientError("ConfigValidation", "Invalid error sampling rate", {
|
|
349
|
-
provided:
|
|
349
|
+
provided: r.errorSampling,
|
|
350
350
|
expected: "0-1"
|
|
351
351
|
}), new at(w.INVALID_ERROR_SAMPLING_RATE, "config");
|
|
352
|
-
}, ct = (
|
|
353
|
-
const e = Array.isArray(
|
|
352
|
+
}, ct = (r) => {
|
|
353
|
+
const e = Array.isArray(r) ? r : [r];
|
|
354
354
|
for (const t of e) {
|
|
355
355
|
if (typeof t != "string" || t.trim() === "")
|
|
356
356
|
throw i.clientError("ConfigValidation", "Invalid scroll container selector", {
|
|
357
357
|
selector: t,
|
|
358
358
|
type: typeof t,
|
|
359
359
|
isEmpty: t === "" || typeof t == "string" && t.trim() === ""
|
|
360
|
-
}), new
|
|
360
|
+
}), new P(w.INVALID_SCROLL_CONTAINER_SELECTORS, "config");
|
|
361
361
|
if (typeof document < "u")
|
|
362
362
|
try {
|
|
363
363
|
document.querySelector(t);
|
|
@@ -365,39 +365,39 @@ const ot = (n) => {
|
|
|
365
365
|
i.clientWarn("ConfigValidation", `Invalid CSS selector will be ignored: "${t}"`);
|
|
366
366
|
}
|
|
367
367
|
}
|
|
368
|
-
}, lt = (
|
|
369
|
-
if (
|
|
370
|
-
if (!
|
|
368
|
+
}, lt = (r) => {
|
|
369
|
+
if (r && r.googleAnalytics) {
|
|
370
|
+
if (!r.googleAnalytics.measurementId || typeof r.googleAnalytics.measurementId != "string" || r.googleAnalytics.measurementId.trim() === "")
|
|
371
371
|
throw i.clientError("ConfigValidation", "Invalid Google Analytics measurement ID", {
|
|
372
|
-
provided:
|
|
373
|
-
type: typeof
|
|
372
|
+
provided: r.googleAnalytics.measurementId,
|
|
373
|
+
type: typeof r.googleAnalytics.measurementId
|
|
374
374
|
}), new ye(w.INVALID_GOOGLE_ANALYTICS_ID, "config");
|
|
375
|
-
const e =
|
|
375
|
+
const e = r.googleAnalytics.measurementId.trim();
|
|
376
376
|
if (!e.match(/^(G-|UA-)/))
|
|
377
377
|
throw i.clientError("ConfigValidation", 'Google Analytics measurement ID must start with "G-" or "UA-"', {
|
|
378
378
|
provided: e
|
|
379
379
|
}), new ye('Google Analytics measurement ID must start with "G-" or "UA-"', "config");
|
|
380
380
|
}
|
|
381
|
-
}, dt = (
|
|
382
|
-
ot(
|
|
381
|
+
}, dt = (r) => {
|
|
382
|
+
ot(r);
|
|
383
383
|
const e = {
|
|
384
|
-
...
|
|
385
|
-
id:
|
|
386
|
-
globalMetadata:
|
|
387
|
-
sensitiveQueryParams:
|
|
384
|
+
...r,
|
|
385
|
+
id: r.id.trim(),
|
|
386
|
+
globalMetadata: r.globalMetadata ?? {},
|
|
387
|
+
sensitiveQueryParams: r.sensitiveQueryParams ?? []
|
|
388
388
|
};
|
|
389
389
|
if (!e.id)
|
|
390
390
|
throw i.clientError("ConfigValidation", "Project ID is empty after trimming whitespace", {
|
|
391
|
-
originalId:
|
|
391
|
+
originalId: r.id,
|
|
392
392
|
normalizedId: e.id
|
|
393
393
|
}), new Q(w.PROJECT_ID_EMPTY_AFTER_TRIM, "config");
|
|
394
394
|
return e;
|
|
395
|
-
}, be = (
|
|
396
|
-
if (!
|
|
397
|
-
return i.debug("Sanitize", "String sanitization skipped - empty or invalid input", { value:
|
|
398
|
-
const e =
|
|
399
|
-
let t =
|
|
400
|
-
|
|
395
|
+
}, be = (r) => {
|
|
396
|
+
if (!r || typeof r != "string" || r.trim().length === 0)
|
|
397
|
+
return i.debug("Sanitize", "String sanitization skipped - empty or invalid input", { value: r, type: typeof r }), "";
|
|
398
|
+
const e = r.length;
|
|
399
|
+
let t = r;
|
|
400
|
+
r.length > M && (t = r.slice(0, Math.max(0, M)), i.warn("Sanitize", "String truncated due to length limit", {
|
|
401
401
|
originalLength: e,
|
|
402
402
|
maxLength: M,
|
|
403
403
|
truncatedLength: t.length
|
|
@@ -409,52 +409,52 @@ const ot = (n) => {
|
|
|
409
409
|
}
|
|
410
410
|
s > 0 && i.warn("Sanitize", "XSS patterns detected and removed", {
|
|
411
411
|
patternMatches: s,
|
|
412
|
-
originalValue:
|
|
412
|
+
originalValue: r.slice(0, 100)
|
|
413
413
|
// Log first 100 chars for debugging
|
|
414
414
|
}), t = t.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'").replaceAll("/", "/");
|
|
415
|
-
const
|
|
415
|
+
const n = t.trim();
|
|
416
416
|
return (e > 50 || s > 0) && i.debug("Sanitize", "String sanitization completed", {
|
|
417
417
|
originalLength: e,
|
|
418
|
-
sanitizedLength:
|
|
418
|
+
sanitizedLength: n.length,
|
|
419
419
|
xssPatternMatches: s,
|
|
420
420
|
wasTruncated: e > M
|
|
421
|
-
}),
|
|
422
|
-
}, ht = (
|
|
423
|
-
if (typeof
|
|
421
|
+
}), n;
|
|
422
|
+
}, ht = (r) => {
|
|
423
|
+
if (typeof r != "string")
|
|
424
424
|
return "";
|
|
425
|
-
|
|
426
|
-
let e =
|
|
425
|
+
r.length > M && (r = r.slice(0, Math.max(0, M)));
|
|
426
|
+
let e = r;
|
|
427
427
|
for (const t of _e)
|
|
428
428
|
e = e.replace(t, "");
|
|
429
429
|
return e = e.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'"), e.trim();
|
|
430
|
-
},
|
|
430
|
+
}, q = (r, e = 0) => {
|
|
431
431
|
if (e > le)
|
|
432
432
|
return i.warn("Sanitize", "Maximum object depth exceeded during sanitization", {
|
|
433
433
|
depth: e,
|
|
434
434
|
maxDepth: le
|
|
435
435
|
}), null;
|
|
436
|
-
if (
|
|
436
|
+
if (r == null)
|
|
437
437
|
return null;
|
|
438
|
-
if (typeof
|
|
439
|
-
return be(
|
|
440
|
-
if (typeof
|
|
441
|
-
return !Number.isFinite(
|
|
442
|
-
if (typeof
|
|
443
|
-
return
|
|
444
|
-
if (Array.isArray(
|
|
445
|
-
const t =
|
|
438
|
+
if (typeof r == "string")
|
|
439
|
+
return be(r);
|
|
440
|
+
if (typeof r == "number")
|
|
441
|
+
return !Number.isFinite(r) || r < -Number.MAX_SAFE_INTEGER || r > Number.MAX_SAFE_INTEGER ? (i.warn("Sanitize", "Invalid number sanitized to 0", { value: r, isFinite: Number.isFinite(r) }), 0) : r;
|
|
442
|
+
if (typeof r == "boolean")
|
|
443
|
+
return r;
|
|
444
|
+
if (Array.isArray(r)) {
|
|
445
|
+
const t = r.length, s = r.slice(0, W);
|
|
446
446
|
t > W && i.warn("Sanitize", "Array truncated due to length limit", {
|
|
447
447
|
originalLength: t,
|
|
448
448
|
maxLength: W,
|
|
449
449
|
depth: e
|
|
450
450
|
});
|
|
451
|
-
const
|
|
452
|
-
return t > 0 &&
|
|
451
|
+
const n = s.map((a) => q(a, e + 1)).filter((a) => a !== null);
|
|
452
|
+
return t > 0 && n.length === 0 && i.warn("Sanitize", "All array items were filtered out during sanitization", { originalLength: t, depth: e }), n;
|
|
453
453
|
}
|
|
454
|
-
if (typeof
|
|
455
|
-
const t = {}, s = Object.entries(
|
|
456
|
-
|
|
457
|
-
originalKeys:
|
|
454
|
+
if (typeof r == "object") {
|
|
455
|
+
const t = {}, s = Object.entries(r), n = s.length, a = s.slice(0, 20);
|
|
456
|
+
n > 20 && i.warn("Sanitize", "Object keys truncated due to limit", {
|
|
457
|
+
originalKeys: n,
|
|
458
458
|
maxKeys: 20,
|
|
459
459
|
depth: e
|
|
460
460
|
});
|
|
@@ -462,7 +462,7 @@ const ot = (n) => {
|
|
|
462
462
|
for (const [l, c] of a) {
|
|
463
463
|
const d = be(l);
|
|
464
464
|
if (d) {
|
|
465
|
-
const u =
|
|
465
|
+
const u = q(c, e + 1);
|
|
466
466
|
u !== null ? t[d] = u : o++;
|
|
467
467
|
} else
|
|
468
468
|
o++;
|
|
@@ -473,18 +473,18 @@ const ot = (n) => {
|
|
|
473
473
|
depth: e
|
|
474
474
|
}), t;
|
|
475
475
|
}
|
|
476
|
-
return i.debug("Sanitize", "Unknown value type sanitized to null", { type: typeof
|
|
477
|
-
}, ut = (
|
|
476
|
+
return i.debug("Sanitize", "Unknown value type sanitized to null", { type: typeof r, depth: e }), null;
|
|
477
|
+
}, ut = (r) => {
|
|
478
478
|
i.debug("Sanitize", "Starting API config sanitization");
|
|
479
479
|
const e = {};
|
|
480
|
-
if (typeof
|
|
481
|
-
return i.warn("Sanitize", "API config data is not an object", { data:
|
|
480
|
+
if (typeof r != "object" || r === null)
|
|
481
|
+
return i.warn("Sanitize", "API config data is not an object", { data: r, type: typeof r }), e;
|
|
482
482
|
try {
|
|
483
|
-
const t = Object.keys(
|
|
484
|
-
let s = 0,
|
|
483
|
+
const t = Object.keys(r);
|
|
484
|
+
let s = 0, n = 0;
|
|
485
485
|
for (const a of t)
|
|
486
486
|
if (it.has(a)) {
|
|
487
|
-
const o =
|
|
487
|
+
const o = r[a];
|
|
488
488
|
if (a === "excludedUrlPaths") {
|
|
489
489
|
const l = Array.isArray(o) ? o : typeof o == "string" ? [o] : [], c = l.length;
|
|
490
490
|
e.excludedUrlPaths = l.map((u) => ht(String(u))).filter(Boolean);
|
|
@@ -496,16 +496,16 @@ const ot = (n) => {
|
|
|
496
496
|
} else if (a === "tags")
|
|
497
497
|
Array.isArray(o) ? (e.tags = o, i.debug("Sanitize", "Tags processed", { count: o.length })) : i.warn("Sanitize", "Tags value is not an array", { value: o, type: typeof o });
|
|
498
498
|
else {
|
|
499
|
-
const l =
|
|
499
|
+
const l = q(o);
|
|
500
500
|
l !== null ? e[a] = l : i.warn("Sanitize", "API config value sanitized to null", { key: a, originalValue: o });
|
|
501
501
|
}
|
|
502
502
|
s++;
|
|
503
503
|
} else
|
|
504
|
-
|
|
504
|
+
n++, i.debug("Sanitize", "API config key not allowed", { key: a });
|
|
505
505
|
i.info("Sanitize", "API config sanitization completed", {
|
|
506
506
|
originalKeys: t.length,
|
|
507
507
|
processedKeys: s,
|
|
508
|
-
filteredKeys:
|
|
508
|
+
filteredKeys: n,
|
|
509
509
|
finalKeys: Object.keys(e).length
|
|
510
510
|
});
|
|
511
511
|
} catch (t) {
|
|
@@ -514,28 +514,28 @@ const ot = (n) => {
|
|
|
514
514
|
}), new Error(`API config sanitization failed: ${t instanceof Error ? t.message : "Unknown error"}`);
|
|
515
515
|
}
|
|
516
516
|
return e;
|
|
517
|
-
}, gt = (
|
|
518
|
-
if (i.debug("Sanitize", "Starting metadata sanitization", { hasMetadata:
|
|
517
|
+
}, gt = (r) => {
|
|
518
|
+
if (i.debug("Sanitize", "Starting metadata sanitization", { hasMetadata: r != null }), typeof r != "object" || r === null)
|
|
519
519
|
return i.debug("Sanitize", "Metadata is not an object, returning empty object", {
|
|
520
|
-
metadata:
|
|
521
|
-
type: typeof
|
|
520
|
+
metadata: r,
|
|
521
|
+
type: typeof r
|
|
522
522
|
}), {};
|
|
523
523
|
try {
|
|
524
|
-
const e = Object.keys(
|
|
524
|
+
const e = Object.keys(r).length, t = q(r), s = typeof t == "object" && t !== null ? t : {}, n = Object.keys(s).length;
|
|
525
525
|
return i.debug("Sanitize", "Metadata sanitization completed", {
|
|
526
526
|
originalKeys: e,
|
|
527
|
-
finalKeys:
|
|
528
|
-
keysFiltered: e -
|
|
527
|
+
finalKeys: n,
|
|
528
|
+
keysFiltered: e - n
|
|
529
529
|
}), s;
|
|
530
530
|
} catch (e) {
|
|
531
531
|
throw i.error("Sanitize", "Metadata sanitization failed", {
|
|
532
532
|
error: e instanceof Error ? e.message : e
|
|
533
533
|
}), new Error(`Metadata sanitization failed: ${e instanceof Error ? e.message : "Unknown error"}`);
|
|
534
534
|
}
|
|
535
|
-
}, ft = (
|
|
536
|
-
if (typeof
|
|
535
|
+
}, ft = (r) => {
|
|
536
|
+
if (typeof r != "object" || r === null)
|
|
537
537
|
return !1;
|
|
538
|
-
for (const e of Object.values(
|
|
538
|
+
for (const e of Object.values(r)) {
|
|
539
539
|
if (e == null)
|
|
540
540
|
continue;
|
|
541
541
|
const t = typeof e;
|
|
@@ -549,27 +549,27 @@ const ot = (n) => {
|
|
|
549
549
|
}
|
|
550
550
|
}
|
|
551
551
|
return !0;
|
|
552
|
-
}, mt = (
|
|
552
|
+
}, mt = (r) => typeof r != "string" ? {
|
|
553
553
|
valid: !1,
|
|
554
554
|
error: "Event name must be a string"
|
|
555
|
-
} :
|
|
555
|
+
} : r.length === 0 ? {
|
|
556
556
|
valid: !1,
|
|
557
557
|
error: "Event name cannot be empty"
|
|
558
|
-
} :
|
|
558
|
+
} : r.length > re ? {
|
|
559
559
|
valid: !1,
|
|
560
560
|
error: `Event name is too long (max ${re} characters)`
|
|
561
|
-
} :
|
|
561
|
+
} : r.includes("<") || r.includes(">") || r.includes("&") ? {
|
|
562
562
|
valid: !1,
|
|
563
563
|
error: "Event name contains invalid characters"
|
|
564
|
-
} : ["constructor", "prototype", "__proto__", "eval", "function", "var", "let", "const"].includes(
|
|
564
|
+
} : ["constructor", "prototype", "__proto__", "eval", "function", "var", "let", "const"].includes(r.toLowerCase()) ? {
|
|
565
565
|
valid: !1,
|
|
566
566
|
error: "Event name cannot be a reserved word"
|
|
567
|
-
} : { valid: !0 }, pt = (
|
|
568
|
-
const s = gt(e),
|
|
567
|
+
} : { valid: !0 }, pt = (r, e, t) => {
|
|
568
|
+
const s = gt(e), n = `${t} "${r}" metadata error`;
|
|
569
569
|
if (!ft(s))
|
|
570
570
|
return {
|
|
571
571
|
valid: !1,
|
|
572
|
-
error: `${
|
|
572
|
+
error: `${n}: object has invalid types. Valid types are string, number, boolean or string arrays.`
|
|
573
573
|
};
|
|
574
574
|
let a;
|
|
575
575
|
try {
|
|
@@ -577,71 +577,71 @@ const ot = (n) => {
|
|
|
577
577
|
} catch {
|
|
578
578
|
return {
|
|
579
579
|
valid: !1,
|
|
580
|
-
error: `${
|
|
580
|
+
error: `${n}: object contains circular references or cannot be serialized.`
|
|
581
581
|
};
|
|
582
582
|
}
|
|
583
583
|
if (a.length > ae)
|
|
584
584
|
return {
|
|
585
585
|
valid: !1,
|
|
586
|
-
error: `${
|
|
586
|
+
error: `${n}: object is too large (max ${ae / 1024} KB).`
|
|
587
587
|
};
|
|
588
588
|
if (Object.keys(s).length > oe)
|
|
589
589
|
return {
|
|
590
590
|
valid: !1,
|
|
591
|
-
error: `${
|
|
591
|
+
error: `${n}: object has too many keys (max ${oe} keys).`
|
|
592
592
|
};
|
|
593
593
|
for (const [l, c] of Object.entries(s)) {
|
|
594
594
|
if (Array.isArray(c)) {
|
|
595
595
|
if (c.length > ce)
|
|
596
596
|
return {
|
|
597
597
|
valid: !1,
|
|
598
|
-
error: `${
|
|
598
|
+
error: `${n}: array property "${l}" is too large (max ${ce} items).`
|
|
599
599
|
};
|
|
600
600
|
for (const d of c)
|
|
601
601
|
if (typeof d == "string" && d.length > 500)
|
|
602
602
|
return {
|
|
603
603
|
valid: !1,
|
|
604
|
-
error: `${
|
|
604
|
+
error: `${n}: array property "${l}" contains strings that are too long (max 500 characters).`
|
|
605
605
|
};
|
|
606
606
|
}
|
|
607
607
|
if (typeof c == "string" && c.length > M)
|
|
608
608
|
return {
|
|
609
609
|
valid: !1,
|
|
610
|
-
error: `${
|
|
610
|
+
error: `${n}: property "${l}" is too long (max ${M} characters).`
|
|
611
611
|
};
|
|
612
612
|
}
|
|
613
613
|
return {
|
|
614
614
|
valid: !0,
|
|
615
615
|
sanitizedMetadata: s
|
|
616
616
|
};
|
|
617
|
-
}, vt = (
|
|
618
|
-
const t = mt(
|
|
617
|
+
}, vt = (r, e) => {
|
|
618
|
+
const t = mt(r);
|
|
619
619
|
if (!t.valid)
|
|
620
|
-
return i.clientError("EventValidation", "Event name validation failed", { eventName:
|
|
620
|
+
return i.clientError("EventValidation", "Event name validation failed", { eventName: r, error: t.error }), t;
|
|
621
621
|
if (!e)
|
|
622
622
|
return { valid: !0 };
|
|
623
|
-
const s = pt(
|
|
623
|
+
const s = pt(r, e, "customEvent");
|
|
624
624
|
return s.valid || i.clientError("EventValidation", "Event metadata validation failed", {
|
|
625
|
-
eventName:
|
|
625
|
+
eventName: r,
|
|
626
626
|
error: s.error
|
|
627
627
|
}), s;
|
|
628
|
-
}, te = (
|
|
628
|
+
}, te = (r, e = !1) => {
|
|
629
629
|
try {
|
|
630
|
-
const t = new URL(
|
|
631
|
-
return s || e &&
|
|
630
|
+
const t = new URL(r), s = t.protocol === "https:", n = t.protocol === "http:";
|
|
631
|
+
return s || e && n;
|
|
632
632
|
} catch {
|
|
633
633
|
return !1;
|
|
634
634
|
}
|
|
635
|
-
}, St = (
|
|
636
|
-
i.debug("URLUtils", "Generating API URL", { projectId:
|
|
637
|
-
const t = new URL(window.location.href), s = t.hostname,
|
|
638
|
-
if (
|
|
635
|
+
}, St = (r, e = !1) => {
|
|
636
|
+
i.debug("URLUtils", "Generating API URL", { projectId: r, allowHttp: e });
|
|
637
|
+
const t = new URL(window.location.href), s = t.hostname, n = s.split(".");
|
|
638
|
+
if (n.length === 0)
|
|
639
639
|
throw i.clientError("URLUtils", "Invalid hostname - no domain parts found", { hostname: s }), new Error("Invalid URL");
|
|
640
|
-
const a =
|
|
640
|
+
const a = n.slice(-2).join("."), o = e && t.protocol === "http:" ? "http" : "https", l = `${o}://${r}.${a}`;
|
|
641
641
|
if (i.debug("URLUtils", "Generated API URL", {
|
|
642
642
|
originalUrl: window.location.href,
|
|
643
643
|
hostname: s,
|
|
644
|
-
domainParts:
|
|
644
|
+
domainParts: n.length,
|
|
645
645
|
cleanDomain: a,
|
|
646
646
|
protocol: o,
|
|
647
647
|
generatedUrl: l
|
|
@@ -651,53 +651,53 @@ const ot = (n) => {
|
|
|
651
651
|
allowHttp: e
|
|
652
652
|
}), new Error("Invalid URL");
|
|
653
653
|
return i.debug("URLUtils", "API URL generation completed successfully", { apiUrl: l }), l;
|
|
654
|
-
}, se = (
|
|
654
|
+
}, se = (r, e = []) => {
|
|
655
655
|
i.debug("URLUtils", "Normalizing URL", {
|
|
656
|
-
urlLength:
|
|
656
|
+
urlLength: r.length,
|
|
657
657
|
sensitiveParamsCount: e.length
|
|
658
658
|
});
|
|
659
659
|
try {
|
|
660
|
-
const t = new URL(
|
|
660
|
+
const t = new URL(r), s = t.searchParams, n = Array.from(s.keys()).length;
|
|
661
661
|
let a = !1;
|
|
662
662
|
const o = [];
|
|
663
663
|
if (e.forEach((c) => {
|
|
664
664
|
s.has(c) && (s.delete(c), a = !0, o.push(c));
|
|
665
665
|
}), a && i.debug("URLUtils", "Sensitive parameters removed from URL", {
|
|
666
666
|
removedParams: o,
|
|
667
|
-
originalParamCount:
|
|
667
|
+
originalParamCount: n,
|
|
668
668
|
finalParamCount: Array.from(s.keys()).length
|
|
669
|
-
}), !a &&
|
|
670
|
-
return i.debug("URLUtils", "URL normalization - no changes needed"),
|
|
669
|
+
}), !a && r.includes("?"))
|
|
670
|
+
return i.debug("URLUtils", "URL normalization - no changes needed"), r;
|
|
671
671
|
t.search = s.toString();
|
|
672
672
|
const l = t.toString();
|
|
673
673
|
return i.debug("URLUtils", "URL normalization completed", {
|
|
674
674
|
hasChanged: a,
|
|
675
|
-
originalLength:
|
|
675
|
+
originalLength: r.length,
|
|
676
676
|
normalizedLength: l.length
|
|
677
677
|
}), l;
|
|
678
678
|
} catch (t) {
|
|
679
679
|
return i.warn("URLUtils", "URL normalization failed, returning original", {
|
|
680
|
-
url:
|
|
680
|
+
url: r.slice(0, 100),
|
|
681
681
|
error: t instanceof Error ? t.message : t
|
|
682
|
-
}),
|
|
682
|
+
}), r;
|
|
683
683
|
}
|
|
684
|
-
}, yt = (
|
|
684
|
+
}, yt = (r, e = []) => {
|
|
685
685
|
if (i.debug("URLUtils", "Checking if URL path is excluded", {
|
|
686
|
-
urlLength:
|
|
686
|
+
urlLength: r.length,
|
|
687
687
|
excludedPathsCount: e.length
|
|
688
688
|
}), e.length === 0)
|
|
689
689
|
return i.debug("URLUtils", "No excluded paths configured"), !1;
|
|
690
690
|
let t;
|
|
691
691
|
try {
|
|
692
|
-
t = new URL(
|
|
692
|
+
t = new URL(r, window.location.origin).pathname, i.debug("URLUtils", "Extracted path from URL", { path: t });
|
|
693
693
|
} catch (c) {
|
|
694
694
|
return i.warn("URLUtils", "Failed to parse URL for path exclusion check", {
|
|
695
|
-
url:
|
|
695
|
+
url: r.slice(0, 100),
|
|
696
696
|
error: c instanceof Error ? c.message : c
|
|
697
697
|
}), !1;
|
|
698
698
|
}
|
|
699
|
-
const s = (c) => typeof c == "object" && c !== void 0 && typeof c.test == "function",
|
|
700
|
-
"^" + c.split("*").map((d) =>
|
|
699
|
+
const s = (c) => typeof c == "object" && c !== void 0 && typeof c.test == "function", n = (c) => c.replaceAll(/[$()*+.?[\\\]^{|}]/g, "\\$&"), a = (c) => new RegExp(
|
|
700
|
+
"^" + c.split("*").map((d) => n(d)).join(".+") + "$"
|
|
701
701
|
), o = e.find((c) => {
|
|
702
702
|
try {
|
|
703
703
|
if (s(c)) {
|
|
@@ -748,10 +748,10 @@ class Et {
|
|
|
748
748
|
}
|
|
749
749
|
async load(e, t, s) {
|
|
750
750
|
try {
|
|
751
|
-
const
|
|
752
|
-
if (!
|
|
751
|
+
const n = s ? `${window.location.origin}/config` : this.getUrl(e);
|
|
752
|
+
if (!n)
|
|
753
753
|
throw new Error("Config URL is not valid or not allowed");
|
|
754
|
-
const a = await fetch(
|
|
754
|
+
const a = await fetch(n, {
|
|
755
755
|
method: "GET",
|
|
756
756
|
headers: { "Content-Type": "application/json" }
|
|
757
757
|
});
|
|
@@ -760,7 +760,7 @@ class Et {
|
|
|
760
760
|
throw i.error("ConfigManager", "Config API request failed", {
|
|
761
761
|
status: a.status,
|
|
762
762
|
statusText: a.statusText,
|
|
763
|
-
configUrl:
|
|
763
|
+
configUrl: n
|
|
764
764
|
}), new Error(A);
|
|
765
765
|
}
|
|
766
766
|
const o = await a.json();
|
|
@@ -773,17 +773,17 @@ class Et {
|
|
|
773
773
|
new URLSearchParams(window.location.search).get("qaMode") === "true" && !d.mode && (d.mode = L.QA, i.info("ConfigManager", "QA mode enabled via URL parameter"));
|
|
774
774
|
const y = Object.values(L).includes(d.mode) ? 1 : d.errorSampling ?? 0.1;
|
|
775
775
|
return { ...d, errorSampling: y };
|
|
776
|
-
} catch (
|
|
777
|
-
const a =
|
|
776
|
+
} catch (n) {
|
|
777
|
+
const a = n instanceof Error ? n.message : "Unknown error";
|
|
778
778
|
throw i.error("ConfigManager", "Failed to load config", { error: a, apiUrl: e }), new Error(`Failed to load config: ${a}`);
|
|
779
779
|
}
|
|
780
780
|
}
|
|
781
781
|
getUrl(e) {
|
|
782
782
|
const s = new URLSearchParams(window.location.search).get("qaMode") === "true";
|
|
783
|
-
let
|
|
784
|
-
if (s && (
|
|
785
|
-
throw i.clientError("ConfigManager", "Invalid config URL provided", { configUrl:
|
|
786
|
-
return
|
|
783
|
+
let n = `${e}/config`;
|
|
784
|
+
if (s && (n += "?qaMode=true"), !te(n))
|
|
785
|
+
throw i.clientError("ConfigManager", "Invalid config URL provided", { configUrl: n }), new Error("Config URL is not valid or not allowed");
|
|
786
|
+
return n;
|
|
787
787
|
}
|
|
788
788
|
getDefaultConfig(e) {
|
|
789
789
|
return Ye({
|
|
@@ -858,13 +858,22 @@ class wt extends p {
|
|
|
858
858
|
try {
|
|
859
859
|
return (await fetch(t, {
|
|
860
860
|
method: "POST",
|
|
861
|
+
mode: "cors",
|
|
862
|
+
credentials: "omit",
|
|
863
|
+
body: s,
|
|
861
864
|
headers: {
|
|
862
|
-
"Content-Type": "application/json"
|
|
863
|
-
|
|
864
|
-
|
|
865
|
+
"Content-Type": "application/json",
|
|
866
|
+
Origin: window.location.origin,
|
|
867
|
+
Referer: window.location.href
|
|
868
|
+
}
|
|
865
869
|
})).ok;
|
|
866
|
-
} catch (
|
|
867
|
-
|
|
870
|
+
} catch (n) {
|
|
871
|
+
const a = n instanceof Error ? n.message : String(n), o = a.includes("CORS") || a.includes("NotSameOrigin") || a.includes("blocked");
|
|
872
|
+
return i.error("SenderManager", "Failed to send events async", {
|
|
873
|
+
error: a,
|
|
874
|
+
isCorsError: o,
|
|
875
|
+
url: t.replace(/\/\/[^/]+/, "//[DOMAIN]")
|
|
876
|
+
}), !1;
|
|
868
877
|
}
|
|
869
878
|
}
|
|
870
879
|
sendQueueSync(e) {
|
|
@@ -878,16 +887,22 @@ class wt extends p {
|
|
|
878
887
|
return navigator.sendBeacon(t, s);
|
|
879
888
|
}
|
|
880
889
|
sendSyncXHR(e, t) {
|
|
890
|
+
const s = new XMLHttpRequest();
|
|
881
891
|
try {
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
return i.error("SenderManager", "Sync XHR failed", {
|
|
892
|
+
return s.open("POST", e, !1), s.setRequestHeader("Content-Type", "application/json"), s.setRequestHeader("Origin", window.location.origin), s.setRequestHeader("Referer", window.location.href), s.withCredentials = !1, s.timeout = xe, s.send(t), s.status >= 200 && s.status < 300;
|
|
893
|
+
} catch (n) {
|
|
894
|
+
const a = n instanceof Error ? n.message : String(n), o = a.includes("CORS") || a.includes("NotSameOrigin") || a.includes("blocked");
|
|
895
|
+
return i.error("SenderManager", "Sync XHR failed", {
|
|
896
|
+
error: a,
|
|
897
|
+
isCorsError: o,
|
|
898
|
+
status: s.status ?? "unknown",
|
|
899
|
+
url: e.replace(/\/\/[^/]+/, "//[DOMAIN]")
|
|
900
|
+
}), !1;
|
|
886
901
|
}
|
|
887
902
|
}
|
|
888
903
|
prepareRequest(e) {
|
|
889
904
|
return {
|
|
890
|
-
url: this.get("config").id === C.HttpLocal ? window.location.origin : this.get("apiUrl")
|
|
905
|
+
url: `${this.get("config").id === C.HttpLocal ? window.location.origin : this.get("apiUrl")}/collect`,
|
|
891
906
|
payload: JSON.stringify(e)
|
|
892
907
|
};
|
|
893
908
|
}
|
|
@@ -1015,17 +1030,17 @@ class It extends p {
|
|
|
1015
1030
|
return e >= 1 ? !0 : e <= 0 ? !1 : this.getHash(this.get("userId")) % 100 / 100 < e;
|
|
1016
1031
|
}
|
|
1017
1032
|
isWebVitalEventSampledIn(e) {
|
|
1018
|
-
const t = e === "LONG_TASK", s = t ? De :
|
|
1033
|
+
const t = e === "LONG_TASK", s = t ? De : Pe;
|
|
1019
1034
|
if (s >= 1) return !0;
|
|
1020
1035
|
if (s <= 0) return !1;
|
|
1021
|
-
const
|
|
1022
|
-
return this.getHash(
|
|
1036
|
+
const n = `${this.get("userId")}|${t ? "long_task" : "web_vitals"}`;
|
|
1037
|
+
return this.getHash(n) % 100 / 100 < s;
|
|
1023
1038
|
}
|
|
1024
1039
|
getHash(e) {
|
|
1025
1040
|
let t = 0;
|
|
1026
1041
|
for (let s = 0; s < e.length; s++) {
|
|
1027
|
-
const
|
|
1028
|
-
t = (t << 5) - t +
|
|
1042
|
+
const n = e.charCodeAt(s);
|
|
1043
|
+
t = (t << 5) - t + n, t |= 0;
|
|
1029
1044
|
}
|
|
1030
1045
|
return Math.abs(t);
|
|
1031
1046
|
}
|
|
@@ -1045,7 +1060,7 @@ class Tt extends p {
|
|
|
1045
1060
|
const s = this.get("config")?.tags?.filter((a) => a.triggerType === h.PAGE_VIEW) ?? [];
|
|
1046
1061
|
if (s.length === 0)
|
|
1047
1062
|
return [];
|
|
1048
|
-
const
|
|
1063
|
+
const n = [];
|
|
1049
1064
|
for (const a of s) {
|
|
1050
1065
|
const { id: o, logicalOperator: l, conditions: c } = a, d = [];
|
|
1051
1066
|
for (const g of c)
|
|
@@ -1072,15 +1087,15 @@ class Tt extends p {
|
|
|
1072
1087
|
}
|
|
1073
1088
|
}
|
|
1074
1089
|
let u = !1;
|
|
1075
|
-
u = l === G.AND ? d.every(Boolean) : d.some(Boolean), u &&
|
|
1090
|
+
u = l === G.AND ? d.every(Boolean) : d.some(Boolean), u && n.push(o);
|
|
1076
1091
|
}
|
|
1077
|
-
return
|
|
1092
|
+
return n;
|
|
1078
1093
|
}
|
|
1079
1094
|
checkEventTypeClick(e, t) {
|
|
1080
1095
|
const s = this.get("config")?.tags?.filter((a) => a.triggerType === h.CLICK) ?? [];
|
|
1081
1096
|
if (s.length === 0)
|
|
1082
1097
|
return [];
|
|
1083
|
-
const
|
|
1098
|
+
const n = [];
|
|
1084
1099
|
for (const a of s) {
|
|
1085
1100
|
const { id: o, logicalOperator: l, conditions: c } = a, d = [];
|
|
1086
1101
|
for (const g of c) {
|
|
@@ -1117,26 +1132,26 @@ class Tt extends p {
|
|
|
1117
1132
|
}
|
|
1118
1133
|
}
|
|
1119
1134
|
let u = !1;
|
|
1120
|
-
u = l === G.AND ? d.every(Boolean) : d.some(Boolean), u &&
|
|
1135
|
+
u = l === G.AND ? d.every(Boolean) : d.some(Boolean), u && n.push(o);
|
|
1121
1136
|
}
|
|
1122
|
-
return
|
|
1137
|
+
return n;
|
|
1123
1138
|
}
|
|
1124
1139
|
matchUrlMatches(e, t) {
|
|
1125
1140
|
if (e.type !== m.URL_MATCHES)
|
|
1126
1141
|
return !1;
|
|
1127
|
-
const s = e.value.toLowerCase(),
|
|
1142
|
+
const s = e.value.toLowerCase(), n = t.toLowerCase();
|
|
1128
1143
|
switch (e.operator) {
|
|
1129
1144
|
case f.EQUALS:
|
|
1130
|
-
return
|
|
1145
|
+
return n === s;
|
|
1131
1146
|
case f.CONTAINS:
|
|
1132
|
-
return
|
|
1147
|
+
return n.includes(s);
|
|
1133
1148
|
case f.STARTS_WITH:
|
|
1134
|
-
return
|
|
1149
|
+
return n.startsWith(s);
|
|
1135
1150
|
case f.ENDS_WITH:
|
|
1136
|
-
return
|
|
1151
|
+
return n.endsWith(s);
|
|
1137
1152
|
case f.REGEX:
|
|
1138
1153
|
try {
|
|
1139
|
-
return new RegExp(s, "gi").test(
|
|
1154
|
+
return new RegExp(s, "gi").test(n);
|
|
1140
1155
|
} catch {
|
|
1141
1156
|
return !1;
|
|
1142
1157
|
}
|
|
@@ -1147,19 +1162,19 @@ class Tt extends p {
|
|
|
1147
1162
|
matchDeviceType(e, t) {
|
|
1148
1163
|
if (e.type !== m.DEVICE_TYPE)
|
|
1149
1164
|
return !1;
|
|
1150
|
-
const s = e.value.toLowerCase(),
|
|
1165
|
+
const s = e.value.toLowerCase(), n = t.toLowerCase();
|
|
1151
1166
|
switch (e.operator) {
|
|
1152
1167
|
case f.EQUALS:
|
|
1153
|
-
return
|
|
1168
|
+
return n === s;
|
|
1154
1169
|
case f.CONTAINS:
|
|
1155
|
-
return
|
|
1170
|
+
return n.includes(s);
|
|
1156
1171
|
case f.STARTS_WITH:
|
|
1157
|
-
return
|
|
1172
|
+
return n.startsWith(s);
|
|
1158
1173
|
case f.ENDS_WITH:
|
|
1159
|
-
return
|
|
1174
|
+
return n.endsWith(s);
|
|
1160
1175
|
case f.REGEX:
|
|
1161
1176
|
try {
|
|
1162
|
-
return new RegExp(s, "gi").test(
|
|
1177
|
+
return new RegExp(s, "gi").test(n);
|
|
1163
1178
|
} catch {
|
|
1164
1179
|
return !1;
|
|
1165
1180
|
}
|
|
@@ -1181,19 +1196,19 @@ class Tt extends p {
|
|
|
1181
1196
|
t.role ?? "",
|
|
1182
1197
|
t.ariaLabel ?? "",
|
|
1183
1198
|
...Object.values(t.dataAttributes ?? {})
|
|
1184
|
-
].join(" "),
|
|
1199
|
+
].join(" "), n = e.value.toLowerCase(), a = s.toLowerCase();
|
|
1185
1200
|
switch (e.operator) {
|
|
1186
1201
|
case f.EQUALS:
|
|
1187
|
-
return this.checkElementFieldEquals(t,
|
|
1202
|
+
return this.checkElementFieldEquals(t, n);
|
|
1188
1203
|
case f.CONTAINS:
|
|
1189
|
-
return a.includes(
|
|
1204
|
+
return a.includes(n);
|
|
1190
1205
|
case f.STARTS_WITH:
|
|
1191
|
-
return a.startsWith(
|
|
1206
|
+
return a.startsWith(n);
|
|
1192
1207
|
case f.ENDS_WITH:
|
|
1193
|
-
return a.endsWith(
|
|
1208
|
+
return a.endsWith(n);
|
|
1194
1209
|
case f.REGEX:
|
|
1195
1210
|
try {
|
|
1196
|
-
return new RegExp(
|
|
1211
|
+
return new RegExp(n, "gi").test(a);
|
|
1197
1212
|
} catch {
|
|
1198
1213
|
return !1;
|
|
1199
1214
|
}
|
|
@@ -1206,19 +1221,19 @@ class Tt extends p {
|
|
|
1206
1221
|
e.type
|
|
1207
1222
|
))
|
|
1208
1223
|
return !1;
|
|
1209
|
-
const s = t ?? "",
|
|
1224
|
+
const s = t ?? "", n = e.value.toLowerCase(), a = s.toLowerCase();
|
|
1210
1225
|
switch (e.operator) {
|
|
1211
1226
|
case f.EQUALS:
|
|
1212
|
-
return a ===
|
|
1227
|
+
return a === n;
|
|
1213
1228
|
case f.CONTAINS:
|
|
1214
|
-
return a.includes(
|
|
1229
|
+
return a.includes(n);
|
|
1215
1230
|
case f.STARTS_WITH:
|
|
1216
|
-
return a.startsWith(
|
|
1231
|
+
return a.startsWith(n);
|
|
1217
1232
|
case f.ENDS_WITH:
|
|
1218
|
-
return a.endsWith(
|
|
1233
|
+
return a.endsWith(n);
|
|
1219
1234
|
case f.REGEX:
|
|
1220
1235
|
try {
|
|
1221
|
-
return new RegExp(
|
|
1236
|
+
return new RegExp(n, "gi").test(a);
|
|
1222
1237
|
} catch {
|
|
1223
1238
|
return !1;
|
|
1224
1239
|
}
|
|
@@ -1238,15 +1253,15 @@ class Tt extends p {
|
|
|
1238
1253
|
e.role,
|
|
1239
1254
|
e.ariaLabel
|
|
1240
1255
|
];
|
|
1241
|
-
for (const
|
|
1242
|
-
if (
|
|
1243
|
-
const a =
|
|
1256
|
+
for (const n of s)
|
|
1257
|
+
if (n) {
|
|
1258
|
+
const a = n.toLowerCase(), o = t.toLowerCase();
|
|
1244
1259
|
if (a === o)
|
|
1245
1260
|
return !0;
|
|
1246
1261
|
}
|
|
1247
1262
|
if (e.dataAttributes)
|
|
1248
|
-
for (const
|
|
1249
|
-
const a =
|
|
1263
|
+
for (const n of Object.values(e.dataAttributes)) {
|
|
1264
|
+
const a = n.toLowerCase(), o = t.toLowerCase();
|
|
1250
1265
|
if (a === o)
|
|
1251
1266
|
return !0;
|
|
1252
1267
|
}
|
|
@@ -1284,7 +1299,7 @@ class Mt extends p {
|
|
|
1284
1299
|
type: e,
|
|
1285
1300
|
page_url: t,
|
|
1286
1301
|
from_page_url: s,
|
|
1287
|
-
scroll_data:
|
|
1302
|
+
scroll_data: n,
|
|
1288
1303
|
click_data: a,
|
|
1289
1304
|
custom_event: o,
|
|
1290
1305
|
web_vitals: l,
|
|
@@ -1296,7 +1311,7 @@ class Mt extends p {
|
|
|
1296
1311
|
page_url: t,
|
|
1297
1312
|
hasCustomEvent: !!o,
|
|
1298
1313
|
hasClickData: !!a,
|
|
1299
|
-
hasScrollData: !!
|
|
1314
|
+
hasScrollData: !!n,
|
|
1300
1315
|
hasWebVitals: !!l
|
|
1301
1316
|
}), !this.samplingManager.shouldSampleEvent(e, l)) {
|
|
1302
1317
|
i.debug("EventManager", "Event filtered by sampling", { type: e, samplingActive: !0 });
|
|
@@ -1305,7 +1320,7 @@ class Mt extends p {
|
|
|
1305
1320
|
if (this.isDuplicatedEvent({
|
|
1306
1321
|
type: e,
|
|
1307
1322
|
page_url: t,
|
|
1308
|
-
scroll_data:
|
|
1323
|
+
scroll_data: n,
|
|
1309
1324
|
click_data: a,
|
|
1310
1325
|
custom_event: o,
|
|
1311
1326
|
web_vitals: l,
|
|
@@ -1314,8 +1329,8 @@ class Mt extends p {
|
|
|
1314
1329
|
})) {
|
|
1315
1330
|
const k = Date.now();
|
|
1316
1331
|
if (this.eventsQueue && this.eventsQueue.length > 0) {
|
|
1317
|
-
const
|
|
1318
|
-
|
|
1332
|
+
const H = this.eventsQueue.at(-1);
|
|
1333
|
+
H && (H.timestamp = k);
|
|
1319
1334
|
}
|
|
1320
1335
|
this.lastEvent && (this.lastEvent.timestamp = k), i.debug("EventManager", "Duplicate event detected, timestamp updated", {
|
|
1321
1336
|
type: e,
|
|
@@ -1336,7 +1351,7 @@ class Mt extends p {
|
|
|
1336
1351
|
timestamp: Date.now(),
|
|
1337
1352
|
...U && { referrer: document.referrer || "Direct" },
|
|
1338
1353
|
...s && !y ? { from_page_url: s } : {},
|
|
1339
|
-
...
|
|
1354
|
+
...n && { scroll_data: n },
|
|
1340
1355
|
...a && { click_data: a },
|
|
1341
1356
|
...o && { custom_event: o },
|
|
1342
1357
|
...ie && { utm: ie },
|
|
@@ -1346,9 +1361,9 @@ class Mt extends p {
|
|
|
1346
1361
|
};
|
|
1347
1362
|
if (this.get("config")?.tags?.length) {
|
|
1348
1363
|
const k = this.tagsManager.getEventTagsIds(O, this.get("device"));
|
|
1349
|
-
k?.length && (O.tags = this.get("config")?.mode === "qa" || this.get("config")?.mode === "debug" ? k.map((
|
|
1350
|
-
id:
|
|
1351
|
-
key: this.get("config")?.tags?.find((Le) => Le.id ===
|
|
1364
|
+
k?.length && (O.tags = this.get("config")?.mode === "qa" || this.get("config")?.mode === "debug" ? k.map((H) => ({
|
|
1365
|
+
id: H,
|
|
1366
|
+
key: this.get("config")?.tags?.find((Le) => Le.id === H)?.key ?? ""
|
|
1352
1367
|
})) : k);
|
|
1353
1368
|
}
|
|
1354
1369
|
this.lastEvent = O, this.processAndSend(O);
|
|
@@ -1449,11 +1464,11 @@ class Mt extends p {
|
|
|
1449
1464
|
buildEventsPayload() {
|
|
1450
1465
|
const e = /* @__PURE__ */ new Map();
|
|
1451
1466
|
for (const s of this.eventsQueue) {
|
|
1452
|
-
let
|
|
1453
|
-
s.click_data && (
|
|
1467
|
+
let n = `${s.type}_${s.page_url}`;
|
|
1468
|
+
s.click_data && (n += `_${s.click_data.x}_${s.click_data.y}`), s.scroll_data && (n += `_${s.scroll_data.depth}_${s.scroll_data.direction}`), s.custom_event && (n += `_${s.custom_event.name}`), s.web_vitals && (n += `_${s.web_vitals.type}`), e.has(n) || e.set(n, s);
|
|
1454
1469
|
}
|
|
1455
1470
|
const t = [...e.values()];
|
|
1456
|
-
return t.sort((s,
|
|
1471
|
+
return t.sort((s, n) => s.timestamp - n.timestamp), {
|
|
1457
1472
|
user_id: this.get("userId"),
|
|
1458
1473
|
session_id: this.get("sessionId"),
|
|
1459
1474
|
device: this.get("device"),
|
|
@@ -1467,14 +1482,14 @@ class Mt extends p {
|
|
|
1467
1482
|
getEventFingerprint(e) {
|
|
1468
1483
|
const t = `${e.type}_${e.page_url}`;
|
|
1469
1484
|
if (e.click_data) {
|
|
1470
|
-
const s = Math.round((e.click_data.x || 0) / F) * F,
|
|
1471
|
-
return `${t}_${s}_${
|
|
1485
|
+
const s = Math.round((e.click_data.x || 0) / F) * F, n = Math.round((e.click_data.y || 0) / F) * F;
|
|
1486
|
+
return `${t}_${s}_${n}_${e.click_data.tag}_${e.click_data.id}`;
|
|
1472
1487
|
}
|
|
1473
1488
|
return e.scroll_data ? `${t}_${e.scroll_data.depth}_${e.scroll_data.direction}` : e.custom_event ? `${t}_${e.custom_event.name}` : e.web_vitals ? `${t}_${e.web_vitals.type}` : e.session_end_reason ? `${t}_${e.session_end_reason}` : e.session_start_recovered !== void 0 ? `${t}_${e.session_start_recovered}` : t;
|
|
1474
1489
|
}
|
|
1475
1490
|
isDuplicatedEvent(e) {
|
|
1476
|
-
const t = this.getEventFingerprint(e), s = this.eventFingerprints.get(t) ?? 0,
|
|
1477
|
-
return
|
|
1491
|
+
const t = this.getEventFingerprint(e), s = this.eventFingerprints.get(t) ?? 0, n = Date.now();
|
|
1492
|
+
return n - s < de ? !0 : (this.eventFingerprints.set(t, n), this.cleanupOldFingerprints(), !1);
|
|
1478
1493
|
}
|
|
1479
1494
|
/**
|
|
1480
1495
|
* Cleans up old fingerprints to prevent memory leaks
|
|
@@ -1483,10 +1498,10 @@ class Mt extends p {
|
|
|
1483
1498
|
if (this.eventFingerprints.size <= Oe)
|
|
1484
1499
|
return;
|
|
1485
1500
|
const e = Date.now(), t = de * Fe, s = [];
|
|
1486
|
-
for (const [
|
|
1487
|
-
e - a > t && s.push(
|
|
1488
|
-
for (const
|
|
1489
|
-
this.eventFingerprints.delete(
|
|
1501
|
+
for (const [n, a] of this.eventFingerprints)
|
|
1502
|
+
e - a > t && s.push(n);
|
|
1503
|
+
for (const n of s)
|
|
1504
|
+
this.eventFingerprints.delete(n);
|
|
1490
1505
|
i.debug("EventManager", "Cleaned up old event fingerprints", {
|
|
1491
1506
|
totalFingerprints: this.eventFingerprints.size + s.length,
|
|
1492
1507
|
cleanedCount: s.length,
|
|
@@ -1553,11 +1568,11 @@ class Mt extends p {
|
|
|
1553
1568
|
const e = this.storageManager.getItem(this.PERSISTENCE_KEY);
|
|
1554
1569
|
if (!e)
|
|
1555
1570
|
return;
|
|
1556
|
-
const t = JSON.parse(e), s = Date.now(),
|
|
1557
|
-
if (s - t.timestamp >
|
|
1571
|
+
const t = JSON.parse(e), s = Date.now(), n = Qe;
|
|
1572
|
+
if (s - t.timestamp > n) {
|
|
1558
1573
|
this.clearPersistedEvents(), i.debug("EventManager", "Cleared expired persisted events", {
|
|
1559
1574
|
age: s - t.timestamp,
|
|
1560
|
-
maxAge:
|
|
1575
|
+
maxAge: n
|
|
1561
1576
|
});
|
|
1562
1577
|
return;
|
|
1563
1578
|
}
|
|
@@ -1754,12 +1769,12 @@ class Ce extends p {
|
|
|
1754
1769
|
eventManager;
|
|
1755
1770
|
projectId;
|
|
1756
1771
|
debugMode;
|
|
1757
|
-
constructor(e, t, s,
|
|
1772
|
+
constructor(e, t, s, n) {
|
|
1758
1773
|
super(), this.storageManager = e, this.eventManager = s ?? null, this.projectId = t, this.debugMode = (this.get("config")?.mode === "qa" || this.get("config")?.mode === "debug") ?? !1, this.config = {
|
|
1759
1774
|
recoveryWindowMs: this.calculateRecoveryWindow(),
|
|
1760
1775
|
maxRecoveryAttempts: Ke,
|
|
1761
1776
|
contextPreservation: !0,
|
|
1762
|
-
...
|
|
1777
|
+
...n
|
|
1763
1778
|
};
|
|
1764
1779
|
}
|
|
1765
1780
|
/**
|
|
@@ -1775,22 +1790,22 @@ class Ce extends p {
|
|
|
1775
1790
|
), {
|
|
1776
1791
|
recovered: !1
|
|
1777
1792
|
};
|
|
1778
|
-
const
|
|
1779
|
-
if (!
|
|
1793
|
+
const n = s?.context;
|
|
1794
|
+
if (!n)
|
|
1780
1795
|
return this.debugMode && i.debug("SessionRecovery", "No session context available for recovery"), {
|
|
1781
1796
|
recovered: !1
|
|
1782
1797
|
};
|
|
1783
1798
|
const a = Date.now();
|
|
1784
|
-
if (a -
|
|
1799
|
+
if (a - n.lastActivity > this.config.recoveryWindowMs)
|
|
1785
1800
|
return this.debugMode && i.debug("SessionRecovery", "Session recovery failed - outside recovery window"), {
|
|
1786
1801
|
recovered: !1
|
|
1787
1802
|
};
|
|
1788
|
-
const l =
|
|
1803
|
+
const l = n.sessionId, c = (s?.attempt ?? 0) + 1, d = {
|
|
1789
1804
|
sessionId: e ?? l,
|
|
1790
1805
|
timestamp: a,
|
|
1791
1806
|
attempt: c,
|
|
1792
1807
|
context: {
|
|
1793
|
-
...
|
|
1808
|
+
...n,
|
|
1794
1809
|
recoveryAttempts: c,
|
|
1795
1810
|
lastActivity: a
|
|
1796
1811
|
}
|
|
@@ -1835,8 +1850,8 @@ class Ce extends p {
|
|
|
1835
1850
|
context: e
|
|
1836
1851
|
};
|
|
1837
1852
|
t.push(s);
|
|
1838
|
-
const
|
|
1839
|
-
t.length >
|
|
1853
|
+
const n = 5;
|
|
1854
|
+
t.length > n && t.splice(0, t.length - n), this.storeRecoveryAttempts(t), this.debugMode && i.debug("SessionRecovery", `Stored session context for recovery: ${e.sessionId}`);
|
|
1840
1855
|
} catch (t) {
|
|
1841
1856
|
this.debugMode && i.warn("SessionRecovery", "Failed to store session context for recovery", { error: t });
|
|
1842
1857
|
}
|
|
@@ -1881,7 +1896,7 @@ class Ce extends p {
|
|
|
1881
1896
|
* Clean up old recovery attempts
|
|
1882
1897
|
*/
|
|
1883
1898
|
cleanupOldRecoveryAttempts() {
|
|
1884
|
-
const e = this.getStoredRecoveryAttempts(), t = Date.now(), s = e.filter((
|
|
1899
|
+
const e = this.getStoredRecoveryAttempts(), t = Date.now(), s = e.filter((n) => t - n.timestamp <= this.config.recoveryWindowMs);
|
|
1885
1900
|
s.length !== e.length && (this.storeRecoveryAttempts(s), this.debugMode && i.debug("SessionRecovery", `Cleaned up ${e.length - s.length} old recovery attempts`));
|
|
1886
1901
|
}
|
|
1887
1902
|
/**
|
|
@@ -1968,7 +1983,7 @@ class Ut extends p {
|
|
|
1968
1983
|
crossTabConflicts: 0,
|
|
1969
1984
|
lastHealthCheck: Date.now()
|
|
1970
1985
|
};
|
|
1971
|
-
constructor(e, t, s,
|
|
1986
|
+
constructor(e, t, s, n, a) {
|
|
1972
1987
|
super(), this.config = {
|
|
1973
1988
|
throttleDelay: Te,
|
|
1974
1989
|
visibilityTimeout: Ve,
|
|
@@ -1980,7 +1995,7 @@ class Ut extends p {
|
|
|
1980
1995
|
maxRetries: 2,
|
|
1981
1996
|
debugMode: !1,
|
|
1982
1997
|
...a
|
|
1983
|
-
}, this.onActivity = e, this.onInactivity = t, this.eventManager = s ?? null, this.storageManager =
|
|
1998
|
+
}, this.onActivity = e, this.onInactivity = t, this.eventManager = s ?? null, this.storageManager = n ?? null, this.deviceCapabilities = this.detectDeviceCapabilities(), this.initializeRecoveryManager(), this.initializeListenerManagers(), this.setupAllListeners(), this.sessionEndConfig.enablePageUnloadHandlers && this.setupPageUnloadHandlers(), i.debug("SessionManager", "SessionManager initialized", {
|
|
1984
1999
|
sessionTimeout: this.config.timeout,
|
|
1985
2000
|
deviceCapabilities: this.deviceCapabilities,
|
|
1986
2001
|
unloadHandlersEnabled: this.sessionEndConfig.enablePageUnloadHandlers
|
|
@@ -2024,8 +2039,8 @@ class Ut extends p {
|
|
|
2024
2039
|
const e = Date.now();
|
|
2025
2040
|
let t = "", s = !1;
|
|
2026
2041
|
if (this.recoveryManager?.hasRecoverableSession()) {
|
|
2027
|
-
const
|
|
2028
|
-
|
|
2042
|
+
const n = this.recoveryManager.attemptSessionRecovery();
|
|
2043
|
+
n.recovered && n.recoveredSessionId && (t = n.recoveredSessionId, s = !0, this.trackSessionHealth("recovery"), n.context ? (this.sessionStartTime = n.context.startTime, this.lastActivityTime = e) : (this.sessionStartTime = e, this.lastActivityTime = e), i.info("SessionManager", "Session successfully recovered", {
|
|
2029
2044
|
sessionId: t,
|
|
2030
2045
|
recoveryAttempts: this.sessionHealth.recoveryAttempts
|
|
2031
2046
|
}));
|
|
@@ -2048,8 +2063,8 @@ class Ut extends p {
|
|
|
2048
2063
|
}), this.recoveryManager && (this.recoveryManager.cleanupOldRecoveryAttempts(), this.recoveryManager = null);
|
|
2049
2064
|
}
|
|
2050
2065
|
detectDeviceCapabilities() {
|
|
2051
|
-
const e = "ontouchstart" in window || navigator.maxTouchPoints > 0, t = window.matchMedia("(pointer: fine)").matches, s = !window.matchMedia("(pointer: coarse)").matches,
|
|
2052
|
-
return { hasTouch: e, hasMouse: t, hasKeyboard: s, isMobile:
|
|
2066
|
+
const e = "ontouchstart" in window || navigator.maxTouchPoints > 0, t = window.matchMedia("(pointer: fine)").matches, s = !window.matchMedia("(pointer: coarse)").matches, n = we() === E.Mobile;
|
|
2067
|
+
return { hasTouch: e, hasMouse: t, hasKeyboard: s, isMobile: n };
|
|
2053
2068
|
}
|
|
2054
2069
|
initializeListenerManagers() {
|
|
2055
2070
|
this.listenerManagers.push(new _t(this.handleActivity)), this.deviceCapabilities.hasTouch && this.listenerManagers.push(new Ct(this.handleActivity, this.config.motionThreshold)), this.deviceCapabilities.hasMouse && this.listenerManagers.push(new Lt(this.handleActivity)), this.deviceCapabilities.hasKeyboard && this.listenerManagers.push(new Rt(this.handleActivity)), this.listenerManagers.push(
|
|
@@ -2161,20 +2176,20 @@ class Ut extends p {
|
|
|
2161
2176
|
}
|
|
2162
2177
|
async performSessionEnd(e, t) {
|
|
2163
2178
|
const s = Date.now();
|
|
2164
|
-
let
|
|
2179
|
+
let n = 0;
|
|
2165
2180
|
try {
|
|
2166
2181
|
if (i.info("SessionManager", "Starting session end", { method: t, reason: e, timestamp: s }), this.eventManager) {
|
|
2167
2182
|
this.eventManager.track({
|
|
2168
2183
|
type: h.SESSION_END,
|
|
2169
2184
|
session_end_reason: e
|
|
2170
|
-
}),
|
|
2185
|
+
}), n = this.eventManager.getQueueLength();
|
|
2171
2186
|
const o = await this.eventManager.flushImmediately();
|
|
2172
2187
|
this.cleanupSession();
|
|
2173
2188
|
const l = {
|
|
2174
2189
|
success: o,
|
|
2175
2190
|
reason: e,
|
|
2176
2191
|
timestamp: s,
|
|
2177
|
-
eventsFlushed:
|
|
2192
|
+
eventsFlushed: n,
|
|
2178
2193
|
method: t
|
|
2179
2194
|
};
|
|
2180
2195
|
return o ? this.sessionEndStats.successfulEnds++ : this.sessionEndStats.failedEnds++, l;
|
|
@@ -2193,7 +2208,7 @@ class Ut extends p {
|
|
|
2193
2208
|
success: !1,
|
|
2194
2209
|
reason: e,
|
|
2195
2210
|
timestamp: s,
|
|
2196
|
-
eventsFlushed:
|
|
2211
|
+
eventsFlushed: n,
|
|
2197
2212
|
method: t
|
|
2198
2213
|
};
|
|
2199
2214
|
}
|
|
@@ -2241,16 +2256,16 @@ class Ut extends p {
|
|
|
2241
2256
|
return a ? this.sessionEndStats.successfulEnds++ : this.sessionEndStats.failedEnds++, o;
|
|
2242
2257
|
}
|
|
2243
2258
|
this.cleanupSession();
|
|
2244
|
-
const
|
|
2259
|
+
const n = {
|
|
2245
2260
|
success: !0,
|
|
2246
2261
|
reason: e,
|
|
2247
2262
|
timestamp: t,
|
|
2248
2263
|
eventsFlushed: 0,
|
|
2249
2264
|
method: "sync"
|
|
2250
2265
|
};
|
|
2251
|
-
return this.sessionEndStats.successfulEnds++,
|
|
2252
|
-
} catch (
|
|
2253
|
-
return this.sessionEndStats.failedEnds++, this.cleanupSession(), i.error("SessionManager", "Sync session end failed", { error:
|
|
2266
|
+
return this.sessionEndStats.successfulEnds++, n;
|
|
2267
|
+
} catch (n) {
|
|
2268
|
+
return this.sessionEndStats.failedEnds++, this.cleanupSession(), i.error("SessionManager", "Sync session end failed", { error: n, reason: e }), {
|
|
2254
2269
|
success: !1,
|
|
2255
2270
|
reason: e,
|
|
2256
2271
|
timestamp: t,
|
|
@@ -2265,16 +2280,16 @@ class Ut extends p {
|
|
|
2265
2280
|
e || !this.get("sessionId") || (e = !0, this.clearInactivityTimer(), this.endSessionSafely("page_unload", { forceSync: !0 }));
|
|
2266
2281
|
}, s = () => {
|
|
2267
2282
|
t();
|
|
2268
|
-
},
|
|
2283
|
+
}, n = (o) => {
|
|
2269
2284
|
o.persisted || t();
|
|
2270
2285
|
}, a = () => {
|
|
2271
2286
|
document.visibilityState === "hidden" && this.get("sessionId") && !e && (this.visibilityChangeTimeout = window.setTimeout(() => {
|
|
2272
2287
|
document.visibilityState === "hidden" && this.get("sessionId") && !e && t(), this.visibilityChangeTimeout = null;
|
|
2273
2288
|
}, 1e3));
|
|
2274
2289
|
};
|
|
2275
|
-
window.addEventListener("beforeunload", s), window.addEventListener("pagehide",
|
|
2290
|
+
window.addEventListener("beforeunload", s), window.addEventListener("pagehide", n), document.addEventListener("visibilitychange", a), this.cleanupHandlers.push(
|
|
2276
2291
|
() => window.removeEventListener("beforeunload", s),
|
|
2277
|
-
() => window.removeEventListener("pagehide",
|
|
2292
|
+
() => window.removeEventListener("pagehide", n),
|
|
2278
2293
|
() => document.removeEventListener("visibilitychange", a),
|
|
2279
2294
|
() => {
|
|
2280
2295
|
this.visibilityChangeTimeout && (clearTimeout(this.visibilityChangeTimeout), this.visibilityChangeTimeout = null);
|
|
@@ -2282,10 +2297,10 @@ class Ut extends p {
|
|
|
2282
2297
|
);
|
|
2283
2298
|
}
|
|
2284
2299
|
}
|
|
2285
|
-
class
|
|
2286
|
-
constructor(e, t, s,
|
|
2287
|
-
super(), this.callbacks =
|
|
2288
|
-
tabHeartbeatIntervalMs:
|
|
2300
|
+
class Ht extends p {
|
|
2301
|
+
constructor(e, t, s, n) {
|
|
2302
|
+
super(), this.callbacks = n, this.storageManager = e, this.projectId = t, this.tabId = $(), this.config = {
|
|
2303
|
+
tabHeartbeatIntervalMs: Be,
|
|
2289
2304
|
tabElectionTimeoutMs: We,
|
|
2290
2305
|
debugMode: (this.get("config")?.mode === "qa" || this.get("config")?.mode === "debug") ?? !1,
|
|
2291
2306
|
...s
|
|
@@ -2445,10 +2460,10 @@ class Pt extends p {
|
|
|
2445
2460
|
if (!this.sessionEnded && this.leaderTabId && !this.isTabLeader) {
|
|
2446
2461
|
const s = this.getStoredSessionContext();
|
|
2447
2462
|
if (s) {
|
|
2448
|
-
const
|
|
2449
|
-
|
|
2463
|
+
const n = Date.now() - s.lastActivity, a = this.config.tabHeartbeatIntervalMs * 3;
|
|
2464
|
+
n > a && (this.config.debugMode && i.warn(
|
|
2450
2465
|
"CrossTabSession",
|
|
2451
|
-
`Leader tab appears inactive (${
|
|
2466
|
+
`Leader tab appears inactive (${n}ms), attempting to become leader`
|
|
2452
2467
|
), this.leaderTabId = null, this.startLeaderElection());
|
|
2453
2468
|
}
|
|
2454
2469
|
}
|
|
@@ -2583,13 +2598,13 @@ class Pt extends p {
|
|
|
2583
2598
|
const e = Date.now(), t = this.lastHeartbeatSent ?? 0, s = this.config.tabHeartbeatIntervalMs * 0.8;
|
|
2584
2599
|
if (!this.isTabLeader && e - t < s)
|
|
2585
2600
|
return;
|
|
2586
|
-
const
|
|
2601
|
+
const n = {
|
|
2587
2602
|
type: "heartbeat",
|
|
2588
2603
|
tabId: this.tabId,
|
|
2589
2604
|
sessionId: this.tabInfo.sessionId,
|
|
2590
2605
|
timestamp: e
|
|
2591
2606
|
};
|
|
2592
|
-
this.broadcastChannel.postMessage(
|
|
2607
|
+
this.broadcastChannel.postMessage(n), this.lastHeartbeatSent = e;
|
|
2593
2608
|
}
|
|
2594
2609
|
/**
|
|
2595
2610
|
* Update tab info with current timestamp
|
|
@@ -2712,8 +2727,8 @@ class Pt extends p {
|
|
|
2712
2727
|
const e = this.getStoredSessionContext();
|
|
2713
2728
|
if (!e)
|
|
2714
2729
|
return this.get("config")?.sessionTimeout ?? R;
|
|
2715
|
-
const s = Date.now() - e.lastActivity,
|
|
2716
|
-
return Math.max(0,
|
|
2730
|
+
const s = Date.now() - e.lastActivity, n = this.get("config")?.sessionTimeout ?? R;
|
|
2731
|
+
return Math.max(0, n - s);
|
|
2717
2732
|
}
|
|
2718
2733
|
/**
|
|
2719
2734
|
* Update session activity from any tab
|
|
@@ -2729,7 +2744,7 @@ class Pt extends p {
|
|
|
2729
2744
|
this.heartbeatInterval && (clearInterval(this.heartbeatInterval), this.heartbeatInterval = null), this.electionTimeout && (clearTimeout(this.electionTimeout), this.electionTimeout = null), this.cleanupTimeout && (clearTimeout(this.cleanupTimeout), this.cleanupTimeout = null), this.fallbackLeadershipTimeout && (clearTimeout(this.fallbackLeadershipTimeout), this.fallbackLeadershipTimeout = null), this.electionDelayTimeout && (clearTimeout(this.electionDelayTimeout), this.electionDelayTimeout = null), this.tabInfoCleanupTimeout && (clearTimeout(this.tabInfoCleanupTimeout), this.tabInfoCleanupTimeout = null), this.closingAnnouncementTimeout && (clearTimeout(this.closingAnnouncementTimeout), this.closingAnnouncementTimeout = null), this.leaderHealthCheckInterval && (clearInterval(this.leaderHealthCheckInterval), this.leaderHealthCheckInterval = null), this.endSession("manual_stop"), this.broadcastChannel && this.broadcastChannel.close();
|
|
2730
2745
|
}
|
|
2731
2746
|
}
|
|
2732
|
-
class
|
|
2747
|
+
class Pt extends p {
|
|
2733
2748
|
eventManager;
|
|
2734
2749
|
storageManager;
|
|
2735
2750
|
sessionStorageKey;
|
|
@@ -2771,16 +2786,16 @@ class Ht extends p {
|
|
|
2771
2786
|
const e = async () => {
|
|
2772
2787
|
if (this.crossTabSessionManager && this.crossTabSessionManager.updateSessionActivity(), !this.get("sessionId"))
|
|
2773
2788
|
try {
|
|
2774
|
-
const
|
|
2775
|
-
this.set("sessionId",
|
|
2776
|
-
sessionId:
|
|
2777
|
-
recovered:
|
|
2789
|
+
const n = await this.createOrJoinSession();
|
|
2790
|
+
this.set("sessionId", n.sessionId), i.info("SessionHandler", "🏁 Session started", {
|
|
2791
|
+
sessionId: n.sessionId,
|
|
2792
|
+
recovered: n.recovered,
|
|
2778
2793
|
crossTabActive: !!this.crossTabSessionManager
|
|
2779
|
-
}), this.trackSession(h.SESSION_START,
|
|
2780
|
-
} catch (
|
|
2794
|
+
}), this.trackSession(h.SESSION_START, n.recovered), this.persistSession(n.sessionId), this.startHeartbeat();
|
|
2795
|
+
} catch (n) {
|
|
2781
2796
|
i.error(
|
|
2782
2797
|
"SessionHandler",
|
|
2783
|
-
`Session creation failed: ${
|
|
2798
|
+
`Session creation failed: ${n instanceof Error ? n.message : "Unknown error"}`
|
|
2784
2799
|
), this.forceCleanupSession();
|
|
2785
2800
|
}
|
|
2786
2801
|
}, t = () => {
|
|
@@ -2789,17 +2804,17 @@ class Ht extends p {
|
|
|
2789
2804
|
(this.get("config")?.mode === "qa" || this.get("config")?.mode === "debug") && i.debug("SessionHandler", "Session kept alive by cross-tab activity");
|
|
2790
2805
|
return;
|
|
2791
2806
|
}
|
|
2792
|
-
this.sessionManager.endSessionManaged("inactivity").then((
|
|
2807
|
+
this.sessionManager.endSessionManaged("inactivity").then((n) => {
|
|
2793
2808
|
i.info("SessionHandler", "🛑 Session ended by inactivity", {
|
|
2794
2809
|
sessionId: this.get("sessionId"),
|
|
2795
|
-
reason:
|
|
2796
|
-
success:
|
|
2797
|
-
eventsFlushed:
|
|
2810
|
+
reason: n.reason,
|
|
2811
|
+
success: n.success,
|
|
2812
|
+
eventsFlushed: n.eventsFlushed
|
|
2798
2813
|
}), this.crossTabSessionManager && this.crossTabSessionManager.endSession("inactivity"), this.clearPersistedSession(), this.stopHeartbeat();
|
|
2799
|
-
}).catch((
|
|
2814
|
+
}).catch((n) => {
|
|
2800
2815
|
i.error(
|
|
2801
2816
|
"SessionHandler",
|
|
2802
|
-
`Session end failed: ${
|
|
2817
|
+
`Session end failed: ${n instanceof Error ? n.message : "Unknown error"}`
|
|
2803
2818
|
), this.forceCleanupSession();
|
|
2804
2819
|
});
|
|
2805
2820
|
}
|
|
@@ -2852,7 +2867,7 @@ class Ht extends p {
|
|
|
2852
2867
|
(this.get("config")?.mode === "qa" || this.get("config")?.mode === "debug") && i.warn("SessionHandler", "Cross-tab conflict detected"), this.sessionManager && this.sessionManager.trackSessionHealth("conflict");
|
|
2853
2868
|
}
|
|
2854
2869
|
};
|
|
2855
|
-
this._crossTabSessionManager = new
|
|
2870
|
+
this._crossTabSessionManager = new Ht(this.storageManager, e, t, l), i.debug("SessionHandler", "Cross-tab session manager initialized", { projectId: e });
|
|
2856
2871
|
}
|
|
2857
2872
|
async createOrJoinSession() {
|
|
2858
2873
|
if (this.crossTabSessionManager) {
|
|
@@ -2913,8 +2928,8 @@ class Ht extends p {
|
|
|
2913
2928
|
const e = this.storageManager.getItem(this.sessionStorageKey);
|
|
2914
2929
|
if (e)
|
|
2915
2930
|
try {
|
|
2916
|
-
const t = JSON.parse(e),
|
|
2917
|
-
if (
|
|
2931
|
+
const t = JSON.parse(e), n = Date.now() - t.lastHeartbeat, a = this.get("config")?.sessionTimeout ?? R;
|
|
2932
|
+
if (n > a) {
|
|
2918
2933
|
const o = this.recoveryManager?.hasRecoverableSession();
|
|
2919
2934
|
if (o && this.recoveryManager) {
|
|
2920
2935
|
const l = {
|
|
@@ -3029,17 +3044,17 @@ class xt extends p {
|
|
|
3029
3044
|
return;
|
|
3030
3045
|
}
|
|
3031
3046
|
i.debug("ClickHandler", "Starting click tracking"), this.clickHandler = (e) => {
|
|
3032
|
-
const t = e, s = t.target,
|
|
3033
|
-
if (!
|
|
3047
|
+
const t = e, s = t.target, n = s instanceof HTMLElement ? s : s instanceof Node && s.parentElement instanceof HTMLElement ? s.parentElement : null;
|
|
3048
|
+
if (!n) {
|
|
3034
3049
|
i.warn("ClickHandler", "Click target not found or not an element");
|
|
3035
3050
|
return;
|
|
3036
3051
|
}
|
|
3037
3052
|
i.info("ClickHandler", "🖱️ Click detected on element", {
|
|
3038
|
-
tagName:
|
|
3039
|
-
className:
|
|
3040
|
-
textContent:
|
|
3053
|
+
tagName: n.tagName,
|
|
3054
|
+
className: n.className || "none",
|
|
3055
|
+
textContent: n.textContent?.slice(0, 50) ?? "empty"
|
|
3041
3056
|
});
|
|
3042
|
-
const a = this.findTrackingElement(
|
|
3057
|
+
const a = this.findTrackingElement(n), o = this.getRelevantClickElement(n), l = this.calculateClickCoordinates(t, n);
|
|
3043
3058
|
if (a) {
|
|
3044
3059
|
const d = this.extractTrackingData(a);
|
|
3045
3060
|
if (d) {
|
|
@@ -3053,7 +3068,7 @@ class xt extends p {
|
|
|
3053
3068
|
});
|
|
3054
3069
|
}
|
|
3055
3070
|
}
|
|
3056
|
-
const c = this.generateClickData(
|
|
3071
|
+
const c = this.generateClickData(n, o, l);
|
|
3057
3072
|
this.eventManager.track({
|
|
3058
3073
|
type: h.CLICK,
|
|
3059
3074
|
click_data: c
|
|
@@ -3093,8 +3108,8 @@ class xt extends p {
|
|
|
3093
3108
|
return e;
|
|
3094
3109
|
}
|
|
3095
3110
|
calculateClickCoordinates(e, t) {
|
|
3096
|
-
const s = t.getBoundingClientRect(),
|
|
3097
|
-
return { x:
|
|
3111
|
+
const s = t.getBoundingClientRect(), n = e.clientX, a = e.clientY, o = s.width > 0 ? Math.max(0, Math.min(1, Number(((n - s.left) / s.width).toFixed(3)))) : 0, l = s.height > 0 ? Math.max(0, Math.min(1, Number(((a - s.top) / s.height).toFixed(3)))) : 0;
|
|
3112
|
+
return { x: n, y: a, relativeX: o, relativeY: l };
|
|
3098
3113
|
}
|
|
3099
3114
|
extractTrackingData(e) {
|
|
3100
3115
|
const t = e.getAttribute(`${z}-name`), s = e.getAttribute(`${z}-value`);
|
|
@@ -3106,9 +3121,9 @@ class xt extends p {
|
|
|
3106
3121
|
};
|
|
3107
3122
|
}
|
|
3108
3123
|
generateClickData(e, t, s) {
|
|
3109
|
-
const { x:
|
|
3124
|
+
const { x: n, y: a, relativeX: o, relativeY: l } = s, c = this.getRelevantText(e, t), d = this.extractElementAttributes(t), u = t.getAttribute("href"), g = t.getAttribute("title"), y = t.getAttribute("alt"), I = t.getAttribute("role"), A = t.getAttribute("aria-label"), U = typeof t.className == "string" ? t.className : String(t.className);
|
|
3110
3125
|
return {
|
|
3111
|
-
x:
|
|
3126
|
+
x: n,
|
|
3112
3127
|
y: a,
|
|
3113
3128
|
relativeX: o,
|
|
3114
3129
|
relativeY: l,
|
|
@@ -3125,19 +3140,19 @@ class xt extends p {
|
|
|
3125
3140
|
};
|
|
3126
3141
|
}
|
|
3127
3142
|
getRelevantText(e, t) {
|
|
3128
|
-
const s = ["main", "section", "article", "body", "html", "header", "footer", "aside", "nav"],
|
|
3129
|
-
if (!
|
|
3143
|
+
const s = ["main", "section", "article", "body", "html", "header", "footer", "aside", "nav"], n = e.textContent?.trim() ?? "", a = t.textContent?.trim() ?? "";
|
|
3144
|
+
if (!n && !a)
|
|
3130
3145
|
return "";
|
|
3131
|
-
if (
|
|
3132
|
-
return
|
|
3146
|
+
if (n && n.length <= _)
|
|
3147
|
+
return n;
|
|
3133
3148
|
const o = s.includes(t.tagName.toLowerCase()), l = a.length > _ * 2;
|
|
3134
|
-
return o && l ?
|
|
3149
|
+
return o && l ? n && n.length <= _ ? n : "" : a.length <= _ ? a : n && n.length < a.length * 0.1 ? n.length <= _ ? n : n.slice(0, _ - 3) + "..." : a.slice(0, _ - 3) + "...";
|
|
3135
3150
|
}
|
|
3136
3151
|
extractElementAttributes(e) {
|
|
3137
3152
|
const t = ["id", "class", "data-testid", "aria-label", "title", "href", "type", "name"], s = {};
|
|
3138
|
-
for (const
|
|
3139
|
-
const a = e.getAttribute(
|
|
3140
|
-
a && (s[
|
|
3153
|
+
for (const n of t) {
|
|
3154
|
+
const a = e.getAttribute(n);
|
|
3155
|
+
a && (s[n] = a);
|
|
3141
3156
|
}
|
|
3142
3157
|
return s;
|
|
3143
3158
|
}
|
|
@@ -3157,10 +3172,10 @@ class Ot extends p {
|
|
|
3157
3172
|
startTracking() {
|
|
3158
3173
|
const e = this.get("config").scrollContainerSelectors, t = Array.isArray(e) ? e : typeof e == "string" ? [e] : [];
|
|
3159
3174
|
i.debug("ScrollHandler", "Starting scroll tracking", { selectorsCount: t.length });
|
|
3160
|
-
const s = t.map((
|
|
3175
|
+
const s = t.map((n) => this.safeQuerySelector(n)).filter((n) => n instanceof HTMLElement);
|
|
3161
3176
|
s.length === 0 && s.push(window);
|
|
3162
|
-
for (const
|
|
3163
|
-
this.setupScrollContainer(
|
|
3177
|
+
for (const n of s)
|
|
3178
|
+
this.setupScrollContainer(n);
|
|
3164
3179
|
}
|
|
3165
3180
|
stopTracking() {
|
|
3166
3181
|
i.debug("ScrollHandler", "Stopping scroll tracking", { containersCount: this.containers.length });
|
|
@@ -3183,21 +3198,21 @@ class Ot extends p {
|
|
|
3183
3198
|
return;
|
|
3184
3199
|
}
|
|
3185
3200
|
t.debounceTimer && clearTimeout(t.debounceTimer), t.debounceTimer = window.setTimeout(() => {
|
|
3186
|
-
const
|
|
3187
|
-
|
|
3201
|
+
const n = this.calculateScrollData(t);
|
|
3202
|
+
n && this.eventManager.track({
|
|
3188
3203
|
type: h.SCROLL,
|
|
3189
|
-
scroll_data:
|
|
3204
|
+
scroll_data: n
|
|
3190
3205
|
}), t.debounceTimer = null;
|
|
3191
3206
|
}, Me);
|
|
3192
3207
|
};
|
|
3193
3208
|
t.listener = s, this.containers.push(t), e instanceof Window ? window.addEventListener("scroll", s, { passive: !0 }) : e.addEventListener("scroll", s, { passive: !0 });
|
|
3194
3209
|
}
|
|
3195
3210
|
calculateScrollData(e) {
|
|
3196
|
-
const { element: t, lastScrollPos: s } = e,
|
|
3211
|
+
const { element: t, lastScrollPos: s } = e, n = this.getScrollTop(t), a = this.getViewportHeight(t), o = this.getScrollHeight(t);
|
|
3197
3212
|
if (t === window && o <= a)
|
|
3198
3213
|
return null;
|
|
3199
|
-
const l =
|
|
3200
|
-
return Math.abs(
|
|
3214
|
+
const l = n > s ? j.DOWN : j.UP, c = o > a ? Math.min(100, Math.max(0, Math.floor(n / (o - a) * 100))) : 0;
|
|
3215
|
+
return Math.abs(n - s) < Ue ? null : (e.lastScrollPos = n, { depth: c, direction: l });
|
|
3201
3216
|
}
|
|
3202
3217
|
getScrollTop(e) {
|
|
3203
3218
|
return e instanceof Window ? window.scrollY : e.scrollTop;
|
|
@@ -3209,8 +3224,8 @@ class Ot extends p {
|
|
|
3209
3224
|
return e instanceof Window ? document.documentElement.scrollHeight : e.scrollHeight;
|
|
3210
3225
|
}
|
|
3211
3226
|
isElementScrollable(e) {
|
|
3212
|
-
const t = getComputedStyle(e), s = t.overflowY === "auto" || t.overflowY === "scroll" || t.overflowX === "auto" || t.overflowX === "scroll" || t.overflow === "auto" || t.overflow === "scroll",
|
|
3213
|
-
return s &&
|
|
3227
|
+
const t = getComputedStyle(e), s = t.overflowY === "auto" || t.overflowY === "scroll" || t.overflowX === "auto" || t.overflowX === "scroll" || t.overflow === "auto" || t.overflow === "scroll", n = e.scrollHeight > e.clientHeight || e.scrollWidth > e.clientWidth;
|
|
3228
|
+
return s && n;
|
|
3214
3229
|
}
|
|
3215
3230
|
safeQuerySelector(e) {
|
|
3216
3231
|
try {
|
|
@@ -3308,19 +3323,19 @@ class Ft extends p {
|
|
|
3308
3323
|
async loadScript(e) {
|
|
3309
3324
|
return new Promise((t, s) => {
|
|
3310
3325
|
try {
|
|
3311
|
-
const
|
|
3312
|
-
|
|
3326
|
+
const n = document.createElement("script");
|
|
3327
|
+
n.id = "tracelog-ga-script", n.async = !0, n.src = `https://www.googletagmanager.com/gtag/js?id=${e}`, n.onload = () => {
|
|
3313
3328
|
t();
|
|
3314
|
-
},
|
|
3329
|
+
}, n.onerror = () => {
|
|
3315
3330
|
const a = new Error("Failed to load Google Analytics script");
|
|
3316
3331
|
i.error("GoogleAnalytics", "Google Analytics script load failed", {
|
|
3317
3332
|
measurementId: e,
|
|
3318
3333
|
error: a.message,
|
|
3319
|
-
scriptSrc:
|
|
3334
|
+
scriptSrc: n.src
|
|
3320
3335
|
}), s(a);
|
|
3321
|
-
}, document.head.appendChild(
|
|
3322
|
-
} catch (
|
|
3323
|
-
const a =
|
|
3336
|
+
}, document.head.appendChild(n);
|
|
3337
|
+
} catch (n) {
|
|
3338
|
+
const a = n instanceof Error ? n : new Error(String(n));
|
|
3324
3339
|
i.error("GoogleAnalytics", "Error creating Google Analytics script", {
|
|
3325
3340
|
measurementId: e,
|
|
3326
3341
|
error: a.message
|
|
@@ -3433,8 +3448,8 @@ class Vt extends p {
|
|
|
3433
3448
|
this.reportTTFB(), this.safeObserve(
|
|
3434
3449
|
"largest-contentful-paint",
|
|
3435
3450
|
(t) => {
|
|
3436
|
-
const s = t.getEntries(),
|
|
3437
|
-
|
|
3451
|
+
const s = t.getEntries(), n = s[s.length - 1];
|
|
3452
|
+
n && this.sendVital({ type: "LCP", value: Number(n.startTime.toFixed(N)) });
|
|
3438
3453
|
},
|
|
3439
3454
|
{ type: "largest-contentful-paint", buffered: !0 },
|
|
3440
3455
|
!0
|
|
@@ -3444,13 +3459,13 @@ class Vt extends p {
|
|
|
3444
3459
|
"layout-shift",
|
|
3445
3460
|
(t) => {
|
|
3446
3461
|
const s = t.getEntries();
|
|
3447
|
-
for (const
|
|
3448
|
-
if (
|
|
3462
|
+
for (const n of s) {
|
|
3463
|
+
if (n.hadRecentInput === !0)
|
|
3449
3464
|
continue;
|
|
3450
|
-
const a = typeof
|
|
3465
|
+
const a = typeof n.value == "number" ? n.value : 0;
|
|
3451
3466
|
e += a;
|
|
3452
3467
|
}
|
|
3453
|
-
this.sendVital({ type: "CLS", value: Number(e.toFixed(
|
|
3468
|
+
this.sendVital({ type: "CLS", value: Number(e.toFixed(He)) });
|
|
3454
3469
|
},
|
|
3455
3470
|
{ type: "layout-shift", buffered: !0 }
|
|
3456
3471
|
), this.safeObserve(
|
|
@@ -3465,8 +3480,8 @@ class Vt extends p {
|
|
|
3465
3480
|
"event",
|
|
3466
3481
|
(t) => {
|
|
3467
3482
|
let s = 0;
|
|
3468
|
-
const
|
|
3469
|
-
for (const a of
|
|
3483
|
+
const n = t.getEntries();
|
|
3484
|
+
for (const a of n) {
|
|
3470
3485
|
const o = (a.processingEnd ?? 0) - (a.startTime ?? 0);
|
|
3471
3486
|
s = Math.max(s, o);
|
|
3472
3487
|
}
|
|
@@ -3477,11 +3492,11 @@ class Vt extends p {
|
|
|
3477
3492
|
}
|
|
3478
3493
|
async initWebVitals() {
|
|
3479
3494
|
try {
|
|
3480
|
-
const { onLCP: e, onCLS: t, onFCP: s, onTTFB:
|
|
3495
|
+
const { onLCP: e, onCLS: t, onFCP: s, onTTFB: n, onINP: a } = await import("./web-vitals-CCnqwnC8.mjs"), o = (l) => (c) => {
|
|
3481
3496
|
const d = Number(c.value.toFixed(N));
|
|
3482
3497
|
this.sendVital({ type: l, value: d });
|
|
3483
3498
|
};
|
|
3484
|
-
e(o("LCP")), t(o("CLS")), s(o("FCP")),
|
|
3499
|
+
e(o("LCP")), t(o("CLS")), s(o("FCP")), n(o("TTFB")), a(o("INP"));
|
|
3485
3500
|
} catch (e) {
|
|
3486
3501
|
i.warn("PerformanceHandler", "Failed to load web-vitals library, using fallback", {
|
|
3487
3502
|
error: e instanceof Error ? e.message : "Unknown error"
|
|
@@ -3509,8 +3524,8 @@ class Vt extends p {
|
|
|
3509
3524
|
(e) => {
|
|
3510
3525
|
const t = e.getEntries();
|
|
3511
3526
|
for (const s of t) {
|
|
3512
|
-
const
|
|
3513
|
-
a - this.lastLongTaskSentAt >=
|
|
3527
|
+
const n = Number(s.duration.toFixed(N)), a = Date.now();
|
|
3528
|
+
a - this.lastLongTaskSentAt >= qe && (this.trackWebVital("LONG_TASK", n), this.lastLongTaskSentAt = a);
|
|
3514
3529
|
}
|
|
3515
3530
|
},
|
|
3516
3531
|
{ type: "longtask", buffered: !0 }
|
|
@@ -3520,10 +3535,10 @@ class Vt extends p {
|
|
|
3520
3535
|
const t = this.getNavigationId(), s = `${e.type}`;
|
|
3521
3536
|
if (t) {
|
|
3522
3537
|
this.reportedByNav.has(t) || this.reportedByNav.set(t, /* @__PURE__ */ new Set());
|
|
3523
|
-
const
|
|
3524
|
-
if (
|
|
3538
|
+
const n = this.reportedByNav.get(t);
|
|
3539
|
+
if (n.has(s))
|
|
3525
3540
|
return;
|
|
3526
|
-
|
|
3541
|
+
n.add(s);
|
|
3527
3542
|
}
|
|
3528
3543
|
this.trackWebVital(e.type, e.value);
|
|
3529
3544
|
}
|
|
@@ -3550,19 +3565,19 @@ class Vt extends p {
|
|
|
3550
3565
|
}), null;
|
|
3551
3566
|
}
|
|
3552
3567
|
}
|
|
3553
|
-
safeObserve(e, t, s,
|
|
3568
|
+
safeObserve(e, t, s, n = !1) {
|
|
3554
3569
|
try {
|
|
3555
3570
|
if (typeof PerformanceObserver > "u") return;
|
|
3556
3571
|
const a = PerformanceObserver.supportedEntryTypes;
|
|
3557
3572
|
if (a && !a.includes(e)) return;
|
|
3558
3573
|
const o = new PerformanceObserver((l, c) => {
|
|
3559
|
-
if (t(l, c),
|
|
3574
|
+
if (t(l, c), n)
|
|
3560
3575
|
try {
|
|
3561
3576
|
c.disconnect();
|
|
3562
3577
|
} catch {
|
|
3563
3578
|
}
|
|
3564
3579
|
});
|
|
3565
|
-
o.observe(s ?? { type: e, buffered: !0 }),
|
|
3580
|
+
o.observe(s ?? { type: e, buffered: !0 }), n || this.observers.push(o);
|
|
3566
3581
|
} catch (a) {
|
|
3567
3582
|
i.warn("PerformanceHandler", "Failed to create performance observer", {
|
|
3568
3583
|
type: e,
|
|
@@ -3664,17 +3679,17 @@ class jt extends p {
|
|
|
3664
3679
|
}
|
|
3665
3680
|
interceptFetch() {
|
|
3666
3681
|
window.fetch = async (e, t) => {
|
|
3667
|
-
const s = Date.now(),
|
|
3682
|
+
const s = Date.now(), n = typeof e == "string" ? e : e.toString(), a = t?.method ?? "GET";
|
|
3668
3683
|
try {
|
|
3669
3684
|
const o = await this.originalFetch(e, t), l = Date.now() - s;
|
|
3670
3685
|
return o.ok || (i.debug("NetworkHandler", "Fetch error detected", {
|
|
3671
3686
|
method: a,
|
|
3672
|
-
url: this.normalizeUrlForTracking(
|
|
3687
|
+
url: this.normalizeUrlForTracking(n),
|
|
3673
3688
|
status: o.status,
|
|
3674
3689
|
statusText: o.statusText
|
|
3675
3690
|
}), this.trackNetworkError(
|
|
3676
3691
|
a.toUpperCase(),
|
|
3677
|
-
this.normalizeUrlForTracking(
|
|
3692
|
+
this.normalizeUrlForTracking(n),
|
|
3678
3693
|
o.status,
|
|
3679
3694
|
o.statusText,
|
|
3680
3695
|
l
|
|
@@ -3683,11 +3698,11 @@ class jt extends p {
|
|
|
3683
3698
|
const l = Date.now() - s, c = o instanceof Error ? o.message : "Network Error";
|
|
3684
3699
|
throw i.debug("NetworkHandler", "Fetch exception caught", {
|
|
3685
3700
|
method: a,
|
|
3686
|
-
url: this.normalizeUrlForTracking(
|
|
3701
|
+
url: this.normalizeUrlForTracking(n),
|
|
3687
3702
|
error: c
|
|
3688
3703
|
}), this.trackNetworkError(
|
|
3689
3704
|
a.toUpperCase(),
|
|
3690
|
-
this.normalizeUrlForTracking(
|
|
3705
|
+
this.normalizeUrlForTracking(n),
|
|
3691
3706
|
void 0,
|
|
3692
3707
|
c,
|
|
3693
3708
|
l
|
|
@@ -3696,7 +3711,7 @@ class jt extends p {
|
|
|
3696
3711
|
};
|
|
3697
3712
|
}
|
|
3698
3713
|
interceptXHR() {
|
|
3699
|
-
const e = this.trackNetworkError.bind(this), t = this.normalizeUrlForTracking.bind(this), s = this.originalXHROpen,
|
|
3714
|
+
const e = this.trackNetworkError.bind(this), t = this.normalizeUrlForTracking.bind(this), s = this.originalXHROpen, n = this.originalXHRSend;
|
|
3700
3715
|
XMLHttpRequest.prototype.open = function(a, o, l, c, d) {
|
|
3701
3716
|
const u = l ?? !0, g = this;
|
|
3702
3717
|
return g._tracelogStartTime = Date.now(), g._tracelogMethod = a.toUpperCase(), g._tracelogUrl = o.toString(), s.call(this, a, o, u, c, d);
|
|
@@ -3717,10 +3732,10 @@ class jt extends p {
|
|
|
3717
3732
|
}
|
|
3718
3733
|
if (u)
|
|
3719
3734
|
return u.call(o, g);
|
|
3720
|
-
},
|
|
3735
|
+
}, n.call(this, a);
|
|
3721
3736
|
};
|
|
3722
3737
|
}
|
|
3723
|
-
trackNetworkError(e, t, s,
|
|
3738
|
+
trackNetworkError(e, t, s, n, a) {
|
|
3724
3739
|
const o = this.get("config");
|
|
3725
3740
|
if (!this.shouldSample(o?.errorSampling ?? 0.1)) {
|
|
3726
3741
|
i.debug(
|
|
@@ -3736,17 +3751,17 @@ class jt extends p {
|
|
|
3736
3751
|
}
|
|
3737
3752
|
i.warn(
|
|
3738
3753
|
"NetworkHandler",
|
|
3739
|
-
`Network error tracked: ${e} ${t} (status: ${s}, statusText: ${
|
|
3740
|
-
{ method: e, url: t, status: s, statusText:
|
|
3754
|
+
`Network error tracked: ${e} ${t} (status: ${s}, statusText: ${n}, duration: ${a}ms)`,
|
|
3755
|
+
{ method: e, url: t, status: s, statusText: n, duration: a }
|
|
3741
3756
|
), this.eventManager.track({
|
|
3742
3757
|
type: h.ERROR,
|
|
3743
3758
|
error_data: {
|
|
3744
3759
|
type: D.NETWORK_ERROR,
|
|
3745
|
-
message:
|
|
3760
|
+
message: n,
|
|
3746
3761
|
method: e,
|
|
3747
3762
|
url: t,
|
|
3748
3763
|
status: s,
|
|
3749
|
-
statusText:
|
|
3764
|
+
statusText: n,
|
|
3750
3765
|
duration: a
|
|
3751
3766
|
}
|
|
3752
3767
|
});
|
|
@@ -3815,7 +3830,7 @@ class Gt extends p {
|
|
|
3815
3830
|
i.warn("App", "Custom event attempted before eventManager initialization", { eventName: e });
|
|
3816
3831
|
return;
|
|
3817
3832
|
}
|
|
3818
|
-
const { valid: s, error:
|
|
3833
|
+
const { valid: s, error: n, sanitizedMetadata: a } = vt(e, t);
|
|
3819
3834
|
if (s)
|
|
3820
3835
|
i.debug("App", "Custom event validated and queued", { eventName: e, hasMetadata: !!a }), this.eventManager.track({
|
|
3821
3836
|
type: h.CUSTOM,
|
|
@@ -3826,14 +3841,14 @@ class Gt extends p {
|
|
|
3826
3841
|
});
|
|
3827
3842
|
else {
|
|
3828
3843
|
const o = this.get("config")?.mode;
|
|
3829
|
-
if (i.clientError("App", `Custom event validation failed: ${
|
|
3844
|
+
if (i.clientError("App", `Custom event validation failed: ${n ?? "unknown error"}`, {
|
|
3830
3845
|
eventName: e,
|
|
3831
|
-
validationError:
|
|
3846
|
+
validationError: n,
|
|
3832
3847
|
hasMetadata: !!t,
|
|
3833
3848
|
mode: o
|
|
3834
3849
|
}), o === "qa" || o === "debug")
|
|
3835
3850
|
throw new Error(
|
|
3836
|
-
`custom event "${e}" validation failed (${
|
|
3851
|
+
`custom event "${e}" validation failed (${n ?? "unknown error"}). Please, review your event data and try again.`
|
|
3837
3852
|
);
|
|
3838
3853
|
}
|
|
3839
3854
|
}
|
|
@@ -3889,7 +3904,7 @@ class Gt extends p {
|
|
|
3889
3904
|
initSessionHandler() {
|
|
3890
3905
|
if (!this.storageManager || !this.eventManager)
|
|
3891
3906
|
throw new Error("StorageManager and EventManager must be initialized before SessionHandler");
|
|
3892
|
-
this.sessionHandler = new
|
|
3907
|
+
this.sessionHandler = new Pt(this.storageManager, this.eventManager), this.sessionHandler.startTracking();
|
|
3893
3908
|
}
|
|
3894
3909
|
initPageViewHandler() {
|
|
3895
3910
|
if (!this.eventManager)
|
|
@@ -3938,14 +3953,14 @@ const Qt = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
|
|
|
3938
3953
|
TagConditionOperator: f,
|
|
3939
3954
|
TagConditionType: m,
|
|
3940
3955
|
TagLogicalOperator: G
|
|
3941
|
-
}, Symbol.toStringTag, { value: "Module" })),
|
|
3956
|
+
}, Symbol.toStringTag, { value: "Module" })), qt = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
|
|
3942
3957
|
__proto__: null,
|
|
3943
3958
|
DEFAULT_SESSION_TIMEOUT_MS: R
|
|
3944
3959
|
}, Symbol.toStringTag, { value: "Module" }));
|
|
3945
3960
|
let v = null, T = !1;
|
|
3946
|
-
const
|
|
3961
|
+
const Bt = async (r) => {
|
|
3947
3962
|
try {
|
|
3948
|
-
if (i.info("API", "Library initialization started", { id:
|
|
3963
|
+
if (i.info("API", "Library initialization started", { id: r.id }), typeof window > "u" || typeof document > "u")
|
|
3949
3964
|
throw i.clientError(
|
|
3950
3965
|
"API",
|
|
3951
3966
|
"Browser environment required - this library can only be used in a browser environment",
|
|
@@ -3956,32 +3971,32 @@ const qt = async (n) => {
|
|
|
3956
3971
|
), new Error("This library can only be used in a browser environment");
|
|
3957
3972
|
if (v) {
|
|
3958
3973
|
i.debug("API", "Library already initialized, skipping duplicate initialization", {
|
|
3959
|
-
projectId:
|
|
3974
|
+
projectId: r.id
|
|
3960
3975
|
});
|
|
3961
3976
|
return;
|
|
3962
3977
|
}
|
|
3963
3978
|
if (T) {
|
|
3964
|
-
i.debug("API", "Concurrent initialization detected, waiting for completion", { projectId:
|
|
3979
|
+
i.debug("API", "Concurrent initialization detected, waiting for completion", { projectId: r.id });
|
|
3965
3980
|
let s = 0;
|
|
3966
|
-
const
|
|
3967
|
-
for (; T && s <
|
|
3981
|
+
const n = me.MAX_CONCURRENT_RETRIES, a = me.CONCURRENT_RETRY_DELAY_MS;
|
|
3982
|
+
for (; T && s < n; )
|
|
3968
3983
|
await new Promise((o) => setTimeout(o, a)), s++;
|
|
3969
3984
|
if (v) {
|
|
3970
3985
|
i.debug("API", "Concurrent initialization completed successfully", {
|
|
3971
|
-
projectId:
|
|
3986
|
+
projectId: r.id,
|
|
3972
3987
|
retriesUsed: s
|
|
3973
3988
|
});
|
|
3974
3989
|
return;
|
|
3975
3990
|
}
|
|
3976
3991
|
if (T)
|
|
3977
3992
|
throw i.error("API", "Initialization timeout - concurrent initialization took too long", {
|
|
3978
|
-
projectId:
|
|
3993
|
+
projectId: r.id,
|
|
3979
3994
|
retriesUsed: s,
|
|
3980
|
-
maxRetries:
|
|
3995
|
+
maxRetries: n
|
|
3981
3996
|
}), new Error("App initialization timeout - concurrent initialization took too long");
|
|
3982
3997
|
}
|
|
3983
|
-
T = !0, i.debug("API", "Validating and normalizing configuration", { projectId:
|
|
3984
|
-
const e = dt(
|
|
3998
|
+
T = !0, i.debug("API", "Validating and normalizing configuration", { projectId: r.id });
|
|
3999
|
+
const e = dt(r);
|
|
3985
4000
|
i.debug("API", "Creating App instance", { projectId: e.id });
|
|
3986
4001
|
const t = new Gt();
|
|
3987
4002
|
await t.init(e), v = t, i.info("API", "Library initialization completed successfully", {
|
|
@@ -3998,20 +4013,20 @@ const qt = async (n) => {
|
|
|
3998
4013
|
} finally {
|
|
3999
4014
|
T = !1;
|
|
4000
4015
|
}
|
|
4001
|
-
}, Wt = (
|
|
4016
|
+
}, Wt = (r, e) => {
|
|
4002
4017
|
try {
|
|
4003
4018
|
if (!v)
|
|
4004
4019
|
throw i.clientError("API", "Custom event failed - Library not initialized. Please call TraceLog.init() first", {
|
|
4005
|
-
eventName:
|
|
4020
|
+
eventName: r,
|
|
4006
4021
|
hasMetadata: !!e
|
|
4007
4022
|
}), new Error("App not initialized");
|
|
4008
4023
|
i.debug("API", "Sending custom event", {
|
|
4009
|
-
eventName:
|
|
4024
|
+
eventName: r,
|
|
4010
4025
|
hasMetadata: !!e,
|
|
4011
4026
|
metadataKeys: e ? Object.keys(e) : []
|
|
4012
|
-
}), v.sendCustomEvent(
|
|
4027
|
+
}), v.sendCustomEvent(r, e);
|
|
4013
4028
|
} catch (t) {
|
|
4014
|
-
if (i.error("API", "Event tracking failed", { eventName:
|
|
4029
|
+
if (i.error("API", "Event tracking failed", { eventName: r, error: t, hasMetadata: !!e }), t instanceof Error && (t.message === "App not initialized" || t.message.includes("validation failed")))
|
|
4015
4030
|
throw t;
|
|
4016
4031
|
}
|
|
4017
4032
|
}, Xt = () => v !== null, Kt = () => ({
|
|
@@ -4023,17 +4038,17 @@ const qt = async (n) => {
|
|
|
4023
4038
|
if (i.info("API", "Library cleanup initiated"), !v)
|
|
4024
4039
|
throw i.warn("API", "Cleanup called but Library was not initialized"), new Error("App not initialized");
|
|
4025
4040
|
v.destroy(), v = null, T = !1, i.info("API", "Library cleanup completed successfully");
|
|
4026
|
-
} catch (
|
|
4027
|
-
i.error("API", "Cleanup failed", { error:
|
|
4041
|
+
} catch (r) {
|
|
4042
|
+
i.error("API", "Cleanup failed", { error: r, hadApp: !!v, wasInitializing: T });
|
|
4028
4043
|
}
|
|
4029
4044
|
}, Jt = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
|
|
4030
4045
|
__proto__: null,
|
|
4031
|
-
Constants:
|
|
4046
|
+
Constants: qt,
|
|
4032
4047
|
Types: Qt,
|
|
4033
4048
|
destroy: Yt,
|
|
4034
4049
|
event: Wt,
|
|
4035
4050
|
getInitializationStatus: Kt,
|
|
4036
|
-
init:
|
|
4051
|
+
init: Bt,
|
|
4037
4052
|
isInitialized: Xt
|
|
4038
4053
|
}, Symbol.toStringTag, { value: "Module" }));
|
|
4039
4054
|
export {
|