@tracelog/lib 0.0.4 → 0.0.5
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,4 +1,4 @@
|
|
|
1
|
-
var E = /* @__PURE__ */ ((
|
|
1
|
+
var E = /* @__PURE__ */ ((r) => (r.Mobile = "mobile", r.Tablet = "tablet", r.Desktop = "desktop", r.Unknown = "unknown", r))(E || {});
|
|
2
2
|
const q = {};
|
|
3
3
|
class p {
|
|
4
4
|
get(e) {
|
|
@@ -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
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, Pe = 4, He = 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, Be = Te, qe = 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);
|
|
@@ -310,47 +310,47 @@ 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 H("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
|
|
331
|
+
provided: r.globalMetadata,
|
|
332
|
+
type: typeof r.globalMetadata
|
|
333
333
|
}), new H(w.INVALID_GLOBAL_METADATA, "config");
|
|
334
|
-
if (
|
|
335
|
-
if (!Array.isArray(
|
|
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
|
|
337
|
+
provided: r.sensitiveQueryParams,
|
|
338
|
+
type: typeof r.sensitiveQueryParams
|
|
339
339
|
}), new H(w.INVALID_SENSITIVE_QUERY_PARAMS, "config");
|
|
340
|
-
for (const e of
|
|
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
345
|
}), new H("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", {
|
|
@@ -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
|
-
}, B = (
|
|
430
|
+
}, B = (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) => B(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
|
});
|
|
@@ -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);
|
|
@@ -501,11 +501,11 @@ const ot = (n) => {
|
|
|
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 = B(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,20 @@ class wt extends p {
|
|
|
858
858
|
try {
|
|
859
859
|
return (await fetch(t, {
|
|
860
860
|
method: "POST",
|
|
861
|
+
mode: "cors",
|
|
862
|
+
credentials: "omit",
|
|
861
863
|
headers: {
|
|
862
864
|
"Content-Type": "application/json"
|
|
863
865
|
},
|
|
864
866
|
body: s
|
|
865
867
|
})).ok;
|
|
866
|
-
} catch (
|
|
867
|
-
|
|
868
|
+
} catch (n) {
|
|
869
|
+
const a = n instanceof Error ? n.message : String(n), o = a.includes("CORS") || a.includes("NotSameOrigin") || a.includes("blocked");
|
|
870
|
+
return i.error("SenderManager", "Failed to send events async", {
|
|
871
|
+
error: a,
|
|
872
|
+
isCorsError: o,
|
|
873
|
+
url: t.replace(/\/\/[^/]+/, "//[DOMAIN]")
|
|
874
|
+
}), !1;
|
|
868
875
|
}
|
|
869
876
|
}
|
|
870
877
|
sendQueueSync(e) {
|
|
@@ -878,16 +885,22 @@ class wt extends p {
|
|
|
878
885
|
return navigator.sendBeacon(t, s);
|
|
879
886
|
}
|
|
880
887
|
sendSyncXHR(e, t) {
|
|
888
|
+
const s = new XMLHttpRequest();
|
|
881
889
|
try {
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
return i.error("SenderManager", "Sync XHR failed", {
|
|
890
|
+
return s.open("POST", e, !1), s.setRequestHeader("Content-Type", "application/json"), s.withCredentials = !1, s.timeout = xe, s.send(t), s.status >= 200 && s.status < 300;
|
|
891
|
+
} catch (n) {
|
|
892
|
+
const a = n instanceof Error ? n.message : String(n), o = a.includes("CORS") || a.includes("NotSameOrigin") || a.includes("blocked");
|
|
893
|
+
return i.error("SenderManager", "Sync XHR failed", {
|
|
894
|
+
error: a,
|
|
895
|
+
isCorsError: o,
|
|
896
|
+
status: s.status ?? "unknown",
|
|
897
|
+
url: e.replace(/\/\/[^/]+/, "//[DOMAIN]")
|
|
898
|
+
}), !1;
|
|
886
899
|
}
|
|
887
900
|
}
|
|
888
901
|
prepareRequest(e) {
|
|
889
902
|
return {
|
|
890
|
-
url: this.get("config").id === C.HttpLocal ? window.location.origin : this.get("apiUrl")
|
|
903
|
+
url: `${this.get("config").id === C.HttpLocal ? window.location.origin : this.get("apiUrl")}/collect`,
|
|
891
904
|
payload: JSON.stringify(e)
|
|
892
905
|
};
|
|
893
906
|
}
|
|
@@ -1018,14 +1031,14 @@ class It extends p {
|
|
|
1018
1031
|
const t = e === "LONG_TASK", s = t ? De : He;
|
|
1019
1032
|
if (s >= 1) return !0;
|
|
1020
1033
|
if (s <= 0) return !1;
|
|
1021
|
-
const
|
|
1022
|
-
return this.getHash(
|
|
1034
|
+
const n = `${this.get("userId")}|${t ? "long_task" : "web_vitals"}`;
|
|
1035
|
+
return this.getHash(n) % 100 / 100 < s;
|
|
1023
1036
|
}
|
|
1024
1037
|
getHash(e) {
|
|
1025
1038
|
let t = 0;
|
|
1026
1039
|
for (let s = 0; s < e.length; s++) {
|
|
1027
|
-
const
|
|
1028
|
-
t = (t << 5) - t +
|
|
1040
|
+
const n = e.charCodeAt(s);
|
|
1041
|
+
t = (t << 5) - t + n, t |= 0;
|
|
1029
1042
|
}
|
|
1030
1043
|
return Math.abs(t);
|
|
1031
1044
|
}
|
|
@@ -1045,7 +1058,7 @@ class Tt extends p {
|
|
|
1045
1058
|
const s = this.get("config")?.tags?.filter((a) => a.triggerType === h.PAGE_VIEW) ?? [];
|
|
1046
1059
|
if (s.length === 0)
|
|
1047
1060
|
return [];
|
|
1048
|
-
const
|
|
1061
|
+
const n = [];
|
|
1049
1062
|
for (const a of s) {
|
|
1050
1063
|
const { id: o, logicalOperator: l, conditions: c } = a, d = [];
|
|
1051
1064
|
for (const g of c)
|
|
@@ -1072,15 +1085,15 @@ class Tt extends p {
|
|
|
1072
1085
|
}
|
|
1073
1086
|
}
|
|
1074
1087
|
let u = !1;
|
|
1075
|
-
u = l === G.AND ? d.every(Boolean) : d.some(Boolean), u &&
|
|
1088
|
+
u = l === G.AND ? d.every(Boolean) : d.some(Boolean), u && n.push(o);
|
|
1076
1089
|
}
|
|
1077
|
-
return
|
|
1090
|
+
return n;
|
|
1078
1091
|
}
|
|
1079
1092
|
checkEventTypeClick(e, t) {
|
|
1080
1093
|
const s = this.get("config")?.tags?.filter((a) => a.triggerType === h.CLICK) ?? [];
|
|
1081
1094
|
if (s.length === 0)
|
|
1082
1095
|
return [];
|
|
1083
|
-
const
|
|
1096
|
+
const n = [];
|
|
1084
1097
|
for (const a of s) {
|
|
1085
1098
|
const { id: o, logicalOperator: l, conditions: c } = a, d = [];
|
|
1086
1099
|
for (const g of c) {
|
|
@@ -1117,26 +1130,26 @@ class Tt extends p {
|
|
|
1117
1130
|
}
|
|
1118
1131
|
}
|
|
1119
1132
|
let u = !1;
|
|
1120
|
-
u = l === G.AND ? d.every(Boolean) : d.some(Boolean), u &&
|
|
1133
|
+
u = l === G.AND ? d.every(Boolean) : d.some(Boolean), u && n.push(o);
|
|
1121
1134
|
}
|
|
1122
|
-
return
|
|
1135
|
+
return n;
|
|
1123
1136
|
}
|
|
1124
1137
|
matchUrlMatches(e, t) {
|
|
1125
1138
|
if (e.type !== m.URL_MATCHES)
|
|
1126
1139
|
return !1;
|
|
1127
|
-
const s = e.value.toLowerCase(),
|
|
1140
|
+
const s = e.value.toLowerCase(), n = t.toLowerCase();
|
|
1128
1141
|
switch (e.operator) {
|
|
1129
1142
|
case f.EQUALS:
|
|
1130
|
-
return
|
|
1143
|
+
return n === s;
|
|
1131
1144
|
case f.CONTAINS:
|
|
1132
|
-
return
|
|
1145
|
+
return n.includes(s);
|
|
1133
1146
|
case f.STARTS_WITH:
|
|
1134
|
-
return
|
|
1147
|
+
return n.startsWith(s);
|
|
1135
1148
|
case f.ENDS_WITH:
|
|
1136
|
-
return
|
|
1149
|
+
return n.endsWith(s);
|
|
1137
1150
|
case f.REGEX:
|
|
1138
1151
|
try {
|
|
1139
|
-
return new RegExp(s, "gi").test(
|
|
1152
|
+
return new RegExp(s, "gi").test(n);
|
|
1140
1153
|
} catch {
|
|
1141
1154
|
return !1;
|
|
1142
1155
|
}
|
|
@@ -1147,19 +1160,19 @@ class Tt extends p {
|
|
|
1147
1160
|
matchDeviceType(e, t) {
|
|
1148
1161
|
if (e.type !== m.DEVICE_TYPE)
|
|
1149
1162
|
return !1;
|
|
1150
|
-
const s = e.value.toLowerCase(),
|
|
1163
|
+
const s = e.value.toLowerCase(), n = t.toLowerCase();
|
|
1151
1164
|
switch (e.operator) {
|
|
1152
1165
|
case f.EQUALS:
|
|
1153
|
-
return
|
|
1166
|
+
return n === s;
|
|
1154
1167
|
case f.CONTAINS:
|
|
1155
|
-
return
|
|
1168
|
+
return n.includes(s);
|
|
1156
1169
|
case f.STARTS_WITH:
|
|
1157
|
-
return
|
|
1170
|
+
return n.startsWith(s);
|
|
1158
1171
|
case f.ENDS_WITH:
|
|
1159
|
-
return
|
|
1172
|
+
return n.endsWith(s);
|
|
1160
1173
|
case f.REGEX:
|
|
1161
1174
|
try {
|
|
1162
|
-
return new RegExp(s, "gi").test(
|
|
1175
|
+
return new RegExp(s, "gi").test(n);
|
|
1163
1176
|
} catch {
|
|
1164
1177
|
return !1;
|
|
1165
1178
|
}
|
|
@@ -1181,19 +1194,19 @@ class Tt extends p {
|
|
|
1181
1194
|
t.role ?? "",
|
|
1182
1195
|
t.ariaLabel ?? "",
|
|
1183
1196
|
...Object.values(t.dataAttributes ?? {})
|
|
1184
|
-
].join(" "),
|
|
1197
|
+
].join(" "), n = e.value.toLowerCase(), a = s.toLowerCase();
|
|
1185
1198
|
switch (e.operator) {
|
|
1186
1199
|
case f.EQUALS:
|
|
1187
|
-
return this.checkElementFieldEquals(t,
|
|
1200
|
+
return this.checkElementFieldEquals(t, n);
|
|
1188
1201
|
case f.CONTAINS:
|
|
1189
|
-
return a.includes(
|
|
1202
|
+
return a.includes(n);
|
|
1190
1203
|
case f.STARTS_WITH:
|
|
1191
|
-
return a.startsWith(
|
|
1204
|
+
return a.startsWith(n);
|
|
1192
1205
|
case f.ENDS_WITH:
|
|
1193
|
-
return a.endsWith(
|
|
1206
|
+
return a.endsWith(n);
|
|
1194
1207
|
case f.REGEX:
|
|
1195
1208
|
try {
|
|
1196
|
-
return new RegExp(
|
|
1209
|
+
return new RegExp(n, "gi").test(a);
|
|
1197
1210
|
} catch {
|
|
1198
1211
|
return !1;
|
|
1199
1212
|
}
|
|
@@ -1206,19 +1219,19 @@ class Tt extends p {
|
|
|
1206
1219
|
e.type
|
|
1207
1220
|
))
|
|
1208
1221
|
return !1;
|
|
1209
|
-
const s = t ?? "",
|
|
1222
|
+
const s = t ?? "", n = e.value.toLowerCase(), a = s.toLowerCase();
|
|
1210
1223
|
switch (e.operator) {
|
|
1211
1224
|
case f.EQUALS:
|
|
1212
|
-
return a ===
|
|
1225
|
+
return a === n;
|
|
1213
1226
|
case f.CONTAINS:
|
|
1214
|
-
return a.includes(
|
|
1227
|
+
return a.includes(n);
|
|
1215
1228
|
case f.STARTS_WITH:
|
|
1216
|
-
return a.startsWith(
|
|
1229
|
+
return a.startsWith(n);
|
|
1217
1230
|
case f.ENDS_WITH:
|
|
1218
|
-
return a.endsWith(
|
|
1231
|
+
return a.endsWith(n);
|
|
1219
1232
|
case f.REGEX:
|
|
1220
1233
|
try {
|
|
1221
|
-
return new RegExp(
|
|
1234
|
+
return new RegExp(n, "gi").test(a);
|
|
1222
1235
|
} catch {
|
|
1223
1236
|
return !1;
|
|
1224
1237
|
}
|
|
@@ -1238,15 +1251,15 @@ class Tt extends p {
|
|
|
1238
1251
|
e.role,
|
|
1239
1252
|
e.ariaLabel
|
|
1240
1253
|
];
|
|
1241
|
-
for (const
|
|
1242
|
-
if (
|
|
1243
|
-
const a =
|
|
1254
|
+
for (const n of s)
|
|
1255
|
+
if (n) {
|
|
1256
|
+
const a = n.toLowerCase(), o = t.toLowerCase();
|
|
1244
1257
|
if (a === o)
|
|
1245
1258
|
return !0;
|
|
1246
1259
|
}
|
|
1247
1260
|
if (e.dataAttributes)
|
|
1248
|
-
for (const
|
|
1249
|
-
const a =
|
|
1261
|
+
for (const n of Object.values(e.dataAttributes)) {
|
|
1262
|
+
const a = n.toLowerCase(), o = t.toLowerCase();
|
|
1250
1263
|
if (a === o)
|
|
1251
1264
|
return !0;
|
|
1252
1265
|
}
|
|
@@ -1284,7 +1297,7 @@ class Mt extends p {
|
|
|
1284
1297
|
type: e,
|
|
1285
1298
|
page_url: t,
|
|
1286
1299
|
from_page_url: s,
|
|
1287
|
-
scroll_data:
|
|
1300
|
+
scroll_data: n,
|
|
1288
1301
|
click_data: a,
|
|
1289
1302
|
custom_event: o,
|
|
1290
1303
|
web_vitals: l,
|
|
@@ -1296,7 +1309,7 @@ class Mt extends p {
|
|
|
1296
1309
|
page_url: t,
|
|
1297
1310
|
hasCustomEvent: !!o,
|
|
1298
1311
|
hasClickData: !!a,
|
|
1299
|
-
hasScrollData: !!
|
|
1312
|
+
hasScrollData: !!n,
|
|
1300
1313
|
hasWebVitals: !!l
|
|
1301
1314
|
}), !this.samplingManager.shouldSampleEvent(e, l)) {
|
|
1302
1315
|
i.debug("EventManager", "Event filtered by sampling", { type: e, samplingActive: !0 });
|
|
@@ -1305,7 +1318,7 @@ class Mt extends p {
|
|
|
1305
1318
|
if (this.isDuplicatedEvent({
|
|
1306
1319
|
type: e,
|
|
1307
1320
|
page_url: t,
|
|
1308
|
-
scroll_data:
|
|
1321
|
+
scroll_data: n,
|
|
1309
1322
|
click_data: a,
|
|
1310
1323
|
custom_event: o,
|
|
1311
1324
|
web_vitals: l,
|
|
@@ -1336,7 +1349,7 @@ class Mt extends p {
|
|
|
1336
1349
|
timestamp: Date.now(),
|
|
1337
1350
|
...U && { referrer: document.referrer || "Direct" },
|
|
1338
1351
|
...s && !y ? { from_page_url: s } : {},
|
|
1339
|
-
...
|
|
1352
|
+
...n && { scroll_data: n },
|
|
1340
1353
|
...a && { click_data: a },
|
|
1341
1354
|
...o && { custom_event: o },
|
|
1342
1355
|
...ie && { utm: ie },
|
|
@@ -1449,11 +1462,11 @@ class Mt extends p {
|
|
|
1449
1462
|
buildEventsPayload() {
|
|
1450
1463
|
const e = /* @__PURE__ */ new Map();
|
|
1451
1464
|
for (const s of this.eventsQueue) {
|
|
1452
|
-
let
|
|
1453
|
-
s.click_data && (
|
|
1465
|
+
let n = `${s.type}_${s.page_url}`;
|
|
1466
|
+
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
1467
|
}
|
|
1455
1468
|
const t = [...e.values()];
|
|
1456
|
-
return t.sort((s,
|
|
1469
|
+
return t.sort((s, n) => s.timestamp - n.timestamp), {
|
|
1457
1470
|
user_id: this.get("userId"),
|
|
1458
1471
|
session_id: this.get("sessionId"),
|
|
1459
1472
|
device: this.get("device"),
|
|
@@ -1467,14 +1480,14 @@ class Mt extends p {
|
|
|
1467
1480
|
getEventFingerprint(e) {
|
|
1468
1481
|
const t = `${e.type}_${e.page_url}`;
|
|
1469
1482
|
if (e.click_data) {
|
|
1470
|
-
const s = Math.round((e.click_data.x || 0) / F) * F,
|
|
1471
|
-
return `${t}_${s}_${
|
|
1483
|
+
const s = Math.round((e.click_data.x || 0) / F) * F, n = Math.round((e.click_data.y || 0) / F) * F;
|
|
1484
|
+
return `${t}_${s}_${n}_${e.click_data.tag}_${e.click_data.id}`;
|
|
1472
1485
|
}
|
|
1473
1486
|
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
1487
|
}
|
|
1475
1488
|
isDuplicatedEvent(e) {
|
|
1476
|
-
const t = this.getEventFingerprint(e), s = this.eventFingerprints.get(t) ?? 0,
|
|
1477
|
-
return
|
|
1489
|
+
const t = this.getEventFingerprint(e), s = this.eventFingerprints.get(t) ?? 0, n = Date.now();
|
|
1490
|
+
return n - s < de ? !0 : (this.eventFingerprints.set(t, n), this.cleanupOldFingerprints(), !1);
|
|
1478
1491
|
}
|
|
1479
1492
|
/**
|
|
1480
1493
|
* Cleans up old fingerprints to prevent memory leaks
|
|
@@ -1483,10 +1496,10 @@ class Mt extends p {
|
|
|
1483
1496
|
if (this.eventFingerprints.size <= Oe)
|
|
1484
1497
|
return;
|
|
1485
1498
|
const e = Date.now(), t = de * Fe, s = [];
|
|
1486
|
-
for (const [
|
|
1487
|
-
e - a > t && s.push(
|
|
1488
|
-
for (const
|
|
1489
|
-
this.eventFingerprints.delete(
|
|
1499
|
+
for (const [n, a] of this.eventFingerprints)
|
|
1500
|
+
e - a > t && s.push(n);
|
|
1501
|
+
for (const n of s)
|
|
1502
|
+
this.eventFingerprints.delete(n);
|
|
1490
1503
|
i.debug("EventManager", "Cleaned up old event fingerprints", {
|
|
1491
1504
|
totalFingerprints: this.eventFingerprints.size + s.length,
|
|
1492
1505
|
cleanedCount: s.length,
|
|
@@ -1553,11 +1566,11 @@ class Mt extends p {
|
|
|
1553
1566
|
const e = this.storageManager.getItem(this.PERSISTENCE_KEY);
|
|
1554
1567
|
if (!e)
|
|
1555
1568
|
return;
|
|
1556
|
-
const t = JSON.parse(e), s = Date.now(),
|
|
1557
|
-
if (s - t.timestamp >
|
|
1569
|
+
const t = JSON.parse(e), s = Date.now(), n = Qe;
|
|
1570
|
+
if (s - t.timestamp > n) {
|
|
1558
1571
|
this.clearPersistedEvents(), i.debug("EventManager", "Cleared expired persisted events", {
|
|
1559
1572
|
age: s - t.timestamp,
|
|
1560
|
-
maxAge:
|
|
1573
|
+
maxAge: n
|
|
1561
1574
|
});
|
|
1562
1575
|
return;
|
|
1563
1576
|
}
|
|
@@ -1754,12 +1767,12 @@ class Ce extends p {
|
|
|
1754
1767
|
eventManager;
|
|
1755
1768
|
projectId;
|
|
1756
1769
|
debugMode;
|
|
1757
|
-
constructor(e, t, s,
|
|
1770
|
+
constructor(e, t, s, n) {
|
|
1758
1771
|
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
1772
|
recoveryWindowMs: this.calculateRecoveryWindow(),
|
|
1760
1773
|
maxRecoveryAttempts: Ke,
|
|
1761
1774
|
contextPreservation: !0,
|
|
1762
|
-
...
|
|
1775
|
+
...n
|
|
1763
1776
|
};
|
|
1764
1777
|
}
|
|
1765
1778
|
/**
|
|
@@ -1775,22 +1788,22 @@ class Ce extends p {
|
|
|
1775
1788
|
), {
|
|
1776
1789
|
recovered: !1
|
|
1777
1790
|
};
|
|
1778
|
-
const
|
|
1779
|
-
if (!
|
|
1791
|
+
const n = s?.context;
|
|
1792
|
+
if (!n)
|
|
1780
1793
|
return this.debugMode && i.debug("SessionRecovery", "No session context available for recovery"), {
|
|
1781
1794
|
recovered: !1
|
|
1782
1795
|
};
|
|
1783
1796
|
const a = Date.now();
|
|
1784
|
-
if (a -
|
|
1797
|
+
if (a - n.lastActivity > this.config.recoveryWindowMs)
|
|
1785
1798
|
return this.debugMode && i.debug("SessionRecovery", "Session recovery failed - outside recovery window"), {
|
|
1786
1799
|
recovered: !1
|
|
1787
1800
|
};
|
|
1788
|
-
const l =
|
|
1801
|
+
const l = n.sessionId, c = (s?.attempt ?? 0) + 1, d = {
|
|
1789
1802
|
sessionId: e ?? l,
|
|
1790
1803
|
timestamp: a,
|
|
1791
1804
|
attempt: c,
|
|
1792
1805
|
context: {
|
|
1793
|
-
...
|
|
1806
|
+
...n,
|
|
1794
1807
|
recoveryAttempts: c,
|
|
1795
1808
|
lastActivity: a
|
|
1796
1809
|
}
|
|
@@ -1835,8 +1848,8 @@ class Ce extends p {
|
|
|
1835
1848
|
context: e
|
|
1836
1849
|
};
|
|
1837
1850
|
t.push(s);
|
|
1838
|
-
const
|
|
1839
|
-
t.length >
|
|
1851
|
+
const n = 5;
|
|
1852
|
+
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
1853
|
} catch (t) {
|
|
1841
1854
|
this.debugMode && i.warn("SessionRecovery", "Failed to store session context for recovery", { error: t });
|
|
1842
1855
|
}
|
|
@@ -1881,7 +1894,7 @@ class Ce extends p {
|
|
|
1881
1894
|
* Clean up old recovery attempts
|
|
1882
1895
|
*/
|
|
1883
1896
|
cleanupOldRecoveryAttempts() {
|
|
1884
|
-
const e = this.getStoredRecoveryAttempts(), t = Date.now(), s = e.filter((
|
|
1897
|
+
const e = this.getStoredRecoveryAttempts(), t = Date.now(), s = e.filter((n) => t - n.timestamp <= this.config.recoveryWindowMs);
|
|
1885
1898
|
s.length !== e.length && (this.storeRecoveryAttempts(s), this.debugMode && i.debug("SessionRecovery", `Cleaned up ${e.length - s.length} old recovery attempts`));
|
|
1886
1899
|
}
|
|
1887
1900
|
/**
|
|
@@ -1968,7 +1981,7 @@ class Ut extends p {
|
|
|
1968
1981
|
crossTabConflicts: 0,
|
|
1969
1982
|
lastHealthCheck: Date.now()
|
|
1970
1983
|
};
|
|
1971
|
-
constructor(e, t, s,
|
|
1984
|
+
constructor(e, t, s, n, a) {
|
|
1972
1985
|
super(), this.config = {
|
|
1973
1986
|
throttleDelay: Te,
|
|
1974
1987
|
visibilityTimeout: Ve,
|
|
@@ -1980,7 +1993,7 @@ class Ut extends p {
|
|
|
1980
1993
|
maxRetries: 2,
|
|
1981
1994
|
debugMode: !1,
|
|
1982
1995
|
...a
|
|
1983
|
-
}, this.onActivity = e, this.onInactivity = t, this.eventManager = s ?? null, this.storageManager =
|
|
1996
|
+
}, 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
1997
|
sessionTimeout: this.config.timeout,
|
|
1985
1998
|
deviceCapabilities: this.deviceCapabilities,
|
|
1986
1999
|
unloadHandlersEnabled: this.sessionEndConfig.enablePageUnloadHandlers
|
|
@@ -2024,8 +2037,8 @@ class Ut extends p {
|
|
|
2024
2037
|
const e = Date.now();
|
|
2025
2038
|
let t = "", s = !1;
|
|
2026
2039
|
if (this.recoveryManager?.hasRecoverableSession()) {
|
|
2027
|
-
const
|
|
2028
|
-
|
|
2040
|
+
const n = this.recoveryManager.attemptSessionRecovery();
|
|
2041
|
+
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
2042
|
sessionId: t,
|
|
2030
2043
|
recoveryAttempts: this.sessionHealth.recoveryAttempts
|
|
2031
2044
|
}));
|
|
@@ -2048,8 +2061,8 @@ class Ut extends p {
|
|
|
2048
2061
|
}), this.recoveryManager && (this.recoveryManager.cleanupOldRecoveryAttempts(), this.recoveryManager = null);
|
|
2049
2062
|
}
|
|
2050
2063
|
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:
|
|
2064
|
+
const e = "ontouchstart" in window || navigator.maxTouchPoints > 0, t = window.matchMedia("(pointer: fine)").matches, s = !window.matchMedia("(pointer: coarse)").matches, n = we() === E.Mobile;
|
|
2065
|
+
return { hasTouch: e, hasMouse: t, hasKeyboard: s, isMobile: n };
|
|
2053
2066
|
}
|
|
2054
2067
|
initializeListenerManagers() {
|
|
2055
2068
|
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 +2174,20 @@ class Ut extends p {
|
|
|
2161
2174
|
}
|
|
2162
2175
|
async performSessionEnd(e, t) {
|
|
2163
2176
|
const s = Date.now();
|
|
2164
|
-
let
|
|
2177
|
+
let n = 0;
|
|
2165
2178
|
try {
|
|
2166
2179
|
if (i.info("SessionManager", "Starting session end", { method: t, reason: e, timestamp: s }), this.eventManager) {
|
|
2167
2180
|
this.eventManager.track({
|
|
2168
2181
|
type: h.SESSION_END,
|
|
2169
2182
|
session_end_reason: e
|
|
2170
|
-
}),
|
|
2183
|
+
}), n = this.eventManager.getQueueLength();
|
|
2171
2184
|
const o = await this.eventManager.flushImmediately();
|
|
2172
2185
|
this.cleanupSession();
|
|
2173
2186
|
const l = {
|
|
2174
2187
|
success: o,
|
|
2175
2188
|
reason: e,
|
|
2176
2189
|
timestamp: s,
|
|
2177
|
-
eventsFlushed:
|
|
2190
|
+
eventsFlushed: n,
|
|
2178
2191
|
method: t
|
|
2179
2192
|
};
|
|
2180
2193
|
return o ? this.sessionEndStats.successfulEnds++ : this.sessionEndStats.failedEnds++, l;
|
|
@@ -2193,7 +2206,7 @@ class Ut extends p {
|
|
|
2193
2206
|
success: !1,
|
|
2194
2207
|
reason: e,
|
|
2195
2208
|
timestamp: s,
|
|
2196
|
-
eventsFlushed:
|
|
2209
|
+
eventsFlushed: n,
|
|
2197
2210
|
method: t
|
|
2198
2211
|
};
|
|
2199
2212
|
}
|
|
@@ -2241,16 +2254,16 @@ class Ut extends p {
|
|
|
2241
2254
|
return a ? this.sessionEndStats.successfulEnds++ : this.sessionEndStats.failedEnds++, o;
|
|
2242
2255
|
}
|
|
2243
2256
|
this.cleanupSession();
|
|
2244
|
-
const
|
|
2257
|
+
const n = {
|
|
2245
2258
|
success: !0,
|
|
2246
2259
|
reason: e,
|
|
2247
2260
|
timestamp: t,
|
|
2248
2261
|
eventsFlushed: 0,
|
|
2249
2262
|
method: "sync"
|
|
2250
2263
|
};
|
|
2251
|
-
return this.sessionEndStats.successfulEnds++,
|
|
2252
|
-
} catch (
|
|
2253
|
-
return this.sessionEndStats.failedEnds++, this.cleanupSession(), i.error("SessionManager", "Sync session end failed", { error:
|
|
2264
|
+
return this.sessionEndStats.successfulEnds++, n;
|
|
2265
|
+
} catch (n) {
|
|
2266
|
+
return this.sessionEndStats.failedEnds++, this.cleanupSession(), i.error("SessionManager", "Sync session end failed", { error: n, reason: e }), {
|
|
2254
2267
|
success: !1,
|
|
2255
2268
|
reason: e,
|
|
2256
2269
|
timestamp: t,
|
|
@@ -2265,16 +2278,16 @@ class Ut extends p {
|
|
|
2265
2278
|
e || !this.get("sessionId") || (e = !0, this.clearInactivityTimer(), this.endSessionSafely("page_unload", { forceSync: !0 }));
|
|
2266
2279
|
}, s = () => {
|
|
2267
2280
|
t();
|
|
2268
|
-
},
|
|
2281
|
+
}, n = (o) => {
|
|
2269
2282
|
o.persisted || t();
|
|
2270
2283
|
}, a = () => {
|
|
2271
2284
|
document.visibilityState === "hidden" && this.get("sessionId") && !e && (this.visibilityChangeTimeout = window.setTimeout(() => {
|
|
2272
2285
|
document.visibilityState === "hidden" && this.get("sessionId") && !e && t(), this.visibilityChangeTimeout = null;
|
|
2273
2286
|
}, 1e3));
|
|
2274
2287
|
};
|
|
2275
|
-
window.addEventListener("beforeunload", s), window.addEventListener("pagehide",
|
|
2288
|
+
window.addEventListener("beforeunload", s), window.addEventListener("pagehide", n), document.addEventListener("visibilitychange", a), this.cleanupHandlers.push(
|
|
2276
2289
|
() => window.removeEventListener("beforeunload", s),
|
|
2277
|
-
() => window.removeEventListener("pagehide",
|
|
2290
|
+
() => window.removeEventListener("pagehide", n),
|
|
2278
2291
|
() => document.removeEventListener("visibilitychange", a),
|
|
2279
2292
|
() => {
|
|
2280
2293
|
this.visibilityChangeTimeout && (clearTimeout(this.visibilityChangeTimeout), this.visibilityChangeTimeout = null);
|
|
@@ -2283,8 +2296,8 @@ class Ut extends p {
|
|
|
2283
2296
|
}
|
|
2284
2297
|
}
|
|
2285
2298
|
class Pt extends p {
|
|
2286
|
-
constructor(e, t, s,
|
|
2287
|
-
super(), this.callbacks =
|
|
2299
|
+
constructor(e, t, s, n) {
|
|
2300
|
+
super(), this.callbacks = n, this.storageManager = e, this.projectId = t, this.tabId = $(), this.config = {
|
|
2288
2301
|
tabHeartbeatIntervalMs: qe,
|
|
2289
2302
|
tabElectionTimeoutMs: We,
|
|
2290
2303
|
debugMode: (this.get("config")?.mode === "qa" || this.get("config")?.mode === "debug") ?? !1,
|
|
@@ -2445,10 +2458,10 @@ class Pt extends p {
|
|
|
2445
2458
|
if (!this.sessionEnded && this.leaderTabId && !this.isTabLeader) {
|
|
2446
2459
|
const s = this.getStoredSessionContext();
|
|
2447
2460
|
if (s) {
|
|
2448
|
-
const
|
|
2449
|
-
|
|
2461
|
+
const n = Date.now() - s.lastActivity, a = this.config.tabHeartbeatIntervalMs * 3;
|
|
2462
|
+
n > a && (this.config.debugMode && i.warn(
|
|
2450
2463
|
"CrossTabSession",
|
|
2451
|
-
`Leader tab appears inactive (${
|
|
2464
|
+
`Leader tab appears inactive (${n}ms), attempting to become leader`
|
|
2452
2465
|
), this.leaderTabId = null, this.startLeaderElection());
|
|
2453
2466
|
}
|
|
2454
2467
|
}
|
|
@@ -2583,13 +2596,13 @@ class Pt extends p {
|
|
|
2583
2596
|
const e = Date.now(), t = this.lastHeartbeatSent ?? 0, s = this.config.tabHeartbeatIntervalMs * 0.8;
|
|
2584
2597
|
if (!this.isTabLeader && e - t < s)
|
|
2585
2598
|
return;
|
|
2586
|
-
const
|
|
2599
|
+
const n = {
|
|
2587
2600
|
type: "heartbeat",
|
|
2588
2601
|
tabId: this.tabId,
|
|
2589
2602
|
sessionId: this.tabInfo.sessionId,
|
|
2590
2603
|
timestamp: e
|
|
2591
2604
|
};
|
|
2592
|
-
this.broadcastChannel.postMessage(
|
|
2605
|
+
this.broadcastChannel.postMessage(n), this.lastHeartbeatSent = e;
|
|
2593
2606
|
}
|
|
2594
2607
|
/**
|
|
2595
2608
|
* Update tab info with current timestamp
|
|
@@ -2712,8 +2725,8 @@ class Pt extends p {
|
|
|
2712
2725
|
const e = this.getStoredSessionContext();
|
|
2713
2726
|
if (!e)
|
|
2714
2727
|
return this.get("config")?.sessionTimeout ?? R;
|
|
2715
|
-
const s = Date.now() - e.lastActivity,
|
|
2716
|
-
return Math.max(0,
|
|
2728
|
+
const s = Date.now() - e.lastActivity, n = this.get("config")?.sessionTimeout ?? R;
|
|
2729
|
+
return Math.max(0, n - s);
|
|
2717
2730
|
}
|
|
2718
2731
|
/**
|
|
2719
2732
|
* Update session activity from any tab
|
|
@@ -2771,16 +2784,16 @@ class Ht extends p {
|
|
|
2771
2784
|
const e = async () => {
|
|
2772
2785
|
if (this.crossTabSessionManager && this.crossTabSessionManager.updateSessionActivity(), !this.get("sessionId"))
|
|
2773
2786
|
try {
|
|
2774
|
-
const
|
|
2775
|
-
this.set("sessionId",
|
|
2776
|
-
sessionId:
|
|
2777
|
-
recovered:
|
|
2787
|
+
const n = await this.createOrJoinSession();
|
|
2788
|
+
this.set("sessionId", n.sessionId), i.info("SessionHandler", "🏁 Session started", {
|
|
2789
|
+
sessionId: n.sessionId,
|
|
2790
|
+
recovered: n.recovered,
|
|
2778
2791
|
crossTabActive: !!this.crossTabSessionManager
|
|
2779
|
-
}), this.trackSession(h.SESSION_START,
|
|
2780
|
-
} catch (
|
|
2792
|
+
}), this.trackSession(h.SESSION_START, n.recovered), this.persistSession(n.sessionId), this.startHeartbeat();
|
|
2793
|
+
} catch (n) {
|
|
2781
2794
|
i.error(
|
|
2782
2795
|
"SessionHandler",
|
|
2783
|
-
`Session creation failed: ${
|
|
2796
|
+
`Session creation failed: ${n instanceof Error ? n.message : "Unknown error"}`
|
|
2784
2797
|
), this.forceCleanupSession();
|
|
2785
2798
|
}
|
|
2786
2799
|
}, t = () => {
|
|
@@ -2789,17 +2802,17 @@ class Ht extends p {
|
|
|
2789
2802
|
(this.get("config")?.mode === "qa" || this.get("config")?.mode === "debug") && i.debug("SessionHandler", "Session kept alive by cross-tab activity");
|
|
2790
2803
|
return;
|
|
2791
2804
|
}
|
|
2792
|
-
this.sessionManager.endSessionManaged("inactivity").then((
|
|
2805
|
+
this.sessionManager.endSessionManaged("inactivity").then((n) => {
|
|
2793
2806
|
i.info("SessionHandler", "🛑 Session ended by inactivity", {
|
|
2794
2807
|
sessionId: this.get("sessionId"),
|
|
2795
|
-
reason:
|
|
2796
|
-
success:
|
|
2797
|
-
eventsFlushed:
|
|
2808
|
+
reason: n.reason,
|
|
2809
|
+
success: n.success,
|
|
2810
|
+
eventsFlushed: n.eventsFlushed
|
|
2798
2811
|
}), this.crossTabSessionManager && this.crossTabSessionManager.endSession("inactivity"), this.clearPersistedSession(), this.stopHeartbeat();
|
|
2799
|
-
}).catch((
|
|
2812
|
+
}).catch((n) => {
|
|
2800
2813
|
i.error(
|
|
2801
2814
|
"SessionHandler",
|
|
2802
|
-
`Session end failed: ${
|
|
2815
|
+
`Session end failed: ${n instanceof Error ? n.message : "Unknown error"}`
|
|
2803
2816
|
), this.forceCleanupSession();
|
|
2804
2817
|
});
|
|
2805
2818
|
}
|
|
@@ -2913,8 +2926,8 @@ class Ht extends p {
|
|
|
2913
2926
|
const e = this.storageManager.getItem(this.sessionStorageKey);
|
|
2914
2927
|
if (e)
|
|
2915
2928
|
try {
|
|
2916
|
-
const t = JSON.parse(e),
|
|
2917
|
-
if (
|
|
2929
|
+
const t = JSON.parse(e), n = Date.now() - t.lastHeartbeat, a = this.get("config")?.sessionTimeout ?? R;
|
|
2930
|
+
if (n > a) {
|
|
2918
2931
|
const o = this.recoveryManager?.hasRecoverableSession();
|
|
2919
2932
|
if (o && this.recoveryManager) {
|
|
2920
2933
|
const l = {
|
|
@@ -3029,17 +3042,17 @@ class xt extends p {
|
|
|
3029
3042
|
return;
|
|
3030
3043
|
}
|
|
3031
3044
|
i.debug("ClickHandler", "Starting click tracking"), this.clickHandler = (e) => {
|
|
3032
|
-
const t = e, s = t.target,
|
|
3033
|
-
if (!
|
|
3045
|
+
const t = e, s = t.target, n = s instanceof HTMLElement ? s : s instanceof Node && s.parentElement instanceof HTMLElement ? s.parentElement : null;
|
|
3046
|
+
if (!n) {
|
|
3034
3047
|
i.warn("ClickHandler", "Click target not found or not an element");
|
|
3035
3048
|
return;
|
|
3036
3049
|
}
|
|
3037
3050
|
i.info("ClickHandler", "🖱️ Click detected on element", {
|
|
3038
|
-
tagName:
|
|
3039
|
-
className:
|
|
3040
|
-
textContent:
|
|
3051
|
+
tagName: n.tagName,
|
|
3052
|
+
className: n.className || "none",
|
|
3053
|
+
textContent: n.textContent?.slice(0, 50) ?? "empty"
|
|
3041
3054
|
});
|
|
3042
|
-
const a = this.findTrackingElement(
|
|
3055
|
+
const a = this.findTrackingElement(n), o = this.getRelevantClickElement(n), l = this.calculateClickCoordinates(t, n);
|
|
3043
3056
|
if (a) {
|
|
3044
3057
|
const d = this.extractTrackingData(a);
|
|
3045
3058
|
if (d) {
|
|
@@ -3053,7 +3066,7 @@ class xt extends p {
|
|
|
3053
3066
|
});
|
|
3054
3067
|
}
|
|
3055
3068
|
}
|
|
3056
|
-
const c = this.generateClickData(
|
|
3069
|
+
const c = this.generateClickData(n, o, l);
|
|
3057
3070
|
this.eventManager.track({
|
|
3058
3071
|
type: h.CLICK,
|
|
3059
3072
|
click_data: c
|
|
@@ -3093,8 +3106,8 @@ class xt extends p {
|
|
|
3093
3106
|
return e;
|
|
3094
3107
|
}
|
|
3095
3108
|
calculateClickCoordinates(e, t) {
|
|
3096
|
-
const s = t.getBoundingClientRect(),
|
|
3097
|
-
return { x:
|
|
3109
|
+
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;
|
|
3110
|
+
return { x: n, y: a, relativeX: o, relativeY: l };
|
|
3098
3111
|
}
|
|
3099
3112
|
extractTrackingData(e) {
|
|
3100
3113
|
const t = e.getAttribute(`${z}-name`), s = e.getAttribute(`${z}-value`);
|
|
@@ -3106,9 +3119,9 @@ class xt extends p {
|
|
|
3106
3119
|
};
|
|
3107
3120
|
}
|
|
3108
3121
|
generateClickData(e, t, s) {
|
|
3109
|
-
const { x:
|
|
3122
|
+
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
3123
|
return {
|
|
3111
|
-
x:
|
|
3124
|
+
x: n,
|
|
3112
3125
|
y: a,
|
|
3113
3126
|
relativeX: o,
|
|
3114
3127
|
relativeY: l,
|
|
@@ -3125,19 +3138,19 @@ class xt extends p {
|
|
|
3125
3138
|
};
|
|
3126
3139
|
}
|
|
3127
3140
|
getRelevantText(e, t) {
|
|
3128
|
-
const s = ["main", "section", "article", "body", "html", "header", "footer", "aside", "nav"],
|
|
3129
|
-
if (!
|
|
3141
|
+
const s = ["main", "section", "article", "body", "html", "header", "footer", "aside", "nav"], n = e.textContent?.trim() ?? "", a = t.textContent?.trim() ?? "";
|
|
3142
|
+
if (!n && !a)
|
|
3130
3143
|
return "";
|
|
3131
|
-
if (
|
|
3132
|
-
return
|
|
3144
|
+
if (n && n.length <= _)
|
|
3145
|
+
return n;
|
|
3133
3146
|
const o = s.includes(t.tagName.toLowerCase()), l = a.length > _ * 2;
|
|
3134
|
-
return o && l ?
|
|
3147
|
+
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
3148
|
}
|
|
3136
3149
|
extractElementAttributes(e) {
|
|
3137
3150
|
const t = ["id", "class", "data-testid", "aria-label", "title", "href", "type", "name"], s = {};
|
|
3138
|
-
for (const
|
|
3139
|
-
const a = e.getAttribute(
|
|
3140
|
-
a && (s[
|
|
3151
|
+
for (const n of t) {
|
|
3152
|
+
const a = e.getAttribute(n);
|
|
3153
|
+
a && (s[n] = a);
|
|
3141
3154
|
}
|
|
3142
3155
|
return s;
|
|
3143
3156
|
}
|
|
@@ -3157,10 +3170,10 @@ class Ot extends p {
|
|
|
3157
3170
|
startTracking() {
|
|
3158
3171
|
const e = this.get("config").scrollContainerSelectors, t = Array.isArray(e) ? e : typeof e == "string" ? [e] : [];
|
|
3159
3172
|
i.debug("ScrollHandler", "Starting scroll tracking", { selectorsCount: t.length });
|
|
3160
|
-
const s = t.map((
|
|
3173
|
+
const s = t.map((n) => this.safeQuerySelector(n)).filter((n) => n instanceof HTMLElement);
|
|
3161
3174
|
s.length === 0 && s.push(window);
|
|
3162
|
-
for (const
|
|
3163
|
-
this.setupScrollContainer(
|
|
3175
|
+
for (const n of s)
|
|
3176
|
+
this.setupScrollContainer(n);
|
|
3164
3177
|
}
|
|
3165
3178
|
stopTracking() {
|
|
3166
3179
|
i.debug("ScrollHandler", "Stopping scroll tracking", { containersCount: this.containers.length });
|
|
@@ -3183,21 +3196,21 @@ class Ot extends p {
|
|
|
3183
3196
|
return;
|
|
3184
3197
|
}
|
|
3185
3198
|
t.debounceTimer && clearTimeout(t.debounceTimer), t.debounceTimer = window.setTimeout(() => {
|
|
3186
|
-
const
|
|
3187
|
-
|
|
3199
|
+
const n = this.calculateScrollData(t);
|
|
3200
|
+
n && this.eventManager.track({
|
|
3188
3201
|
type: h.SCROLL,
|
|
3189
|
-
scroll_data:
|
|
3202
|
+
scroll_data: n
|
|
3190
3203
|
}), t.debounceTimer = null;
|
|
3191
3204
|
}, Me);
|
|
3192
3205
|
};
|
|
3193
3206
|
t.listener = s, this.containers.push(t), e instanceof Window ? window.addEventListener("scroll", s, { passive: !0 }) : e.addEventListener("scroll", s, { passive: !0 });
|
|
3194
3207
|
}
|
|
3195
3208
|
calculateScrollData(e) {
|
|
3196
|
-
const { element: t, lastScrollPos: s } = e,
|
|
3209
|
+
const { element: t, lastScrollPos: s } = e, n = this.getScrollTop(t), a = this.getViewportHeight(t), o = this.getScrollHeight(t);
|
|
3197
3210
|
if (t === window && o <= a)
|
|
3198
3211
|
return null;
|
|
3199
|
-
const l =
|
|
3200
|
-
return Math.abs(
|
|
3212
|
+
const l = n > s ? j.DOWN : j.UP, c = o > a ? Math.min(100, Math.max(0, Math.floor(n / (o - a) * 100))) : 0;
|
|
3213
|
+
return Math.abs(n - s) < Ue ? null : (e.lastScrollPos = n, { depth: c, direction: l });
|
|
3201
3214
|
}
|
|
3202
3215
|
getScrollTop(e) {
|
|
3203
3216
|
return e instanceof Window ? window.scrollY : e.scrollTop;
|
|
@@ -3209,8 +3222,8 @@ class Ot extends p {
|
|
|
3209
3222
|
return e instanceof Window ? document.documentElement.scrollHeight : e.scrollHeight;
|
|
3210
3223
|
}
|
|
3211
3224
|
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 &&
|
|
3225
|
+
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;
|
|
3226
|
+
return s && n;
|
|
3214
3227
|
}
|
|
3215
3228
|
safeQuerySelector(e) {
|
|
3216
3229
|
try {
|
|
@@ -3308,19 +3321,19 @@ class Ft extends p {
|
|
|
3308
3321
|
async loadScript(e) {
|
|
3309
3322
|
return new Promise((t, s) => {
|
|
3310
3323
|
try {
|
|
3311
|
-
const
|
|
3312
|
-
|
|
3324
|
+
const n = document.createElement("script");
|
|
3325
|
+
n.id = "tracelog-ga-script", n.async = !0, n.src = `https://www.googletagmanager.com/gtag/js?id=${e}`, n.onload = () => {
|
|
3313
3326
|
t();
|
|
3314
|
-
},
|
|
3327
|
+
}, n.onerror = () => {
|
|
3315
3328
|
const a = new Error("Failed to load Google Analytics script");
|
|
3316
3329
|
i.error("GoogleAnalytics", "Google Analytics script load failed", {
|
|
3317
3330
|
measurementId: e,
|
|
3318
3331
|
error: a.message,
|
|
3319
|
-
scriptSrc:
|
|
3332
|
+
scriptSrc: n.src
|
|
3320
3333
|
}), s(a);
|
|
3321
|
-
}, document.head.appendChild(
|
|
3322
|
-
} catch (
|
|
3323
|
-
const a =
|
|
3334
|
+
}, document.head.appendChild(n);
|
|
3335
|
+
} catch (n) {
|
|
3336
|
+
const a = n instanceof Error ? n : new Error(String(n));
|
|
3324
3337
|
i.error("GoogleAnalytics", "Error creating Google Analytics script", {
|
|
3325
3338
|
measurementId: e,
|
|
3326
3339
|
error: a.message
|
|
@@ -3433,8 +3446,8 @@ class Vt extends p {
|
|
|
3433
3446
|
this.reportTTFB(), this.safeObserve(
|
|
3434
3447
|
"largest-contentful-paint",
|
|
3435
3448
|
(t) => {
|
|
3436
|
-
const s = t.getEntries(),
|
|
3437
|
-
|
|
3449
|
+
const s = t.getEntries(), n = s[s.length - 1];
|
|
3450
|
+
n && this.sendVital({ type: "LCP", value: Number(n.startTime.toFixed(N)) });
|
|
3438
3451
|
},
|
|
3439
3452
|
{ type: "largest-contentful-paint", buffered: !0 },
|
|
3440
3453
|
!0
|
|
@@ -3444,10 +3457,10 @@ class Vt extends p {
|
|
|
3444
3457
|
"layout-shift",
|
|
3445
3458
|
(t) => {
|
|
3446
3459
|
const s = t.getEntries();
|
|
3447
|
-
for (const
|
|
3448
|
-
if (
|
|
3460
|
+
for (const n of s) {
|
|
3461
|
+
if (n.hadRecentInput === !0)
|
|
3449
3462
|
continue;
|
|
3450
|
-
const a = typeof
|
|
3463
|
+
const a = typeof n.value == "number" ? n.value : 0;
|
|
3451
3464
|
e += a;
|
|
3452
3465
|
}
|
|
3453
3466
|
this.sendVital({ type: "CLS", value: Number(e.toFixed(Pe)) });
|
|
@@ -3465,8 +3478,8 @@ class Vt extends p {
|
|
|
3465
3478
|
"event",
|
|
3466
3479
|
(t) => {
|
|
3467
3480
|
let s = 0;
|
|
3468
|
-
const
|
|
3469
|
-
for (const a of
|
|
3481
|
+
const n = t.getEntries();
|
|
3482
|
+
for (const a of n) {
|
|
3470
3483
|
const o = (a.processingEnd ?? 0) - (a.startTime ?? 0);
|
|
3471
3484
|
s = Math.max(s, o);
|
|
3472
3485
|
}
|
|
@@ -3477,11 +3490,11 @@ class Vt extends p {
|
|
|
3477
3490
|
}
|
|
3478
3491
|
async initWebVitals() {
|
|
3479
3492
|
try {
|
|
3480
|
-
const { onLCP: e, onCLS: t, onFCP: s, onTTFB:
|
|
3493
|
+
const { onLCP: e, onCLS: t, onFCP: s, onTTFB: n, onINP: a } = await import("./web-vitals-CCnqwnC8.mjs"), o = (l) => (c) => {
|
|
3481
3494
|
const d = Number(c.value.toFixed(N));
|
|
3482
3495
|
this.sendVital({ type: l, value: d });
|
|
3483
3496
|
};
|
|
3484
|
-
e(o("LCP")), t(o("CLS")), s(o("FCP")),
|
|
3497
|
+
e(o("LCP")), t(o("CLS")), s(o("FCP")), n(o("TTFB")), a(o("INP"));
|
|
3485
3498
|
} catch (e) {
|
|
3486
3499
|
i.warn("PerformanceHandler", "Failed to load web-vitals library, using fallback", {
|
|
3487
3500
|
error: e instanceof Error ? e.message : "Unknown error"
|
|
@@ -3509,8 +3522,8 @@ class Vt extends p {
|
|
|
3509
3522
|
(e) => {
|
|
3510
3523
|
const t = e.getEntries();
|
|
3511
3524
|
for (const s of t) {
|
|
3512
|
-
const
|
|
3513
|
-
a - this.lastLongTaskSentAt >= Be && (this.trackWebVital("LONG_TASK",
|
|
3525
|
+
const n = Number(s.duration.toFixed(N)), a = Date.now();
|
|
3526
|
+
a - this.lastLongTaskSentAt >= Be && (this.trackWebVital("LONG_TASK", n), this.lastLongTaskSentAt = a);
|
|
3514
3527
|
}
|
|
3515
3528
|
},
|
|
3516
3529
|
{ type: "longtask", buffered: !0 }
|
|
@@ -3520,10 +3533,10 @@ class Vt extends p {
|
|
|
3520
3533
|
const t = this.getNavigationId(), s = `${e.type}`;
|
|
3521
3534
|
if (t) {
|
|
3522
3535
|
this.reportedByNav.has(t) || this.reportedByNav.set(t, /* @__PURE__ */ new Set());
|
|
3523
|
-
const
|
|
3524
|
-
if (
|
|
3536
|
+
const n = this.reportedByNav.get(t);
|
|
3537
|
+
if (n.has(s))
|
|
3525
3538
|
return;
|
|
3526
|
-
|
|
3539
|
+
n.add(s);
|
|
3527
3540
|
}
|
|
3528
3541
|
this.trackWebVital(e.type, e.value);
|
|
3529
3542
|
}
|
|
@@ -3550,19 +3563,19 @@ class Vt extends p {
|
|
|
3550
3563
|
}), null;
|
|
3551
3564
|
}
|
|
3552
3565
|
}
|
|
3553
|
-
safeObserve(e, t, s,
|
|
3566
|
+
safeObserve(e, t, s, n = !1) {
|
|
3554
3567
|
try {
|
|
3555
3568
|
if (typeof PerformanceObserver > "u") return;
|
|
3556
3569
|
const a = PerformanceObserver.supportedEntryTypes;
|
|
3557
3570
|
if (a && !a.includes(e)) return;
|
|
3558
3571
|
const o = new PerformanceObserver((l, c) => {
|
|
3559
|
-
if (t(l, c),
|
|
3572
|
+
if (t(l, c), n)
|
|
3560
3573
|
try {
|
|
3561
3574
|
c.disconnect();
|
|
3562
3575
|
} catch {
|
|
3563
3576
|
}
|
|
3564
3577
|
});
|
|
3565
|
-
o.observe(s ?? { type: e, buffered: !0 }),
|
|
3578
|
+
o.observe(s ?? { type: e, buffered: !0 }), n || this.observers.push(o);
|
|
3566
3579
|
} catch (a) {
|
|
3567
3580
|
i.warn("PerformanceHandler", "Failed to create performance observer", {
|
|
3568
3581
|
type: e,
|
|
@@ -3664,17 +3677,17 @@ class jt extends p {
|
|
|
3664
3677
|
}
|
|
3665
3678
|
interceptFetch() {
|
|
3666
3679
|
window.fetch = async (e, t) => {
|
|
3667
|
-
const s = Date.now(),
|
|
3680
|
+
const s = Date.now(), n = typeof e == "string" ? e : e.toString(), a = t?.method ?? "GET";
|
|
3668
3681
|
try {
|
|
3669
3682
|
const o = await this.originalFetch(e, t), l = Date.now() - s;
|
|
3670
3683
|
return o.ok || (i.debug("NetworkHandler", "Fetch error detected", {
|
|
3671
3684
|
method: a,
|
|
3672
|
-
url: this.normalizeUrlForTracking(
|
|
3685
|
+
url: this.normalizeUrlForTracking(n),
|
|
3673
3686
|
status: o.status,
|
|
3674
3687
|
statusText: o.statusText
|
|
3675
3688
|
}), this.trackNetworkError(
|
|
3676
3689
|
a.toUpperCase(),
|
|
3677
|
-
this.normalizeUrlForTracking(
|
|
3690
|
+
this.normalizeUrlForTracking(n),
|
|
3678
3691
|
o.status,
|
|
3679
3692
|
o.statusText,
|
|
3680
3693
|
l
|
|
@@ -3683,11 +3696,11 @@ class jt extends p {
|
|
|
3683
3696
|
const l = Date.now() - s, c = o instanceof Error ? o.message : "Network Error";
|
|
3684
3697
|
throw i.debug("NetworkHandler", "Fetch exception caught", {
|
|
3685
3698
|
method: a,
|
|
3686
|
-
url: this.normalizeUrlForTracking(
|
|
3699
|
+
url: this.normalizeUrlForTracking(n),
|
|
3687
3700
|
error: c
|
|
3688
3701
|
}), this.trackNetworkError(
|
|
3689
3702
|
a.toUpperCase(),
|
|
3690
|
-
this.normalizeUrlForTracking(
|
|
3703
|
+
this.normalizeUrlForTracking(n),
|
|
3691
3704
|
void 0,
|
|
3692
3705
|
c,
|
|
3693
3706
|
l
|
|
@@ -3696,7 +3709,7 @@ class jt extends p {
|
|
|
3696
3709
|
};
|
|
3697
3710
|
}
|
|
3698
3711
|
interceptXHR() {
|
|
3699
|
-
const e = this.trackNetworkError.bind(this), t = this.normalizeUrlForTracking.bind(this), s = this.originalXHROpen,
|
|
3712
|
+
const e = this.trackNetworkError.bind(this), t = this.normalizeUrlForTracking.bind(this), s = this.originalXHROpen, n = this.originalXHRSend;
|
|
3700
3713
|
XMLHttpRequest.prototype.open = function(a, o, l, c, d) {
|
|
3701
3714
|
const u = l ?? !0, g = this;
|
|
3702
3715
|
return g._tracelogStartTime = Date.now(), g._tracelogMethod = a.toUpperCase(), g._tracelogUrl = o.toString(), s.call(this, a, o, u, c, d);
|
|
@@ -3717,10 +3730,10 @@ class jt extends p {
|
|
|
3717
3730
|
}
|
|
3718
3731
|
if (u)
|
|
3719
3732
|
return u.call(o, g);
|
|
3720
|
-
},
|
|
3733
|
+
}, n.call(this, a);
|
|
3721
3734
|
};
|
|
3722
3735
|
}
|
|
3723
|
-
trackNetworkError(e, t, s,
|
|
3736
|
+
trackNetworkError(e, t, s, n, a) {
|
|
3724
3737
|
const o = this.get("config");
|
|
3725
3738
|
if (!this.shouldSample(o?.errorSampling ?? 0.1)) {
|
|
3726
3739
|
i.debug(
|
|
@@ -3736,17 +3749,17 @@ class jt extends p {
|
|
|
3736
3749
|
}
|
|
3737
3750
|
i.warn(
|
|
3738
3751
|
"NetworkHandler",
|
|
3739
|
-
`Network error tracked: ${e} ${t} (status: ${s}, statusText: ${
|
|
3740
|
-
{ method: e, url: t, status: s, statusText:
|
|
3752
|
+
`Network error tracked: ${e} ${t} (status: ${s}, statusText: ${n}, duration: ${a}ms)`,
|
|
3753
|
+
{ method: e, url: t, status: s, statusText: n, duration: a }
|
|
3741
3754
|
), this.eventManager.track({
|
|
3742
3755
|
type: h.ERROR,
|
|
3743
3756
|
error_data: {
|
|
3744
3757
|
type: D.NETWORK_ERROR,
|
|
3745
|
-
message:
|
|
3758
|
+
message: n,
|
|
3746
3759
|
method: e,
|
|
3747
3760
|
url: t,
|
|
3748
3761
|
status: s,
|
|
3749
|
-
statusText:
|
|
3762
|
+
statusText: n,
|
|
3750
3763
|
duration: a
|
|
3751
3764
|
}
|
|
3752
3765
|
});
|
|
@@ -3815,7 +3828,7 @@ class Gt extends p {
|
|
|
3815
3828
|
i.warn("App", "Custom event attempted before eventManager initialization", { eventName: e });
|
|
3816
3829
|
return;
|
|
3817
3830
|
}
|
|
3818
|
-
const { valid: s, error:
|
|
3831
|
+
const { valid: s, error: n, sanitizedMetadata: a } = vt(e, t);
|
|
3819
3832
|
if (s)
|
|
3820
3833
|
i.debug("App", "Custom event validated and queued", { eventName: e, hasMetadata: !!a }), this.eventManager.track({
|
|
3821
3834
|
type: h.CUSTOM,
|
|
@@ -3826,14 +3839,14 @@ class Gt extends p {
|
|
|
3826
3839
|
});
|
|
3827
3840
|
else {
|
|
3828
3841
|
const o = this.get("config")?.mode;
|
|
3829
|
-
if (i.clientError("App", `Custom event validation failed: ${
|
|
3842
|
+
if (i.clientError("App", `Custom event validation failed: ${n ?? "unknown error"}`, {
|
|
3830
3843
|
eventName: e,
|
|
3831
|
-
validationError:
|
|
3844
|
+
validationError: n,
|
|
3832
3845
|
hasMetadata: !!t,
|
|
3833
3846
|
mode: o
|
|
3834
3847
|
}), o === "qa" || o === "debug")
|
|
3835
3848
|
throw new Error(
|
|
3836
|
-
`custom event "${e}" validation failed (${
|
|
3849
|
+
`custom event "${e}" validation failed (${n ?? "unknown error"}). Please, review your event data and try again.`
|
|
3837
3850
|
);
|
|
3838
3851
|
}
|
|
3839
3852
|
}
|
|
@@ -3943,9 +3956,9 @@ const Qt = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
|
|
|
3943
3956
|
DEFAULT_SESSION_TIMEOUT_MS: R
|
|
3944
3957
|
}, Symbol.toStringTag, { value: "Module" }));
|
|
3945
3958
|
let v = null, T = !1;
|
|
3946
|
-
const qt = async (
|
|
3959
|
+
const qt = async (r) => {
|
|
3947
3960
|
try {
|
|
3948
|
-
if (i.info("API", "Library initialization started", { id:
|
|
3961
|
+
if (i.info("API", "Library initialization started", { id: r.id }), typeof window > "u" || typeof document > "u")
|
|
3949
3962
|
throw i.clientError(
|
|
3950
3963
|
"API",
|
|
3951
3964
|
"Browser environment required - this library can only be used in a browser environment",
|
|
@@ -3956,32 +3969,32 @@ const qt = async (n) => {
|
|
|
3956
3969
|
), new Error("This library can only be used in a browser environment");
|
|
3957
3970
|
if (v) {
|
|
3958
3971
|
i.debug("API", "Library already initialized, skipping duplicate initialization", {
|
|
3959
|
-
projectId:
|
|
3972
|
+
projectId: r.id
|
|
3960
3973
|
});
|
|
3961
3974
|
return;
|
|
3962
3975
|
}
|
|
3963
3976
|
if (T) {
|
|
3964
|
-
i.debug("API", "Concurrent initialization detected, waiting for completion", { projectId:
|
|
3977
|
+
i.debug("API", "Concurrent initialization detected, waiting for completion", { projectId: r.id });
|
|
3965
3978
|
let s = 0;
|
|
3966
|
-
const
|
|
3967
|
-
for (; T && s <
|
|
3979
|
+
const n = me.MAX_CONCURRENT_RETRIES, a = me.CONCURRENT_RETRY_DELAY_MS;
|
|
3980
|
+
for (; T && s < n; )
|
|
3968
3981
|
await new Promise((o) => setTimeout(o, a)), s++;
|
|
3969
3982
|
if (v) {
|
|
3970
3983
|
i.debug("API", "Concurrent initialization completed successfully", {
|
|
3971
|
-
projectId:
|
|
3984
|
+
projectId: r.id,
|
|
3972
3985
|
retriesUsed: s
|
|
3973
3986
|
});
|
|
3974
3987
|
return;
|
|
3975
3988
|
}
|
|
3976
3989
|
if (T)
|
|
3977
3990
|
throw i.error("API", "Initialization timeout - concurrent initialization took too long", {
|
|
3978
|
-
projectId:
|
|
3991
|
+
projectId: r.id,
|
|
3979
3992
|
retriesUsed: s,
|
|
3980
|
-
maxRetries:
|
|
3993
|
+
maxRetries: n
|
|
3981
3994
|
}), new Error("App initialization timeout - concurrent initialization took too long");
|
|
3982
3995
|
}
|
|
3983
|
-
T = !0, i.debug("API", "Validating and normalizing configuration", { projectId:
|
|
3984
|
-
const e = dt(
|
|
3996
|
+
T = !0, i.debug("API", "Validating and normalizing configuration", { projectId: r.id });
|
|
3997
|
+
const e = dt(r);
|
|
3985
3998
|
i.debug("API", "Creating App instance", { projectId: e.id });
|
|
3986
3999
|
const t = new Gt();
|
|
3987
4000
|
await t.init(e), v = t, i.info("API", "Library initialization completed successfully", {
|
|
@@ -3998,20 +4011,20 @@ const qt = async (n) => {
|
|
|
3998
4011
|
} finally {
|
|
3999
4012
|
T = !1;
|
|
4000
4013
|
}
|
|
4001
|
-
}, Wt = (
|
|
4014
|
+
}, Wt = (r, e) => {
|
|
4002
4015
|
try {
|
|
4003
4016
|
if (!v)
|
|
4004
4017
|
throw i.clientError("API", "Custom event failed - Library not initialized. Please call TraceLog.init() first", {
|
|
4005
|
-
eventName:
|
|
4018
|
+
eventName: r,
|
|
4006
4019
|
hasMetadata: !!e
|
|
4007
4020
|
}), new Error("App not initialized");
|
|
4008
4021
|
i.debug("API", "Sending custom event", {
|
|
4009
|
-
eventName:
|
|
4022
|
+
eventName: r,
|
|
4010
4023
|
hasMetadata: !!e,
|
|
4011
4024
|
metadataKeys: e ? Object.keys(e) : []
|
|
4012
|
-
}), v.sendCustomEvent(
|
|
4025
|
+
}), v.sendCustomEvent(r, e);
|
|
4013
4026
|
} catch (t) {
|
|
4014
|
-
if (i.error("API", "Event tracking failed", { eventName:
|
|
4027
|
+
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
4028
|
throw t;
|
|
4016
4029
|
}
|
|
4017
4030
|
}, Xt = () => v !== null, Kt = () => ({
|
|
@@ -4023,8 +4036,8 @@ const qt = async (n) => {
|
|
|
4023
4036
|
if (i.info("API", "Library cleanup initiated"), !v)
|
|
4024
4037
|
throw i.warn("API", "Cleanup called but Library was not initialized"), new Error("App not initialized");
|
|
4025
4038
|
v.destroy(), v = null, T = !1, i.info("API", "Library cleanup completed successfully");
|
|
4026
|
-
} catch (
|
|
4027
|
-
i.error("API", "Cleanup failed", { error:
|
|
4039
|
+
} catch (r) {
|
|
4040
|
+
i.error("API", "Cleanup failed", { error: r, hadApp: !!v, wasInitializing: T });
|
|
4028
4041
|
}
|
|
4029
4042
|
}, Jt = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
|
|
4030
4043
|
__proto__: null,
|