@tracelog/lib 0.0.5 → 0.0.7
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
|
@@ -6,7 +6,7 @@ class p {
|
|
|
6
6
|
}
|
|
7
7
|
set(e, t) {
|
|
8
8
|
const s = q[e];
|
|
9
|
-
q[e] = t, (e === "sessionId" || e === "config" || e === "hasStartSession") &&
|
|
9
|
+
q[e] = t, (e === "sessionId" || e === "config" || e === "hasStartSession") && n.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, i) {
|
|
102
102
|
if (!this.shouldShowLog(e))
|
|
103
103
|
return;
|
|
104
104
|
const a = this.formatMessage(t, s), o = this.getConsoleMethod(e);
|
|
105
|
-
|
|
105
|
+
i !== void 0 ? console[o](a, i) : 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, i) {
|
|
111
111
|
if (!(typeof window > "u" || typeof CustomEvent > "u"))
|
|
112
112
|
try {
|
|
113
113
|
const a = new CustomEvent("tracelog:log", {
|
|
@@ -116,49 +116,49 @@ class Re extends p {
|
|
|
116
116
|
level: e,
|
|
117
117
|
namespace: t,
|
|
118
118
|
message: s,
|
|
119
|
-
data:
|
|
119
|
+
data: i
|
|
120
120
|
}
|
|
121
121
|
});
|
|
122
122
|
window.dispatchEvent(a);
|
|
123
123
|
} catch {
|
|
124
|
-
console.log(`[TraceLog:${t}] ${s}`,
|
|
124
|
+
console.log(`[TraceLog:${t}] ${s}`, i);
|
|
125
125
|
}
|
|
126
126
|
}
|
|
127
127
|
}
|
|
128
|
-
const
|
|
128
|
+
const n = new Re();
|
|
129
129
|
let J, Ee;
|
|
130
130
|
const ke = () => {
|
|
131
131
|
typeof window < "u" && !J && (J = window.matchMedia("(pointer: coarse)"), Ee = window.matchMedia("(hover: none)"));
|
|
132
132
|
}, we = () => {
|
|
133
133
|
try {
|
|
134
|
-
|
|
134
|
+
n.debug("DeviceDetector", "Starting device detection");
|
|
135
135
|
const r = navigator;
|
|
136
136
|
if (r.userAgentData && typeof r.userAgentData.mobile == "boolean") {
|
|
137
|
-
if (
|
|
137
|
+
if (n.debug("DeviceDetector", "Using modern User-Agent Client Hints API", {
|
|
138
138
|
mobile: r.userAgentData.mobile,
|
|
139
139
|
platform: r.userAgentData.platform
|
|
140
140
|
}), r.userAgentData.platform && /ipad|tablet/i.test(r.userAgentData.platform))
|
|
141
|
-
return
|
|
141
|
+
return n.debug("DeviceDetector", "Device detected as tablet via platform hint"), E.Tablet;
|
|
142
142
|
const d = r.userAgentData.mobile ? E.Mobile : E.Desktop;
|
|
143
|
-
return
|
|
143
|
+
return n.debug("DeviceDetector", "Device detected via User-Agent hints", { result: d }), d;
|
|
144
144
|
}
|
|
145
|
-
|
|
146
|
-
const e = window.innerWidth, t = J?.matches ?? !1, s = Ee?.matches ?? !1,
|
|
145
|
+
n.debug("DeviceDetector", "Using fallback detection methods"), ke();
|
|
146
|
+
const e = window.innerWidth, t = J?.matches ?? !1, s = Ee?.matches ?? !1, i = "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: i,
|
|
151
151
|
isMobileUA: o,
|
|
152
152
|
isTabletUA: l,
|
|
153
153
|
maxTouchPoints: navigator.maxTouchPoints
|
|
154
154
|
};
|
|
155
|
-
return e <= 767 || o &&
|
|
155
|
+
return e <= 767 || o && i ? (n.debug("DeviceDetector", "Device detected as mobile", c), E.Mobile) : e >= 768 && e <= 1024 || l || t && s && i ? (n.debug("DeviceDetector", "Device detected as tablet", c), E.Tablet) : (n.debug("DeviceDetector", "Device detected as desktop", c), E.Desktop);
|
|
156
156
|
} catch (r) {
|
|
157
|
-
return
|
|
157
|
+
return n.warn("DeviceDetector", "Device detection failed, defaulting to desktop", {
|
|
158
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, 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: []
|
|
@@ -255,29 +255,29 @@ const ke = () => {
|
|
|
255
255
|
// Array validation
|
|
256
256
|
INVALID_SENSITIVE_QUERY_PARAMS: "Sensitive query params must be an array of strings"
|
|
257
257
|
}, nt = () => {
|
|
258
|
-
|
|
258
|
+
n.debug("UTMParams", "Extracting UTM parameters from URL", {
|
|
259
259
|
url: window.location.href,
|
|
260
260
|
search: window.location.search
|
|
261
261
|
});
|
|
262
262
|
const r = new URLSearchParams(window.location.search), e = {};
|
|
263
263
|
Je.forEach((s) => {
|
|
264
|
-
const
|
|
265
|
-
if (
|
|
264
|
+
const i = r.get(s);
|
|
265
|
+
if (i) {
|
|
266
266
|
const a = s.split("utm_")[1];
|
|
267
|
-
e[a] =
|
|
267
|
+
e[a] = i, n.debug("UTMParams", "Found UTM parameter", { param: s, key: a, value: i });
|
|
268
268
|
}
|
|
269
269
|
});
|
|
270
270
|
const t = Object.keys(e).length ? e : void 0;
|
|
271
|
-
return t ?
|
|
271
|
+
return t ? n.debug("UTMParams", "UTM parameters extracted successfully", {
|
|
272
272
|
parameterCount: Object.keys(t).length,
|
|
273
273
|
parameters: Object.keys(t)
|
|
274
|
-
}) :
|
|
274
|
+
}) : n.debug("UTMParams", "No UTM parameters found in URL"), t;
|
|
275
275
|
}, $ = () => {
|
|
276
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
|
|
280
|
+
return n.verbose("UUIDUtils", "Generated new UUID", { uuid: r }), r;
|
|
281
281
|
};
|
|
282
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 {
|
|
@@ -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
|
}
|
|
@@ -312,40 +312,40 @@ class ye extends x {
|
|
|
312
312
|
}
|
|
313
313
|
const ot = (r) => {
|
|
314
314
|
if (!r || typeof r != "object")
|
|
315
|
-
throw
|
|
315
|
+
throw n.clientError("ConfigValidation", "Configuration must be an object", { config: r }), new P("Configuration must be an object", "config");
|
|
316
316
|
if (!("id" in r))
|
|
317
|
-
throw
|
|
317
|
+
throw n.clientError("ConfigValidation", "Project ID is missing from configuration"), new Q(w.MISSING_PROJECT_ID, "config");
|
|
318
318
|
if (r.id === null || r.id === void 0 || typeof r.id != "string")
|
|
319
|
-
throw
|
|
319
|
+
throw n.clientError("ConfigValidation", "Project ID must be a non-empty string", {
|
|
320
320
|
providedId: r.id,
|
|
321
321
|
type: typeof r.id
|
|
322
322
|
}), new Q(w.MISSING_PROJECT_ID, "config");
|
|
323
323
|
if (r.sessionTimeout !== void 0 && (typeof r.sessionTimeout != "number" || r.sessionTimeout < Z || r.sessionTimeout > ee))
|
|
324
|
-
throw
|
|
324
|
+
throw n.clientError("ConfigValidation", "Invalid session timeout", {
|
|
325
325
|
provided: r.sessionTimeout,
|
|
326
326
|
min: Z,
|
|
327
327
|
max: ee
|
|
328
328
|
}), new rt(w.INVALID_SESSION_TIMEOUT, "config");
|
|
329
329
|
if (r.globalMetadata !== void 0 && (typeof r.globalMetadata != "object" || r.globalMetadata === null))
|
|
330
|
-
throw
|
|
330
|
+
throw n.clientError("ConfigValidation", "Global metadata must be an object", {
|
|
331
331
|
provided: r.globalMetadata,
|
|
332
332
|
type: typeof r.globalMetadata
|
|
333
|
-
}), new
|
|
333
|
+
}), new P(w.INVALID_GLOBAL_METADATA, "config");
|
|
334
334
|
if (r.scrollContainerSelectors !== void 0 && ct(r.scrollContainerSelectors), r.integrations && lt(r.integrations), r.sensitiveQueryParams !== void 0) {
|
|
335
335
|
if (!Array.isArray(r.sensitiveQueryParams))
|
|
336
|
-
throw
|
|
336
|
+
throw n.clientError("ConfigValidation", "Sensitive query params must be an array", {
|
|
337
337
|
provided: r.sensitiveQueryParams,
|
|
338
338
|
type: typeof r.sensitiveQueryParams
|
|
339
|
-
}), new
|
|
339
|
+
}), new P(w.INVALID_SENSITIVE_QUERY_PARAMS, "config");
|
|
340
340
|
for (const e of r.sensitiveQueryParams)
|
|
341
341
|
if (typeof e != "string")
|
|
342
|
-
throw
|
|
342
|
+
throw n.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
347
|
if (r.errorSampling !== void 0 && (typeof r.errorSampling != "number" || r.errorSampling < 0 || r.errorSampling > 1))
|
|
348
|
-
throw
|
|
348
|
+
throw n.clientError("ConfigValidation", "Invalid error sampling rate", {
|
|
349
349
|
provided: r.errorSampling,
|
|
350
350
|
expected: "0-1"
|
|
351
351
|
}), new at(w.INVALID_ERROR_SAMPLING_RATE, "config");
|
|
@@ -353,28 +353,28 @@ const ot = (r) => {
|
|
|
353
353
|
const e = Array.isArray(r) ? r : [r];
|
|
354
354
|
for (const t of e) {
|
|
355
355
|
if (typeof t != "string" || t.trim() === "")
|
|
356
|
-
throw
|
|
356
|
+
throw n.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);
|
|
364
364
|
} catch {
|
|
365
|
-
|
|
365
|
+
n.clientWarn("ConfigValidation", `Invalid CSS selector will be ignored: "${t}"`);
|
|
366
366
|
}
|
|
367
367
|
}
|
|
368
368
|
}, lt = (r) => {
|
|
369
369
|
if (r && r.googleAnalytics) {
|
|
370
370
|
if (!r.googleAnalytics.measurementId || typeof r.googleAnalytics.measurementId != "string" || r.googleAnalytics.measurementId.trim() === "")
|
|
371
|
-
throw
|
|
371
|
+
throw n.clientError("ConfigValidation", "Invalid Google Analytics measurement ID", {
|
|
372
372
|
provided: r.googleAnalytics.measurementId,
|
|
373
373
|
type: typeof r.googleAnalytics.measurementId
|
|
374
374
|
}), new ye(w.INVALID_GOOGLE_ANALYTICS_ID, "config");
|
|
375
375
|
const e = r.googleAnalytics.measurementId.trim();
|
|
376
376
|
if (!e.match(/^(G-|UA-)/))
|
|
377
|
-
throw
|
|
377
|
+
throw n.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
|
}
|
|
@@ -387,17 +387,17 @@ const ot = (r) => {
|
|
|
387
387
|
sensitiveQueryParams: r.sensitiveQueryParams ?? []
|
|
388
388
|
};
|
|
389
389
|
if (!e.id)
|
|
390
|
-
throw
|
|
390
|
+
throw n.clientError("ConfigValidation", "Project ID is empty after trimming whitespace", {
|
|
391
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
395
|
}, be = (r) => {
|
|
396
396
|
if (!r || typeof r != "string" || r.trim().length === 0)
|
|
397
|
-
return
|
|
397
|
+
return n.debug("Sanitize", "String sanitization skipped - empty or invalid input", { value: r, type: typeof r }), "";
|
|
398
398
|
const e = r.length;
|
|
399
399
|
let t = r;
|
|
400
|
-
r.length > M && (t = r.slice(0, Math.max(0, M)),
|
|
400
|
+
r.length > M && (t = r.slice(0, Math.max(0, M)), n.warn("Sanitize", "String truncated due to length limit", {
|
|
401
401
|
originalLength: e,
|
|
402
402
|
maxLength: M,
|
|
403
403
|
truncatedLength: t.length
|
|
@@ -407,18 +407,18 @@ const ot = (r) => {
|
|
|
407
407
|
const o = t;
|
|
408
408
|
t = t.replace(a, ""), o !== t && s++;
|
|
409
409
|
}
|
|
410
|
-
s > 0 &&
|
|
410
|
+
s > 0 && n.warn("Sanitize", "XSS patterns detected and removed", {
|
|
411
411
|
patternMatches: s,
|
|
412
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
|
|
416
|
-
return (e > 50 || s > 0) &&
|
|
415
|
+
const i = t.trim();
|
|
416
|
+
return (e > 50 || s > 0) && n.debug("Sanitize", "String sanitization completed", {
|
|
417
417
|
originalLength: e,
|
|
418
|
-
sanitizedLength:
|
|
418
|
+
sanitizedLength: i.length,
|
|
419
419
|
xssPatternMatches: s,
|
|
420
420
|
wasTruncated: e > M
|
|
421
|
-
}),
|
|
421
|
+
}), i;
|
|
422
422
|
}, ht = (r) => {
|
|
423
423
|
if (typeof r != "string")
|
|
424
424
|
return "";
|
|
@@ -429,7 +429,7 @@ const ot = (r) => {
|
|
|
429
429
|
return e = e.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'"), e.trim();
|
|
430
430
|
}, B = (r, e = 0) => {
|
|
431
431
|
if (e > le)
|
|
432
|
-
return
|
|
432
|
+
return n.warn("Sanitize", "Maximum object depth exceeded during sanitization", {
|
|
433
433
|
depth: e,
|
|
434
434
|
maxDepth: le
|
|
435
435
|
}), null;
|
|
@@ -438,23 +438,23 @@ const ot = (r) => {
|
|
|
438
438
|
if (typeof r == "string")
|
|
439
439
|
return be(r);
|
|
440
440
|
if (typeof r == "number")
|
|
441
|
-
return !Number.isFinite(r) || r < -Number.MAX_SAFE_INTEGER || r > Number.MAX_SAFE_INTEGER ? (
|
|
441
|
+
return !Number.isFinite(r) || r < -Number.MAX_SAFE_INTEGER || r > Number.MAX_SAFE_INTEGER ? (n.warn("Sanitize", "Invalid number sanitized to 0", { value: r, isFinite: Number.isFinite(r) }), 0) : r;
|
|
442
442
|
if (typeof r == "boolean")
|
|
443
443
|
return r;
|
|
444
444
|
if (Array.isArray(r)) {
|
|
445
445
|
const t = r.length, s = r.slice(0, W);
|
|
446
|
-
t > W &&
|
|
446
|
+
t > W && n.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 i = s.map((a) => B(a, e + 1)).filter((a) => a !== null);
|
|
452
|
+
return t > 0 && i.length === 0 && n.warn("Sanitize", "All array items were filtered out during sanitization", { originalLength: t, depth: e }), i;
|
|
453
453
|
}
|
|
454
454
|
if (typeof r == "object") {
|
|
455
|
-
const t = {}, s = Object.entries(r),
|
|
456
|
-
|
|
457
|
-
originalKeys:
|
|
455
|
+
const t = {}, s = Object.entries(r), i = s.length, a = s.slice(0, 20);
|
|
456
|
+
i > 20 && n.warn("Sanitize", "Object keys truncated due to limit", {
|
|
457
|
+
originalKeys: i,
|
|
458
458
|
maxKeys: 20,
|
|
459
459
|
depth: e
|
|
460
460
|
});
|
|
@@ -467,21 +467,21 @@ const ot = (r) => {
|
|
|
467
467
|
} else
|
|
468
468
|
o++;
|
|
469
469
|
}
|
|
470
|
-
return o > 0 &&
|
|
470
|
+
return o > 0 && n.debug("Sanitize", "Object properties filtered during sanitization", {
|
|
471
471
|
filteredKeysCount: o,
|
|
472
472
|
remainingKeys: Object.keys(t).length,
|
|
473
473
|
depth: e
|
|
474
474
|
}), t;
|
|
475
475
|
}
|
|
476
|
-
return
|
|
476
|
+
return n.debug("Sanitize", "Unknown value type sanitized to null", { type: typeof r, depth: e }), null;
|
|
477
477
|
}, ut = (r) => {
|
|
478
|
-
|
|
478
|
+
n.debug("Sanitize", "Starting API config sanitization");
|
|
479
479
|
const e = {};
|
|
480
480
|
if (typeof r != "object" || r === null)
|
|
481
|
-
return
|
|
481
|
+
return n.warn("Sanitize", "API config data is not an object", { data: r, type: typeof r }), e;
|
|
482
482
|
try {
|
|
483
483
|
const t = Object.keys(r);
|
|
484
|
-
let s = 0,
|
|
484
|
+
let s = 0, i = 0;
|
|
485
485
|
for (const a of t)
|
|
486
486
|
if (it.has(a)) {
|
|
487
487
|
const o = r[a];
|
|
@@ -489,46 +489,46 @@ const ot = (r) => {
|
|
|
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);
|
|
491
491
|
const d = c - e.excludedUrlPaths.length;
|
|
492
|
-
d > 0 &&
|
|
492
|
+
d > 0 && n.warn("Sanitize", "Some excluded URL paths were filtered during sanitization", {
|
|
493
493
|
originalCount: c,
|
|
494
494
|
filteredCount: d
|
|
495
495
|
});
|
|
496
496
|
} else if (a === "tags")
|
|
497
|
-
Array.isArray(o) ? (e.tags = o,
|
|
497
|
+
Array.isArray(o) ? (e.tags = o, n.debug("Sanitize", "Tags processed", { count: o.length })) : n.warn("Sanitize", "Tags value is not an array", { value: o, type: typeof o });
|
|
498
498
|
else {
|
|
499
499
|
const l = B(o);
|
|
500
|
-
l !== null ? e[a] = l :
|
|
500
|
+
l !== null ? e[a] = l : n.warn("Sanitize", "API config value sanitized to null", { key: a, originalValue: o });
|
|
501
501
|
}
|
|
502
502
|
s++;
|
|
503
503
|
} else
|
|
504
|
-
|
|
505
|
-
|
|
504
|
+
i++, n.debug("Sanitize", "API config key not allowed", { key: a });
|
|
505
|
+
n.info("Sanitize", "API config sanitization completed", {
|
|
506
506
|
originalKeys: t.length,
|
|
507
507
|
processedKeys: s,
|
|
508
|
-
filteredKeys:
|
|
508
|
+
filteredKeys: i,
|
|
509
509
|
finalKeys: Object.keys(e).length
|
|
510
510
|
});
|
|
511
511
|
} catch (t) {
|
|
512
|
-
throw
|
|
512
|
+
throw n.error("Sanitize", "API config sanitization failed", {
|
|
513
513
|
error: t instanceof Error ? t.message : t
|
|
514
514
|
}), new Error(`API config sanitization failed: ${t instanceof Error ? t.message : "Unknown error"}`);
|
|
515
515
|
}
|
|
516
516
|
return e;
|
|
517
517
|
}, gt = (r) => {
|
|
518
|
-
if (
|
|
519
|
-
return
|
|
518
|
+
if (n.debug("Sanitize", "Starting metadata sanitization", { hasMetadata: r != null }), typeof r != "object" || r === null)
|
|
519
|
+
return n.debug("Sanitize", "Metadata is not an object, returning empty object", {
|
|
520
520
|
metadata: r,
|
|
521
521
|
type: typeof r
|
|
522
522
|
}), {};
|
|
523
523
|
try {
|
|
524
|
-
const e = Object.keys(r).length, t = B(r), s = typeof t == "object" && t !== null ? t : {},
|
|
525
|
-
return
|
|
524
|
+
const e = Object.keys(r).length, t = B(r), s = typeof t == "object" && t !== null ? t : {}, i = Object.keys(s).length;
|
|
525
|
+
return n.debug("Sanitize", "Metadata sanitization completed", {
|
|
526
526
|
originalKeys: e,
|
|
527
|
-
finalKeys:
|
|
528
|
-
keysFiltered: e -
|
|
527
|
+
finalKeys: i,
|
|
528
|
+
keysFiltered: e - i
|
|
529
529
|
}), s;
|
|
530
530
|
} catch (e) {
|
|
531
|
-
throw
|
|
531
|
+
throw n.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
|
}
|
|
@@ -565,11 +565,11 @@ const ot = (r) => {
|
|
|
565
565
|
valid: !1,
|
|
566
566
|
error: "Event name cannot be a reserved word"
|
|
567
567
|
} : { valid: !0 }, pt = (r, e, t) => {
|
|
568
|
-
const s = gt(e),
|
|
568
|
+
const s = gt(e), i = `${t} "${r}" metadata error`;
|
|
569
569
|
if (!ft(s))
|
|
570
570
|
return {
|
|
571
571
|
valid: !1,
|
|
572
|
-
error: `${
|
|
572
|
+
error: `${i}: object has invalid types. Valid types are string, number, boolean or string arrays.`
|
|
573
573
|
};
|
|
574
574
|
let a;
|
|
575
575
|
try {
|
|
@@ -577,37 +577,37 @@ const ot = (r) => {
|
|
|
577
577
|
} catch {
|
|
578
578
|
return {
|
|
579
579
|
valid: !1,
|
|
580
|
-
error: `${
|
|
580
|
+
error: `${i}: 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: `${i}: 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: `${i}: 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: `${i}: 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: `${i}: 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: `${i}: property "${l}" is too long (max ${M} characters).`
|
|
611
611
|
};
|
|
612
612
|
}
|
|
613
613
|
return {
|
|
@@ -617,108 +617,108 @@ const ot = (r) => {
|
|
|
617
617
|
}, vt = (r, e) => {
|
|
618
618
|
const t = mt(r);
|
|
619
619
|
if (!t.valid)
|
|
620
|
-
return
|
|
620
|
+
return n.clientError("EventValidation", "Event name validation failed", { eventName: r, error: t.error }), t;
|
|
621
621
|
if (!e)
|
|
622
622
|
return { valid: !0 };
|
|
623
623
|
const s = pt(r, e, "customEvent");
|
|
624
|
-
return s.valid ||
|
|
624
|
+
return s.valid || n.clientError("EventValidation", "Event metadata validation failed", {
|
|
625
625
|
eventName: r,
|
|
626
626
|
error: s.error
|
|
627
627
|
}), s;
|
|
628
628
|
}, te = (r, e = !1) => {
|
|
629
629
|
try {
|
|
630
|
-
const t = new URL(r), s = t.protocol === "https:",
|
|
631
|
-
return s || e &&
|
|
630
|
+
const t = new URL(r), s = t.protocol === "https:", i = t.protocol === "http:";
|
|
631
|
+
return s || e && i;
|
|
632
632
|
} catch {
|
|
633
633
|
return !1;
|
|
634
634
|
}
|
|
635
635
|
}, St = (r, e = !1) => {
|
|
636
|
-
|
|
637
|
-
const t = new URL(window.location.href), s = t.hostname,
|
|
638
|
-
if (
|
|
639
|
-
throw
|
|
640
|
-
const a =
|
|
641
|
-
if (
|
|
636
|
+
n.debug("URLUtils", "Generating API URL", { projectId: r, allowHttp: e });
|
|
637
|
+
const t = new URL(window.location.href), s = t.hostname, i = s.split(".");
|
|
638
|
+
if (i.length === 0)
|
|
639
|
+
throw n.clientError("URLUtils", "Invalid hostname - no domain parts found", { hostname: s }), new Error("Invalid URL");
|
|
640
|
+
const a = i.slice(-2).join("."), o = e && t.protocol === "http:" ? "http" : "https", l = `${o}://${r}.${a}`;
|
|
641
|
+
if (n.debug("URLUtils", "Generated API URL", {
|
|
642
642
|
originalUrl: window.location.href,
|
|
643
643
|
hostname: s,
|
|
644
|
-
domainParts:
|
|
644
|
+
domainParts: i.length,
|
|
645
645
|
cleanDomain: a,
|
|
646
646
|
protocol: o,
|
|
647
647
|
generatedUrl: l
|
|
648
648
|
}), !te(l, e))
|
|
649
|
-
throw
|
|
649
|
+
throw n.clientError("URLUtils", "Generated API URL failed validation", {
|
|
650
650
|
apiUrl: l,
|
|
651
651
|
allowHttp: e
|
|
652
652
|
}), new Error("Invalid URL");
|
|
653
|
-
return
|
|
653
|
+
return n.debug("URLUtils", "API URL generation completed successfully", { apiUrl: l }), l;
|
|
654
654
|
}, se = (r, e = []) => {
|
|
655
|
-
|
|
655
|
+
n.debug("URLUtils", "Normalizing URL", {
|
|
656
656
|
urlLength: r.length,
|
|
657
657
|
sensitiveParamsCount: e.length
|
|
658
658
|
});
|
|
659
659
|
try {
|
|
660
|
-
const t = new URL(r), s = t.searchParams,
|
|
660
|
+
const t = new URL(r), s = t.searchParams, i = 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
|
-
}), a &&
|
|
665
|
+
}), a && n.debug("URLUtils", "Sensitive parameters removed from URL", {
|
|
666
666
|
removedParams: o,
|
|
667
|
-
originalParamCount:
|
|
667
|
+
originalParamCount: i,
|
|
668
668
|
finalParamCount: Array.from(s.keys()).length
|
|
669
669
|
}), !a && r.includes("?"))
|
|
670
|
-
return
|
|
670
|
+
return n.debug("URLUtils", "URL normalization - no changes needed"), r;
|
|
671
671
|
t.search = s.toString();
|
|
672
672
|
const l = t.toString();
|
|
673
|
-
return
|
|
673
|
+
return n.debug("URLUtils", "URL normalization completed", {
|
|
674
674
|
hasChanged: a,
|
|
675
675
|
originalLength: r.length,
|
|
676
676
|
normalizedLength: l.length
|
|
677
677
|
}), l;
|
|
678
678
|
} catch (t) {
|
|
679
|
-
return
|
|
679
|
+
return n.warn("URLUtils", "URL normalization failed, returning original", {
|
|
680
680
|
url: r.slice(0, 100),
|
|
681
681
|
error: t instanceof Error ? t.message : t
|
|
682
682
|
}), r;
|
|
683
683
|
}
|
|
684
684
|
}, yt = (r, e = []) => {
|
|
685
|
-
if (
|
|
685
|
+
if (n.debug("URLUtils", "Checking if URL path is excluded", {
|
|
686
686
|
urlLength: r.length,
|
|
687
687
|
excludedPathsCount: e.length
|
|
688
688
|
}), e.length === 0)
|
|
689
|
-
return
|
|
689
|
+
return n.debug("URLUtils", "No excluded paths configured"), !1;
|
|
690
690
|
let t;
|
|
691
691
|
try {
|
|
692
|
-
t = new URL(r, window.location.origin).pathname,
|
|
692
|
+
t = new URL(r, window.location.origin).pathname, n.debug("URLUtils", "Extracted path from URL", { path: t });
|
|
693
693
|
} catch (c) {
|
|
694
|
-
return
|
|
694
|
+
return n.warn("URLUtils", "Failed to parse URL for path exclusion check", {
|
|
695
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", i = (c) => c.replaceAll(/[$()*+.?[\\\]^{|}]/g, "\\$&"), a = (c) => new RegExp(
|
|
700
|
+
"^" + c.split("*").map((d) => i(d)).join(".+") + "$"
|
|
701
701
|
), o = e.find((c) => {
|
|
702
702
|
try {
|
|
703
703
|
if (s(c)) {
|
|
704
704
|
const u = c.test(t);
|
|
705
|
-
return u &&
|
|
705
|
+
return u && n.debug("URLUtils", "Path matched regex pattern", { path: t, pattern: c.toString() }), u;
|
|
706
706
|
}
|
|
707
707
|
if (c.includes("*")) {
|
|
708
708
|
const u = a(c), g = u.test(t);
|
|
709
|
-
return g &&
|
|
709
|
+
return g && n.debug("URLUtils", "Path matched wildcard pattern", { path: t, pattern: c, regex: u.toString() }), g;
|
|
710
710
|
}
|
|
711
711
|
const d = c === t;
|
|
712
|
-
return d &&
|
|
712
|
+
return d && n.debug("URLUtils", "Path matched exact pattern", { path: t, pattern: c }), d;
|
|
713
713
|
} catch (d) {
|
|
714
|
-
return
|
|
714
|
+
return n.warn("URLUtils", "Error testing exclusion pattern", {
|
|
715
715
|
pattern: c,
|
|
716
716
|
path: t,
|
|
717
717
|
error: d instanceof Error ? d.message : d
|
|
718
718
|
}), !1;
|
|
719
719
|
}
|
|
720
720
|
}), l = !!o;
|
|
721
|
-
return
|
|
721
|
+
return n.debug("URLUtils", "URL path exclusion check completed", {
|
|
722
722
|
path: t,
|
|
723
723
|
isExcluded: l,
|
|
724
724
|
matchedPattern: o ?? null,
|
|
@@ -736,10 +736,10 @@ class bt {
|
|
|
736
736
|
class Et {
|
|
737
737
|
async get(e, t) {
|
|
738
738
|
if (t.id === C.HttpSkip)
|
|
739
|
-
return
|
|
740
|
-
|
|
739
|
+
return n.debug("ConfigManager", "Using special project id"), this.getDefaultConfig(t);
|
|
740
|
+
n.debug("ConfigManager", "Loading config from API", { apiUrl: e, projectId: t.id });
|
|
741
741
|
const s = await this.load(e, t, t.id === C.HttpLocal);
|
|
742
|
-
return
|
|
742
|
+
return n.info("ConfigManager", "Config loaded successfully", {
|
|
743
743
|
projectId: t.id,
|
|
744
744
|
mode: s.mode,
|
|
745
745
|
hasExcludedPaths: !!s.excludedUrlPaths?.length,
|
|
@@ -748,42 +748,42 @@ class Et {
|
|
|
748
748
|
}
|
|
749
749
|
async load(e, t, s) {
|
|
750
750
|
try {
|
|
751
|
-
const
|
|
752
|
-
if (!
|
|
751
|
+
const i = s ? `${window.location.origin}/config` : this.getUrl(e);
|
|
752
|
+
if (!i)
|
|
753
753
|
throw new Error("Config URL is not valid or not allowed");
|
|
754
|
-
const a = await fetch(
|
|
754
|
+
const a = await fetch(i, {
|
|
755
755
|
method: "GET",
|
|
756
756
|
headers: { "Content-Type": "application/json" }
|
|
757
757
|
});
|
|
758
758
|
if (!a.ok) {
|
|
759
759
|
const A = `HTTP ${a.status}: ${a.statusText}`;
|
|
760
|
-
throw
|
|
760
|
+
throw n.error("ConfigManager", "Config API request failed", {
|
|
761
761
|
status: a.status,
|
|
762
762
|
statusText: a.statusText,
|
|
763
|
-
configUrl:
|
|
763
|
+
configUrl: i
|
|
764
764
|
}), new Error(A);
|
|
765
765
|
}
|
|
766
766
|
const o = await a.json();
|
|
767
767
|
if (o == null || typeof o != "object" || Array.isArray(o))
|
|
768
|
-
throw
|
|
768
|
+
throw n.error("ConfigManager", "Invalid config API response format", {
|
|
769
769
|
responseType: typeof o,
|
|
770
770
|
isArray: Array.isArray(o)
|
|
771
771
|
}), new Error("Invalid config API response: expected object");
|
|
772
772
|
const l = ut(o), d = { ...{ ...Ae, ...l }, ...t };
|
|
773
|
-
new URLSearchParams(window.location.search).get("qaMode") === "true" && !d.mode && (d.mode = L.QA,
|
|
773
|
+
new URLSearchParams(window.location.search).get("qaMode") === "true" && !d.mode && (d.mode = L.QA, n.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 =
|
|
778
|
-
throw
|
|
776
|
+
} catch (i) {
|
|
777
|
+
const a = i instanceof Error ? i.message : "Unknown error";
|
|
778
|
+
throw n.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
|
|
786
|
-
return
|
|
783
|
+
let i = `${e}/config`;
|
|
784
|
+
if (s && (i += "?qaMode=true"), !te(i))
|
|
785
|
+
throw n.clientError("ConfigManager", "Invalid config URL provided", { configUrl: i }), new Error("Config URL is not valid or not allowed");
|
|
786
|
+
return i;
|
|
787
787
|
}
|
|
788
788
|
getDefaultConfig(e) {
|
|
789
789
|
return Ye({
|
|
@@ -820,14 +820,14 @@ class wt extends p {
|
|
|
820
820
|
return;
|
|
821
821
|
}
|
|
822
822
|
const t = this.createRecoveryBody(e);
|
|
823
|
-
this.sendRecoveredEvents(t) ? (
|
|
823
|
+
this.sendRecoveredEvents(t) ? (n.info("SenderManager", "Persisted events recovered successfully", {
|
|
824
824
|
eventsCount: e.events.length,
|
|
825
825
|
sessionId: e.sessionId
|
|
826
|
-
}), this.clearPersistedEvents()) : (
|
|
826
|
+
}), this.clearPersistedEvents()) : (n.warn("SenderManager", "Failed to recover persisted events, scheduling retry", {
|
|
827
827
|
eventsCount: e.events.length
|
|
828
828
|
}), this.scheduleRetryForRecoveredEvents(t));
|
|
829
829
|
} catch (e) {
|
|
830
|
-
|
|
830
|
+
n.error("SenderManager", "Failed to recover persisted events", { error: e });
|
|
831
831
|
}
|
|
832
832
|
}
|
|
833
833
|
stop() {
|
|
@@ -860,14 +860,16 @@ class wt extends p {
|
|
|
860
860
|
method: "POST",
|
|
861
861
|
mode: "cors",
|
|
862
862
|
credentials: "omit",
|
|
863
|
+
body: s,
|
|
863
864
|
headers: {
|
|
864
|
-
"Content-Type": "application/json"
|
|
865
|
-
|
|
866
|
-
|
|
865
|
+
"Content-Type": "application/json",
|
|
866
|
+
Origin: window.location.origin,
|
|
867
|
+
Referer: window.location.href
|
|
868
|
+
}
|
|
867
869
|
})).ok;
|
|
868
|
-
} catch (
|
|
869
|
-
const a =
|
|
870
|
-
return
|
|
870
|
+
} catch (i) {
|
|
871
|
+
const a = i instanceof Error ? i.message : String(i), o = a.includes("CORS") || a.includes("NotSameOrigin") || a.includes("blocked");
|
|
872
|
+
return n.error("SenderManager", "Failed to send events async", {
|
|
871
873
|
error: a,
|
|
872
874
|
isCorsError: o,
|
|
873
875
|
url: t.replace(/\/\/[^/]+/, "//[DOMAIN]")
|
|
@@ -875,22 +877,22 @@ class wt extends p {
|
|
|
875
877
|
}
|
|
876
878
|
}
|
|
877
879
|
sendQueueSync(e) {
|
|
878
|
-
const { url: t, payload: s } = this.prepareRequest(e);
|
|
879
|
-
return this.isSendBeaconAvailable() && navigator.sendBeacon(t,
|
|
880
|
+
const { url: t, payload: s } = this.prepareRequest(e), i = new Blob([s], { type: "application/json" });
|
|
881
|
+
return this.isSendBeaconAvailable() && navigator.sendBeacon(t, i) ? !0 : this.sendSyncXHR(t, s);
|
|
880
882
|
}
|
|
881
883
|
sendQueue(e) {
|
|
882
884
|
if (!this.isSendBeaconAvailable())
|
|
883
885
|
return !1;
|
|
884
|
-
const { url: t, payload: s } = this.prepareRequest(e);
|
|
885
|
-
return navigator.sendBeacon(t,
|
|
886
|
+
const { url: t, payload: s } = this.prepareRequest(e), i = new Blob([s], { type: "application/json" });
|
|
887
|
+
return navigator.sendBeacon(t, i);
|
|
886
888
|
}
|
|
887
889
|
sendSyncXHR(e, t) {
|
|
888
890
|
const s = new XMLHttpRequest();
|
|
889
891
|
try {
|
|
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 (
|
|
892
|
-
const a =
|
|
893
|
-
return
|
|
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 (i) {
|
|
894
|
+
const a = i instanceof Error ? i.message : String(i), o = a.includes("CORS") || a.includes("NotSameOrigin") || a.includes("blocked");
|
|
895
|
+
return n.error("SenderManager", "Sync XHR failed", {
|
|
894
896
|
error: a,
|
|
895
897
|
isCorsError: o,
|
|
896
898
|
status: s.status ?? "unknown",
|
|
@@ -921,7 +923,7 @@ class wt extends p {
|
|
|
921
923
|
};
|
|
922
924
|
}
|
|
923
925
|
logQueue(e) {
|
|
924
|
-
|
|
926
|
+
n.info("SenderManager", " ⏩ Queue snapshot", e);
|
|
925
927
|
}
|
|
926
928
|
handleSendFailure(e) {
|
|
927
929
|
this.persistFailedEvents(e), this.scheduleRetry(e);
|
|
@@ -938,7 +940,7 @@ class wt extends p {
|
|
|
938
940
|
};
|
|
939
941
|
this.storeManager.setItem(this.queueStorageKey, JSON.stringify(t));
|
|
940
942
|
} catch (t) {
|
|
941
|
-
|
|
943
|
+
n.error("SenderManager", "Failed to persist events", { error: t });
|
|
942
944
|
}
|
|
943
945
|
}
|
|
944
946
|
clearPersistedEvents() {
|
|
@@ -956,21 +958,21 @@ class wt extends p {
|
|
|
956
958
|
if (this.shouldSkipSend())
|
|
957
959
|
return this.logQueue(e), !0;
|
|
958
960
|
if (!this.canSendAsync())
|
|
959
|
-
return
|
|
961
|
+
return n.info("SenderManager", "⏱️ Rate limited - skipping async send", {
|
|
960
962
|
eventsCount: e.events.length,
|
|
961
963
|
timeSinceLastSend: Date.now() - this.lastAsyncSend
|
|
962
964
|
}), !1;
|
|
963
|
-
|
|
965
|
+
n.info("SenderManager", "🌐 Sending events to server (async)", {
|
|
964
966
|
eventsCount: e.events.length,
|
|
965
967
|
sessionId: e.session_id,
|
|
966
968
|
userId: e.user_id
|
|
967
969
|
}), this.lastAsyncSend = Date.now();
|
|
968
970
|
try {
|
|
969
971
|
const s = await t();
|
|
970
|
-
return s ? (
|
|
972
|
+
return s ? (n.info("SenderManager", "✅ Successfully sent events to server", {
|
|
971
973
|
eventsCount: e.events.length,
|
|
972
974
|
method: "async"
|
|
973
|
-
}), this.resetRetryState(), this.clearPersistedEvents()) : (
|
|
975
|
+
}), this.resetRetryState(), this.clearPersistedEvents()) : (n.warn("SenderManager", "Failed to send events", {
|
|
974
976
|
eventsCount: e.events.length,
|
|
975
977
|
method: "async"
|
|
976
978
|
}), this.handleSendFailure(e)), s;
|
|
@@ -982,11 +984,11 @@ class wt extends p {
|
|
|
982
984
|
if (this.shouldSkipSend())
|
|
983
985
|
return this.logQueue(e), !0;
|
|
984
986
|
if (!this.canSendSync())
|
|
985
|
-
return
|
|
987
|
+
return n.info("SenderManager", "⏱️ Rate limited - skipping sync send", {
|
|
986
988
|
eventsCount: e.events.length,
|
|
987
989
|
timeSinceLastSend: Date.now() - this.lastSyncSend
|
|
988
990
|
}), !1;
|
|
989
|
-
|
|
991
|
+
n.info("SenderManager", "🌐 Sending events to server (sync)", {
|
|
990
992
|
eventsCount: e.events.length,
|
|
991
993
|
sessionId: e.session_id,
|
|
992
994
|
userId: e.user_id,
|
|
@@ -994,15 +996,15 @@ class wt extends p {
|
|
|
994
996
|
}), this.lastSyncSend = Date.now();
|
|
995
997
|
try {
|
|
996
998
|
const s = t();
|
|
997
|
-
return s ? (
|
|
999
|
+
return s ? (n.info("SenderManager", "✅ Successfully sent events to server", {
|
|
998
1000
|
eventsCount: e.events.length,
|
|
999
1001
|
method: "sync"
|
|
1000
|
-
}), this.resetRetryState(), this.clearPersistedEvents()) : (
|
|
1002
|
+
}), this.resetRetryState(), this.clearPersistedEvents()) : (n.warn("SenderManager", "Failed to send events", {
|
|
1001
1003
|
eventsCount: e.events.length,
|
|
1002
1004
|
method: "sync"
|
|
1003
1005
|
}), this.handleSendFailure(e)), s;
|
|
1004
1006
|
} catch {
|
|
1005
|
-
return
|
|
1007
|
+
return n.info("SenderManager", "💥 Exception during event sending", {
|
|
1006
1008
|
eventsCount: e.events.length,
|
|
1007
1009
|
method: "sync"
|
|
1008
1010
|
}), this.handleSendFailure(e), !1;
|
|
@@ -1028,17 +1030,17 @@ class It extends p {
|
|
|
1028
1030
|
return e >= 1 ? !0 : e <= 0 ? !1 : this.getHash(this.get("userId")) % 100 / 100 < e;
|
|
1029
1031
|
}
|
|
1030
1032
|
isWebVitalEventSampledIn(e) {
|
|
1031
|
-
const t = e === "LONG_TASK", s = t ? De :
|
|
1033
|
+
const t = e === "LONG_TASK", s = t ? De : Pe;
|
|
1032
1034
|
if (s >= 1) return !0;
|
|
1033
1035
|
if (s <= 0) return !1;
|
|
1034
|
-
const
|
|
1035
|
-
return this.getHash(
|
|
1036
|
+
const i = `${this.get("userId")}|${t ? "long_task" : "web_vitals"}`;
|
|
1037
|
+
return this.getHash(i) % 100 / 100 < s;
|
|
1036
1038
|
}
|
|
1037
1039
|
getHash(e) {
|
|
1038
1040
|
let t = 0;
|
|
1039
1041
|
for (let s = 0; s < e.length; s++) {
|
|
1040
|
-
const
|
|
1041
|
-
t = (t << 5) - t +
|
|
1042
|
+
const i = e.charCodeAt(s);
|
|
1043
|
+
t = (t << 5) - t + i, t |= 0;
|
|
1042
1044
|
}
|
|
1043
1045
|
return Math.abs(t);
|
|
1044
1046
|
}
|
|
@@ -1058,7 +1060,7 @@ class Tt extends p {
|
|
|
1058
1060
|
const s = this.get("config")?.tags?.filter((a) => a.triggerType === h.PAGE_VIEW) ?? [];
|
|
1059
1061
|
if (s.length === 0)
|
|
1060
1062
|
return [];
|
|
1061
|
-
const
|
|
1063
|
+
const i = [];
|
|
1062
1064
|
for (const a of s) {
|
|
1063
1065
|
const { id: o, logicalOperator: l, conditions: c } = a, d = [];
|
|
1064
1066
|
for (const g of c)
|
|
@@ -1085,15 +1087,15 @@ class Tt extends p {
|
|
|
1085
1087
|
}
|
|
1086
1088
|
}
|
|
1087
1089
|
let u = !1;
|
|
1088
|
-
u = l === G.AND ? d.every(Boolean) : d.some(Boolean), u &&
|
|
1090
|
+
u = l === G.AND ? d.every(Boolean) : d.some(Boolean), u && i.push(o);
|
|
1089
1091
|
}
|
|
1090
|
-
return
|
|
1092
|
+
return i;
|
|
1091
1093
|
}
|
|
1092
1094
|
checkEventTypeClick(e, t) {
|
|
1093
1095
|
const s = this.get("config")?.tags?.filter((a) => a.triggerType === h.CLICK) ?? [];
|
|
1094
1096
|
if (s.length === 0)
|
|
1095
1097
|
return [];
|
|
1096
|
-
const
|
|
1098
|
+
const i = [];
|
|
1097
1099
|
for (const a of s) {
|
|
1098
1100
|
const { id: o, logicalOperator: l, conditions: c } = a, d = [];
|
|
1099
1101
|
for (const g of c) {
|
|
@@ -1130,26 +1132,26 @@ class Tt extends p {
|
|
|
1130
1132
|
}
|
|
1131
1133
|
}
|
|
1132
1134
|
let u = !1;
|
|
1133
|
-
u = l === G.AND ? d.every(Boolean) : d.some(Boolean), u &&
|
|
1135
|
+
u = l === G.AND ? d.every(Boolean) : d.some(Boolean), u && i.push(o);
|
|
1134
1136
|
}
|
|
1135
|
-
return
|
|
1137
|
+
return i;
|
|
1136
1138
|
}
|
|
1137
1139
|
matchUrlMatches(e, t) {
|
|
1138
1140
|
if (e.type !== m.URL_MATCHES)
|
|
1139
1141
|
return !1;
|
|
1140
|
-
const s = e.value.toLowerCase(),
|
|
1142
|
+
const s = e.value.toLowerCase(), i = t.toLowerCase();
|
|
1141
1143
|
switch (e.operator) {
|
|
1142
1144
|
case f.EQUALS:
|
|
1143
|
-
return
|
|
1145
|
+
return i === s;
|
|
1144
1146
|
case f.CONTAINS:
|
|
1145
|
-
return
|
|
1147
|
+
return i.includes(s);
|
|
1146
1148
|
case f.STARTS_WITH:
|
|
1147
|
-
return
|
|
1149
|
+
return i.startsWith(s);
|
|
1148
1150
|
case f.ENDS_WITH:
|
|
1149
|
-
return
|
|
1151
|
+
return i.endsWith(s);
|
|
1150
1152
|
case f.REGEX:
|
|
1151
1153
|
try {
|
|
1152
|
-
return new RegExp(s, "gi").test(
|
|
1154
|
+
return new RegExp(s, "gi").test(i);
|
|
1153
1155
|
} catch {
|
|
1154
1156
|
return !1;
|
|
1155
1157
|
}
|
|
@@ -1160,19 +1162,19 @@ class Tt extends p {
|
|
|
1160
1162
|
matchDeviceType(e, t) {
|
|
1161
1163
|
if (e.type !== m.DEVICE_TYPE)
|
|
1162
1164
|
return !1;
|
|
1163
|
-
const s = e.value.toLowerCase(),
|
|
1165
|
+
const s = e.value.toLowerCase(), i = t.toLowerCase();
|
|
1164
1166
|
switch (e.operator) {
|
|
1165
1167
|
case f.EQUALS:
|
|
1166
|
-
return
|
|
1168
|
+
return i === s;
|
|
1167
1169
|
case f.CONTAINS:
|
|
1168
|
-
return
|
|
1170
|
+
return i.includes(s);
|
|
1169
1171
|
case f.STARTS_WITH:
|
|
1170
|
-
return
|
|
1172
|
+
return i.startsWith(s);
|
|
1171
1173
|
case f.ENDS_WITH:
|
|
1172
|
-
return
|
|
1174
|
+
return i.endsWith(s);
|
|
1173
1175
|
case f.REGEX:
|
|
1174
1176
|
try {
|
|
1175
|
-
return new RegExp(s, "gi").test(
|
|
1177
|
+
return new RegExp(s, "gi").test(i);
|
|
1176
1178
|
} catch {
|
|
1177
1179
|
return !1;
|
|
1178
1180
|
}
|
|
@@ -1194,19 +1196,19 @@ class Tt extends p {
|
|
|
1194
1196
|
t.role ?? "",
|
|
1195
1197
|
t.ariaLabel ?? "",
|
|
1196
1198
|
...Object.values(t.dataAttributes ?? {})
|
|
1197
|
-
].join(" "),
|
|
1199
|
+
].join(" "), i = e.value.toLowerCase(), a = s.toLowerCase();
|
|
1198
1200
|
switch (e.operator) {
|
|
1199
1201
|
case f.EQUALS:
|
|
1200
|
-
return this.checkElementFieldEquals(t,
|
|
1202
|
+
return this.checkElementFieldEquals(t, i);
|
|
1201
1203
|
case f.CONTAINS:
|
|
1202
|
-
return a.includes(
|
|
1204
|
+
return a.includes(i);
|
|
1203
1205
|
case f.STARTS_WITH:
|
|
1204
|
-
return a.startsWith(
|
|
1206
|
+
return a.startsWith(i);
|
|
1205
1207
|
case f.ENDS_WITH:
|
|
1206
|
-
return a.endsWith(
|
|
1208
|
+
return a.endsWith(i);
|
|
1207
1209
|
case f.REGEX:
|
|
1208
1210
|
try {
|
|
1209
|
-
return new RegExp(
|
|
1211
|
+
return new RegExp(i, "gi").test(a);
|
|
1210
1212
|
} catch {
|
|
1211
1213
|
return !1;
|
|
1212
1214
|
}
|
|
@@ -1219,19 +1221,19 @@ class Tt extends p {
|
|
|
1219
1221
|
e.type
|
|
1220
1222
|
))
|
|
1221
1223
|
return !1;
|
|
1222
|
-
const s = t ?? "",
|
|
1224
|
+
const s = t ?? "", i = e.value.toLowerCase(), a = s.toLowerCase();
|
|
1223
1225
|
switch (e.operator) {
|
|
1224
1226
|
case f.EQUALS:
|
|
1225
|
-
return a ===
|
|
1227
|
+
return a === i;
|
|
1226
1228
|
case f.CONTAINS:
|
|
1227
|
-
return a.includes(
|
|
1229
|
+
return a.includes(i);
|
|
1228
1230
|
case f.STARTS_WITH:
|
|
1229
|
-
return a.startsWith(
|
|
1231
|
+
return a.startsWith(i);
|
|
1230
1232
|
case f.ENDS_WITH:
|
|
1231
|
-
return a.endsWith(
|
|
1233
|
+
return a.endsWith(i);
|
|
1232
1234
|
case f.REGEX:
|
|
1233
1235
|
try {
|
|
1234
|
-
return new RegExp(
|
|
1236
|
+
return new RegExp(i, "gi").test(a);
|
|
1235
1237
|
} catch {
|
|
1236
1238
|
return !1;
|
|
1237
1239
|
}
|
|
@@ -1251,15 +1253,15 @@ class Tt extends p {
|
|
|
1251
1253
|
e.role,
|
|
1252
1254
|
e.ariaLabel
|
|
1253
1255
|
];
|
|
1254
|
-
for (const
|
|
1255
|
-
if (
|
|
1256
|
-
const a =
|
|
1256
|
+
for (const i of s)
|
|
1257
|
+
if (i) {
|
|
1258
|
+
const a = i.toLowerCase(), o = t.toLowerCase();
|
|
1257
1259
|
if (a === o)
|
|
1258
1260
|
return !0;
|
|
1259
1261
|
}
|
|
1260
1262
|
if (e.dataAttributes)
|
|
1261
|
-
for (const
|
|
1262
|
-
const a =
|
|
1263
|
+
for (const i of Object.values(e.dataAttributes)) {
|
|
1264
|
+
const a = i.toLowerCase(), o = t.toLowerCase();
|
|
1263
1265
|
if (a === o)
|
|
1264
1266
|
return !0;
|
|
1265
1267
|
}
|
|
@@ -1288,7 +1290,7 @@ class Mt extends p {
|
|
|
1288
1290
|
// Persistence storage key
|
|
1289
1291
|
PERSISTENCE_KEY = "tl:circuit_breaker_events";
|
|
1290
1292
|
constructor(e, t = null) {
|
|
1291
|
-
super(), this.storageManager = e, this.googleAnalytics = t, this.samplingManager = new It(), this.tagsManager = new Tt(), this.dataSender = new wt(e), this.restoreEventsFromStorage(),
|
|
1293
|
+
super(), this.storageManager = e, this.googleAnalytics = t, this.samplingManager = new It(), this.tagsManager = new Tt(), this.dataSender = new wt(e), this.restoreEventsFromStorage(), n.debug("EventManager", "EventManager initialized", {
|
|
1292
1294
|
hasGoogleAnalytics: !!t,
|
|
1293
1295
|
restoredEventsCount: this.eventsQueue.length
|
|
1294
1296
|
});
|
|
@@ -1297,28 +1299,28 @@ class Mt extends p {
|
|
|
1297
1299
|
type: e,
|
|
1298
1300
|
page_url: t,
|
|
1299
1301
|
from_page_url: s,
|
|
1300
|
-
scroll_data:
|
|
1302
|
+
scroll_data: i,
|
|
1301
1303
|
click_data: a,
|
|
1302
1304
|
custom_event: o,
|
|
1303
1305
|
web_vitals: l,
|
|
1304
1306
|
session_end_reason: c,
|
|
1305
1307
|
session_start_recovered: d
|
|
1306
1308
|
}) {
|
|
1307
|
-
if (
|
|
1309
|
+
if (n.info("EventManager", `📥 Event captured: ${e}`, {
|
|
1308
1310
|
type: e,
|
|
1309
1311
|
page_url: t,
|
|
1310
1312
|
hasCustomEvent: !!o,
|
|
1311
1313
|
hasClickData: !!a,
|
|
1312
|
-
hasScrollData: !!
|
|
1314
|
+
hasScrollData: !!i,
|
|
1313
1315
|
hasWebVitals: !!l
|
|
1314
1316
|
}), !this.samplingManager.shouldSampleEvent(e, l)) {
|
|
1315
|
-
|
|
1317
|
+
n.debug("EventManager", "Event filtered by sampling", { type: e, samplingActive: !0 });
|
|
1316
1318
|
return;
|
|
1317
1319
|
}
|
|
1318
1320
|
if (this.isDuplicatedEvent({
|
|
1319
1321
|
type: e,
|
|
1320
1322
|
page_url: t,
|
|
1321
|
-
scroll_data:
|
|
1323
|
+
scroll_data: i,
|
|
1322
1324
|
click_data: a,
|
|
1323
1325
|
custom_event: o,
|
|
1324
1326
|
web_vitals: l,
|
|
@@ -1327,10 +1329,10 @@ class Mt extends p {
|
|
|
1327
1329
|
})) {
|
|
1328
1330
|
const k = Date.now();
|
|
1329
1331
|
if (this.eventsQueue && this.eventsQueue.length > 0) {
|
|
1330
|
-
const
|
|
1331
|
-
|
|
1332
|
+
const H = this.eventsQueue.at(-1);
|
|
1333
|
+
H && (H.timestamp = k);
|
|
1332
1334
|
}
|
|
1333
|
-
this.lastEvent && (this.lastEvent.timestamp = k),
|
|
1335
|
+
this.lastEvent && (this.lastEvent.timestamp = k), n.debug("EventManager", "Duplicate event detected, timestamp updated", {
|
|
1334
1336
|
type: e,
|
|
1335
1337
|
queueLength: this.eventsQueue.length
|
|
1336
1338
|
});
|
|
@@ -1338,7 +1340,7 @@ class Mt extends p {
|
|
|
1338
1340
|
}
|
|
1339
1341
|
const g = t || this.get("pageUrl"), y = yt(g, this.get("config").excludedUrlPaths), I = this.get("hasStartSession"), A = e == h.SESSION_END;
|
|
1340
1342
|
if (y && (!A || A && !I)) {
|
|
1341
|
-
(this.get("config")?.mode === "qa" || this.get("config")?.mode === "debug") &&
|
|
1343
|
+
(this.get("config")?.mode === "qa" || this.get("config")?.mode === "debug") && n.debug("EventManager", `Event ${e} on excluded route: ${t}`);
|
|
1342
1344
|
return;
|
|
1343
1345
|
}
|
|
1344
1346
|
const U = e === h.SESSION_START;
|
|
@@ -1349,7 +1351,7 @@ class Mt extends p {
|
|
|
1349
1351
|
timestamp: Date.now(),
|
|
1350
1352
|
...U && { referrer: document.referrer || "Direct" },
|
|
1351
1353
|
...s && !y ? { from_page_url: s } : {},
|
|
1352
|
-
...
|
|
1354
|
+
...i && { scroll_data: i },
|
|
1353
1355
|
...a && { click_data: a },
|
|
1354
1356
|
...o && { custom_event: o },
|
|
1355
1357
|
...ie && { utm: ie },
|
|
@@ -1359,9 +1361,9 @@ class Mt extends p {
|
|
|
1359
1361
|
};
|
|
1360
1362
|
if (this.get("config")?.tags?.length) {
|
|
1361
1363
|
const k = this.tagsManager.getEventTagsIds(O, this.get("device"));
|
|
1362
|
-
k?.length && (O.tags = this.get("config")?.mode === "qa" || this.get("config")?.mode === "debug" ? k.map((
|
|
1363
|
-
id:
|
|
1364
|
-
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 ?? ""
|
|
1365
1367
|
})) : k);
|
|
1366
1368
|
}
|
|
1367
1369
|
this.lastEvent = O, this.processAndSend(O);
|
|
@@ -1370,24 +1372,24 @@ class Mt extends p {
|
|
|
1370
1372
|
this.eventsQueueIntervalId && (clearInterval(this.eventsQueueIntervalId), this.eventsQueueIntervalId = null, this.intervalActive = !1), this.circuitResetTimeoutId && (clearTimeout(this.circuitResetTimeoutId), this.circuitResetTimeoutId = null), this.eventsQueue.length > 0 && this.persistEventsToStorage(), this.eventFingerprints.clear(), this.circuitOpen = !1, this.circuitOpenTime = 0, this.failureCount = 0, this.backoffDelay = b.INITIAL_BACKOFF_DELAY_MS, this.lastEvent = null, this.dataSender.stop();
|
|
1371
1373
|
}
|
|
1372
1374
|
processAndSend(e) {
|
|
1373
|
-
if (
|
|
1375
|
+
if (n.info("EventManager", `🔄 Event processed and queued: ${e.type}`, {
|
|
1374
1376
|
type: e.type,
|
|
1375
1377
|
timestamp: e.timestamp,
|
|
1376
1378
|
page_url: e.page_url,
|
|
1377
1379
|
queueLengthBefore: this.eventsQueue.length
|
|
1378
1380
|
}), this.get("config").ipExcluded) {
|
|
1379
|
-
|
|
1381
|
+
n.info("EventManager", "❌ Event blocked: IP excluded");
|
|
1380
1382
|
return;
|
|
1381
1383
|
}
|
|
1382
1384
|
if (this.eventsQueue.push(e), this.eventsQueue.length > ne) {
|
|
1383
1385
|
const t = this.eventsQueue.shift();
|
|
1384
|
-
|
|
1386
|
+
n.warn("EventManager", "Event queue overflow, oldest event removed", {
|
|
1385
1387
|
maxLength: ne,
|
|
1386
1388
|
currentLength: this.eventsQueue.length,
|
|
1387
1389
|
removedEventType: t?.type
|
|
1388
1390
|
});
|
|
1389
1391
|
}
|
|
1390
|
-
if (this.eventsQueueIntervalId || (this.initEventsQueueInterval(),
|
|
1392
|
+
if (this.eventsQueueIntervalId || (this.initEventsQueueInterval(), n.info("EventManager", "⏰ Event sender initialized - queue will be sent periodically", {
|
|
1391
1393
|
queueLength: this.eventsQueue.length
|
|
1392
1394
|
})), this.googleAnalytics && e.type === h.CUSTOM) {
|
|
1393
1395
|
const t = e.custom_event;
|
|
@@ -1395,7 +1397,7 @@ class Mt extends p {
|
|
|
1395
1397
|
}
|
|
1396
1398
|
}
|
|
1397
1399
|
trackGoogleAnalyticsEvent(e) {
|
|
1398
|
-
this.get("config").mode === "qa" || this.get("config").mode === "debug" ?
|
|
1400
|
+
this.get("config").mode === "qa" || this.get("config").mode === "debug" ? n.debug("EventManager", `Google Analytics event: ${JSON.stringify(e)}`) : this.googleAnalytics && this.googleAnalytics.trackEvent(e.name, e.metadata ?? {});
|
|
1399
1401
|
}
|
|
1400
1402
|
initEventsQueueInterval() {
|
|
1401
1403
|
if (this.eventsQueueIntervalId || this.intervalActive)
|
|
@@ -1423,19 +1425,19 @@ class Mt extends p {
|
|
|
1423
1425
|
sendEventsQueue() {
|
|
1424
1426
|
if (this.eventsQueue.length === 0)
|
|
1425
1427
|
return;
|
|
1426
|
-
if (
|
|
1428
|
+
if (n.info("EventManager", "📤 Preparing to send event queue", {
|
|
1427
1429
|
queueLength: this.eventsQueue.length,
|
|
1428
1430
|
hasSessionId: !!this.get("sessionId"),
|
|
1429
1431
|
circuitOpen: this.circuitOpen
|
|
1430
1432
|
}), this.circuitOpen) {
|
|
1431
1433
|
const s = Date.now() - this.circuitOpenTime;
|
|
1432
1434
|
if (s >= b.RECOVERY_TIME_MS)
|
|
1433
|
-
this.resetCircuitBreaker(),
|
|
1435
|
+
this.resetCircuitBreaker(), n.info("EventManager", "Circuit breaker reset after timeout", {
|
|
1434
1436
|
timeSinceOpen: s,
|
|
1435
1437
|
recoveryTime: b.RECOVERY_TIME_MS
|
|
1436
1438
|
});
|
|
1437
1439
|
else {
|
|
1438
|
-
|
|
1440
|
+
n.debug("EventManager", "Circuit breaker is open - skipping event sending", {
|
|
1439
1441
|
queueLength: this.eventsQueue.length,
|
|
1440
1442
|
failureCount: this.failureCount,
|
|
1441
1443
|
timeSinceOpen: s,
|
|
@@ -1445,15 +1447,15 @@ class Mt extends p {
|
|
|
1445
1447
|
}
|
|
1446
1448
|
}
|
|
1447
1449
|
if (!this.get("sessionId")) {
|
|
1448
|
-
|
|
1450
|
+
n.info("EventManager", `⏳ Queue waiting: ${this.eventsQueue.length} events waiting for active session`);
|
|
1449
1451
|
return;
|
|
1450
1452
|
}
|
|
1451
1453
|
const e = this.buildEventsPayload();
|
|
1452
|
-
this.dataSender.sendEventsQueue(e) ? (
|
|
1454
|
+
this.dataSender.sendEventsQueue(e) ? (n.info("EventManager", "✅ Event queue sent successfully", {
|
|
1453
1455
|
eventsCount: e.events.length,
|
|
1454
1456
|
sessionId: e.session_id,
|
|
1455
1457
|
uniqueEventsAfterDedup: e.events.length
|
|
1456
|
-
}), this.eventsQueue = [], this.failureCount = 0, this.backoffDelay = b.INITIAL_BACKOFF_DELAY_MS, this.clearPersistedEvents()) : (
|
|
1458
|
+
}), this.eventsQueue = [], this.failureCount = 0, this.backoffDelay = b.INITIAL_BACKOFF_DELAY_MS, this.clearPersistedEvents()) : (n.info("EventManager", "❌ Failed to send event queue", {
|
|
1457
1459
|
eventsCount: e.events.length,
|
|
1458
1460
|
failureCount: this.failureCount + 1,
|
|
1459
1461
|
willOpenCircuit: this.failureCount + 1 >= this.MAX_FAILURES
|
|
@@ -1462,11 +1464,11 @@ class Mt extends p {
|
|
|
1462
1464
|
buildEventsPayload() {
|
|
1463
1465
|
const e = /* @__PURE__ */ new Map();
|
|
1464
1466
|
for (const s of this.eventsQueue) {
|
|
1465
|
-
let
|
|
1466
|
-
s.click_data && (
|
|
1467
|
+
let i = `${s.type}_${s.page_url}`;
|
|
1468
|
+
s.click_data && (i += `_${s.click_data.x}_${s.click_data.y}`), s.scroll_data && (i += `_${s.scroll_data.depth}_${s.scroll_data.direction}`), s.custom_event && (i += `_${s.custom_event.name}`), s.web_vitals && (i += `_${s.web_vitals.type}`), e.has(i) || e.set(i, s);
|
|
1467
1469
|
}
|
|
1468
1470
|
const t = [...e.values()];
|
|
1469
|
-
return t.sort((s,
|
|
1471
|
+
return t.sort((s, i) => s.timestamp - i.timestamp), {
|
|
1470
1472
|
user_id: this.get("userId"),
|
|
1471
1473
|
session_id: this.get("sessionId"),
|
|
1472
1474
|
device: this.get("device"),
|
|
@@ -1480,14 +1482,14 @@ class Mt extends p {
|
|
|
1480
1482
|
getEventFingerprint(e) {
|
|
1481
1483
|
const t = `${e.type}_${e.page_url}`;
|
|
1482
1484
|
if (e.click_data) {
|
|
1483
|
-
const s = Math.round((e.click_data.x || 0) / F) * F,
|
|
1484
|
-
return `${t}_${s}_${
|
|
1485
|
+
const s = Math.round((e.click_data.x || 0) / F) * F, i = Math.round((e.click_data.y || 0) / F) * F;
|
|
1486
|
+
return `${t}_${s}_${i}_${e.click_data.tag}_${e.click_data.id}`;
|
|
1485
1487
|
}
|
|
1486
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;
|
|
1487
1489
|
}
|
|
1488
1490
|
isDuplicatedEvent(e) {
|
|
1489
|
-
const t = this.getEventFingerprint(e), s = this.eventFingerprints.get(t) ?? 0,
|
|
1490
|
-
return
|
|
1491
|
+
const t = this.getEventFingerprint(e), s = this.eventFingerprints.get(t) ?? 0, i = Date.now();
|
|
1492
|
+
return i - s < de ? !0 : (this.eventFingerprints.set(t, i), this.cleanupOldFingerprints(), !1);
|
|
1491
1493
|
}
|
|
1492
1494
|
/**
|
|
1493
1495
|
* Cleans up old fingerprints to prevent memory leaks
|
|
@@ -1496,11 +1498,11 @@ class Mt extends p {
|
|
|
1496
1498
|
if (this.eventFingerprints.size <= Oe)
|
|
1497
1499
|
return;
|
|
1498
1500
|
const e = Date.now(), t = de * Fe, s = [];
|
|
1499
|
-
for (const [
|
|
1500
|
-
e - a > t && s.push(
|
|
1501
|
-
for (const
|
|
1502
|
-
this.eventFingerprints.delete(
|
|
1503
|
-
|
|
1501
|
+
for (const [i, a] of this.eventFingerprints)
|
|
1502
|
+
e - a > t && s.push(i);
|
|
1503
|
+
for (const i of s)
|
|
1504
|
+
this.eventFingerprints.delete(i);
|
|
1505
|
+
n.debug("EventManager", "Cleaned up old event fingerprints", {
|
|
1504
1506
|
totalFingerprints: this.eventFingerprints.size + s.length,
|
|
1505
1507
|
cleanedCount: s.length,
|
|
1506
1508
|
remainingCount: this.eventFingerprints.size,
|
|
@@ -1513,7 +1515,7 @@ class Mt extends p {
|
|
|
1513
1515
|
openCircuitBreaker() {
|
|
1514
1516
|
this.circuitOpen = !0, this.circuitOpenTime = Date.now(), this.persistEventsToStorage();
|
|
1515
1517
|
const e = this.eventsQueue.length;
|
|
1516
|
-
this.eventsQueue = [],
|
|
1518
|
+
this.eventsQueue = [], n.warn("EventManager", "Circuit breaker opened with time-based recovery", {
|
|
1517
1519
|
maxFailures: this.MAX_FAILURES,
|
|
1518
1520
|
persistedEvents: e,
|
|
1519
1521
|
failureCount: this.failureCount,
|
|
@@ -1528,9 +1530,9 @@ class Mt extends p {
|
|
|
1528
1530
|
* Resets the circuit breaker and attempts to restore persisted events
|
|
1529
1531
|
*/
|
|
1530
1532
|
resetCircuitBreaker() {
|
|
1531
|
-
this.circuitOpen = !1, this.circuitOpenTime = 0, this.failureCount = 0, this.circuitResetTimeoutId = null,
|
|
1533
|
+
this.circuitOpen = !1, this.circuitOpenTime = 0, this.failureCount = 0, this.circuitResetTimeoutId = null, n.info("EventManager", "Circuit breaker reset - attempting to restore events", {
|
|
1532
1534
|
currentQueueLength: this.eventsQueue.length
|
|
1533
|
-
}), this.restoreEventsFromStorage(),
|
|
1535
|
+
}), this.restoreEventsFromStorage(), n.info("EventManager", "Circuit breaker reset completed", {
|
|
1534
1536
|
restoredQueueLength: this.eventsQueue.length,
|
|
1535
1537
|
backoffDelay: this.backoffDelay
|
|
1536
1538
|
});
|
|
@@ -1547,12 +1549,12 @@ class Mt extends p {
|
|
|
1547
1549
|
timestamp: Date.now(),
|
|
1548
1550
|
failureCount: this.failureCount
|
|
1549
1551
|
};
|
|
1550
|
-
this.storageManager.setItem(this.PERSISTENCE_KEY, JSON.stringify(e)),
|
|
1552
|
+
this.storageManager.setItem(this.PERSISTENCE_KEY, JSON.stringify(e)), n.debug("EventManager", "Events persisted to storage for recovery", {
|
|
1551
1553
|
eventsCount: this.eventsQueue.length,
|
|
1552
1554
|
failureCount: this.failureCount
|
|
1553
1555
|
});
|
|
1554
1556
|
} catch (e) {
|
|
1555
|
-
|
|
1557
|
+
n.warn("EventManager", "Failed to persist events to storage", {
|
|
1556
1558
|
error: e instanceof Error ? e.message : "Unknown error",
|
|
1557
1559
|
eventsCount: this.eventsQueue.length
|
|
1558
1560
|
});
|
|
@@ -1566,20 +1568,20 @@ class Mt extends p {
|
|
|
1566
1568
|
const e = this.storageManager.getItem(this.PERSISTENCE_KEY);
|
|
1567
1569
|
if (!e)
|
|
1568
1570
|
return;
|
|
1569
|
-
const t = JSON.parse(e), s = Date.now(),
|
|
1570
|
-
if (s - t.timestamp >
|
|
1571
|
-
this.clearPersistedEvents(),
|
|
1571
|
+
const t = JSON.parse(e), s = Date.now(), i = Qe;
|
|
1572
|
+
if (s - t.timestamp > i) {
|
|
1573
|
+
this.clearPersistedEvents(), n.debug("EventManager", "Cleared expired persisted events", {
|
|
1572
1574
|
age: s - t.timestamp,
|
|
1573
|
-
maxAge:
|
|
1575
|
+
maxAge: i
|
|
1574
1576
|
});
|
|
1575
1577
|
return;
|
|
1576
1578
|
}
|
|
1577
|
-
Array.isArray(t.events) && t.events.length > 0 && this.eventsQueue.length === 0 && (this.eventsQueue = t.events,
|
|
1579
|
+
Array.isArray(t.events) && t.events.length > 0 && this.eventsQueue.length === 0 && (this.eventsQueue = t.events, n.info("EventManager", "Restored events from storage", {
|
|
1578
1580
|
restoredCount: t.events.length,
|
|
1579
1581
|
originalFailureCount: t.failureCount ?? 0
|
|
1580
1582
|
}));
|
|
1581
1583
|
} catch (e) {
|
|
1582
|
-
|
|
1584
|
+
n.warn("EventManager", "Failed to restore events from storage", {
|
|
1583
1585
|
error: e instanceof Error ? e.message : "Unknown error"
|
|
1584
1586
|
}), this.clearPersistedEvents();
|
|
1585
1587
|
}
|
|
@@ -1589,9 +1591,9 @@ class Mt extends p {
|
|
|
1589
1591
|
*/
|
|
1590
1592
|
clearPersistedEvents() {
|
|
1591
1593
|
try {
|
|
1592
|
-
this.storageManager.removeItem(this.PERSISTENCE_KEY),
|
|
1594
|
+
this.storageManager.removeItem(this.PERSISTENCE_KEY), n.debug("EventManager", "Cleared persisted events from storage");
|
|
1593
1595
|
} catch (e) {
|
|
1594
|
-
|
|
1596
|
+
n.warn("EventManager", "Failed to clear persisted events", {
|
|
1595
1597
|
error: e instanceof Error ? e.message : "Unknown error"
|
|
1596
1598
|
});
|
|
1597
1599
|
}
|
|
@@ -1620,14 +1622,14 @@ class _t {
|
|
|
1620
1622
|
try {
|
|
1621
1623
|
window.addEventListener("scroll", this.onActivity, this.options), window.addEventListener("resize", this.onActivity, this.options), window.addEventListener("focus", this.onActivity, this.options);
|
|
1622
1624
|
} catch (e) {
|
|
1623
|
-
throw
|
|
1625
|
+
throw n.error("ActivityListenerManager", "Failed to setup activity listeners", { error: e }), e;
|
|
1624
1626
|
}
|
|
1625
1627
|
}
|
|
1626
1628
|
cleanup() {
|
|
1627
1629
|
try {
|
|
1628
1630
|
window.removeEventListener("scroll", this.onActivity), window.removeEventListener("resize", this.onActivity), window.removeEventListener("focus", this.onActivity);
|
|
1629
1631
|
} catch (e) {
|
|
1630
|
-
|
|
1632
|
+
n.warn("ActivityListenerManager", "Error during activity listeners cleanup", { error: e });
|
|
1631
1633
|
}
|
|
1632
1634
|
}
|
|
1633
1635
|
}
|
|
@@ -1642,14 +1644,14 @@ class Ct {
|
|
|
1642
1644
|
try {
|
|
1643
1645
|
window.addEventListener("touchstart", this.onActivity, this.options), window.addEventListener("touchmove", this.onActivity, this.options), window.addEventListener("touchend", this.onActivity, this.options), window.addEventListener("orientationchange", this.onActivity, this.options), "DeviceMotionEvent" in window && window.addEventListener("devicemotion", this.handleDeviceMotion, this.options);
|
|
1644
1646
|
} catch (e) {
|
|
1645
|
-
throw
|
|
1647
|
+
throw n.error("TouchListenerManager", "Failed to setup touch listeners", { error: e }), e;
|
|
1646
1648
|
}
|
|
1647
1649
|
}
|
|
1648
1650
|
cleanup() {
|
|
1649
1651
|
try {
|
|
1650
1652
|
window.removeEventListener("touchstart", this.onActivity), window.removeEventListener("touchmove", this.onActivity), window.removeEventListener("touchend", this.onActivity), window.removeEventListener("orientationchange", this.onActivity), "DeviceMotionEvent" in window && window.removeEventListener("devicemotion", this.handleDeviceMotion);
|
|
1651
1653
|
} catch (e) {
|
|
1652
|
-
|
|
1654
|
+
n.warn("TouchListenerManager", "Error during touch listeners cleanup", { error: e });
|
|
1653
1655
|
}
|
|
1654
1656
|
}
|
|
1655
1657
|
handleDeviceMotion = (e) => {
|
|
@@ -1657,7 +1659,7 @@ class Ct {
|
|
|
1657
1659
|
const t = e.acceleration;
|
|
1658
1660
|
t && Math.abs(t.x ?? 0) + Math.abs(t.y ?? 0) + Math.abs(t.z ?? 0) > this.motionThreshold && this.onActivity();
|
|
1659
1661
|
} catch (t) {
|
|
1660
|
-
|
|
1662
|
+
n.warn("TouchListenerManager", "Error handling device motion event", { error: t });
|
|
1661
1663
|
}
|
|
1662
1664
|
};
|
|
1663
1665
|
}
|
|
@@ -1671,14 +1673,14 @@ class Lt {
|
|
|
1671
1673
|
try {
|
|
1672
1674
|
window.addEventListener("mousemove", this.onActivity, this.options), window.addEventListener("mousedown", this.onActivity, this.options), window.addEventListener("wheel", this.onActivity, this.options);
|
|
1673
1675
|
} catch (e) {
|
|
1674
|
-
throw
|
|
1676
|
+
throw n.error("MouseListenerManager", "Failed to setup mouse listeners", { error: e }), e;
|
|
1675
1677
|
}
|
|
1676
1678
|
}
|
|
1677
1679
|
cleanup() {
|
|
1678
1680
|
try {
|
|
1679
1681
|
window.removeEventListener("mousemove", this.onActivity), window.removeEventListener("mousedown", this.onActivity), window.removeEventListener("wheel", this.onActivity);
|
|
1680
1682
|
} catch (e) {
|
|
1681
|
-
|
|
1683
|
+
n.warn("MouseListenerManager", "Error during mouse listeners cleanup", { error: e });
|
|
1682
1684
|
}
|
|
1683
1685
|
}
|
|
1684
1686
|
}
|
|
@@ -1692,14 +1694,14 @@ class Rt {
|
|
|
1692
1694
|
try {
|
|
1693
1695
|
window.addEventListener("keydown", this.onActivity, this.options), window.addEventListener("keypress", this.onActivity, this.options);
|
|
1694
1696
|
} catch (e) {
|
|
1695
|
-
throw
|
|
1697
|
+
throw n.error("KeyboardListenerManager", "Failed to setup keyboard listeners", { error: e }), e;
|
|
1696
1698
|
}
|
|
1697
1699
|
}
|
|
1698
1700
|
cleanup() {
|
|
1699
1701
|
try {
|
|
1700
1702
|
window.removeEventListener("keydown", this.onActivity), window.removeEventListener("keypress", this.onActivity);
|
|
1701
1703
|
} catch (e) {
|
|
1702
|
-
|
|
1704
|
+
n.warn("KeyboardListenerManager", "Error during keyboard listeners cleanup", { error: e });
|
|
1703
1705
|
}
|
|
1704
1706
|
}
|
|
1705
1707
|
}
|
|
@@ -1715,28 +1717,28 @@ class kt {
|
|
|
1715
1717
|
try {
|
|
1716
1718
|
"visibilityState" in document && document.addEventListener("visibilitychange", this.onVisibilityChange, this.options), window.addEventListener("blur", this.onVisibilityChange, this.options), window.addEventListener("focus", this.onActivity, this.options), "onLine" in navigator && (window.addEventListener("online", this.onActivity, this.options), window.addEventListener("offline", this.onVisibilityChange, this.options)), this.isMobile && this.setupMobileEvents();
|
|
1717
1719
|
} catch (e) {
|
|
1718
|
-
throw
|
|
1720
|
+
throw n.error("VisibilityListenerManager", "Failed to setup visibility listeners", { error: e }), e;
|
|
1719
1721
|
}
|
|
1720
1722
|
}
|
|
1721
1723
|
cleanup() {
|
|
1722
1724
|
try {
|
|
1723
1725
|
"visibilityState" in document && document.removeEventListener("visibilitychange", this.onVisibilityChange), window.removeEventListener("blur", this.onVisibilityChange), window.removeEventListener("focus", this.onActivity), "onLine" in navigator && (window.removeEventListener("online", this.onActivity), window.removeEventListener("offline", this.onVisibilityChange)), this.isMobile && this.cleanupMobileEvents();
|
|
1724
1726
|
} catch (e) {
|
|
1725
|
-
|
|
1727
|
+
n.warn("VisibilityListenerManager", "Error during visibility listeners cleanup", { error: e });
|
|
1726
1728
|
}
|
|
1727
1729
|
}
|
|
1728
1730
|
setupMobileEvents() {
|
|
1729
1731
|
try {
|
|
1730
1732
|
document.addEventListener("pause", this.onVisibilityChange, this.options), document.addEventListener("resume", this.onActivity, this.options), "orientation" in screen && screen.orientation.addEventListener("change", this.onActivity, this.options), window.addEventListener("pageshow", this.onActivity, this.options), window.addEventListener("pagehide", this.onActivity, this.options);
|
|
1731
1733
|
} catch (e) {
|
|
1732
|
-
|
|
1734
|
+
n.warn("VisibilityListenerManager", "Failed to setup mobile listeners", { error: e });
|
|
1733
1735
|
}
|
|
1734
1736
|
}
|
|
1735
1737
|
cleanupMobileEvents() {
|
|
1736
1738
|
try {
|
|
1737
1739
|
document.removeEventListener("pause", this.onVisibilityChange), document.removeEventListener("resume", this.onActivity), "orientation" in screen && screen.orientation.removeEventListener("change", this.onActivity), window.removeEventListener("pageshow", this.onActivity), window.removeEventListener("pagehide", this.onActivity);
|
|
1738
1740
|
} catch (e) {
|
|
1739
|
-
|
|
1741
|
+
n.warn("VisibilityListenerManager", "Error during mobile listeners cleanup", { error: e });
|
|
1740
1742
|
}
|
|
1741
1743
|
}
|
|
1742
1744
|
}
|
|
@@ -1750,14 +1752,14 @@ class Nt {
|
|
|
1750
1752
|
try {
|
|
1751
1753
|
window.addEventListener("beforeunload", this.onInactivity, this.options), window.addEventListener("pagehide", this.onInactivity, this.options);
|
|
1752
1754
|
} catch (e) {
|
|
1753
|
-
throw
|
|
1755
|
+
throw n.error("UnloadListenerManager", "Failed to setup unload listeners", { error: e }), e;
|
|
1754
1756
|
}
|
|
1755
1757
|
}
|
|
1756
1758
|
cleanup() {
|
|
1757
1759
|
try {
|
|
1758
1760
|
window.removeEventListener("beforeunload", this.onInactivity), window.removeEventListener("pagehide", this.onInactivity);
|
|
1759
1761
|
} catch (e) {
|
|
1760
|
-
|
|
1762
|
+
n.warn("UnloadListenerManager", "Error during unload listeners cleanup", { error: e });
|
|
1761
1763
|
}
|
|
1762
1764
|
}
|
|
1763
1765
|
}
|
|
@@ -1767,48 +1769,48 @@ class Ce extends p {
|
|
|
1767
1769
|
eventManager;
|
|
1768
1770
|
projectId;
|
|
1769
1771
|
debugMode;
|
|
1770
|
-
constructor(e, t, s,
|
|
1772
|
+
constructor(e, t, s, i) {
|
|
1771
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 = {
|
|
1772
1774
|
recoveryWindowMs: this.calculateRecoveryWindow(),
|
|
1773
1775
|
maxRecoveryAttempts: Ke,
|
|
1774
1776
|
contextPreservation: !0,
|
|
1775
|
-
...
|
|
1777
|
+
...i
|
|
1776
1778
|
};
|
|
1777
1779
|
}
|
|
1778
1780
|
/**
|
|
1779
1781
|
* Attempt to recover a session
|
|
1780
1782
|
*/
|
|
1781
1783
|
attemptSessionRecovery(e) {
|
|
1782
|
-
this.debugMode &&
|
|
1784
|
+
this.debugMode && n.debug("SessionRecovery", "Attempting session recovery");
|
|
1783
1785
|
const t = this.getStoredRecoveryAttempts(), s = this.getLastRecoveryAttempt();
|
|
1784
1786
|
if (!this.canAttemptRecovery(s))
|
|
1785
|
-
return this.debugMode &&
|
|
1787
|
+
return this.debugMode && n.debug(
|
|
1786
1788
|
"SessionRecovery",
|
|
1787
1789
|
"Session recovery not possible - outside recovery window or max attempts reached"
|
|
1788
1790
|
), {
|
|
1789
1791
|
recovered: !1
|
|
1790
1792
|
};
|
|
1791
|
-
const
|
|
1792
|
-
if (!
|
|
1793
|
-
return this.debugMode &&
|
|
1793
|
+
const i = s?.context;
|
|
1794
|
+
if (!i)
|
|
1795
|
+
return this.debugMode && n.debug("SessionRecovery", "No session context available for recovery"), {
|
|
1794
1796
|
recovered: !1
|
|
1795
1797
|
};
|
|
1796
1798
|
const a = Date.now();
|
|
1797
|
-
if (a -
|
|
1798
|
-
return this.debugMode &&
|
|
1799
|
+
if (a - i.lastActivity > this.config.recoveryWindowMs)
|
|
1800
|
+
return this.debugMode && n.debug("SessionRecovery", "Session recovery failed - outside recovery window"), {
|
|
1799
1801
|
recovered: !1
|
|
1800
1802
|
};
|
|
1801
|
-
const l =
|
|
1803
|
+
const l = i.sessionId, c = (s?.attempt ?? 0) + 1, d = {
|
|
1802
1804
|
sessionId: e ?? l,
|
|
1803
1805
|
timestamp: a,
|
|
1804
1806
|
attempt: c,
|
|
1805
1807
|
context: {
|
|
1806
|
-
...
|
|
1808
|
+
...i,
|
|
1807
1809
|
recoveryAttempts: c,
|
|
1808
1810
|
lastActivity: a
|
|
1809
1811
|
}
|
|
1810
1812
|
};
|
|
1811
|
-
return t.push(d), this.storeRecoveryAttempts(t), this.debugMode &&
|
|
1813
|
+
return t.push(d), this.storeRecoveryAttempts(t), this.debugMode && n.debug("SessionRecovery", `Session recovery successful: recovery of session ${l}`), {
|
|
1812
1814
|
recovered: !0,
|
|
1813
1815
|
recoveredSessionId: l,
|
|
1814
1816
|
context: d.context
|
|
@@ -1822,10 +1824,10 @@ class Ce extends p {
|
|
|
1822
1824
|
Math.min(t, X),
|
|
1823
1825
|
K
|
|
1824
1826
|
);
|
|
1825
|
-
return this.debugMode && (t > X ?
|
|
1827
|
+
return this.debugMode && (t > X ? n.warn(
|
|
1826
1828
|
"SessionRecovery",
|
|
1827
1829
|
`Recovery window capped at ${X}ms (24h). Calculated: ${t}ms`
|
|
1828
|
-
) : t < K &&
|
|
1830
|
+
) : t < K && n.warn(
|
|
1829
1831
|
"SessionRecovery",
|
|
1830
1832
|
`Recovery window increased to minimum ${K}ms (2min). Calculated: ${t}ms`
|
|
1831
1833
|
)), s;
|
|
@@ -1848,10 +1850,10 @@ class Ce extends p {
|
|
|
1848
1850
|
context: e
|
|
1849
1851
|
};
|
|
1850
1852
|
t.push(s);
|
|
1851
|
-
const
|
|
1852
|
-
t.length >
|
|
1853
|
+
const i = 5;
|
|
1854
|
+
t.length > i && t.splice(0, t.length - i), this.storeRecoveryAttempts(t), this.debugMode && n.debug("SessionRecovery", `Stored session context for recovery: ${e.sessionId}`);
|
|
1853
1855
|
} catch (t) {
|
|
1854
|
-
this.debugMode &&
|
|
1856
|
+
this.debugMode && n.warn("SessionRecovery", "Failed to store session context for recovery", { error: t });
|
|
1855
1857
|
}
|
|
1856
1858
|
}
|
|
1857
1859
|
/**
|
|
@@ -1864,7 +1866,7 @@ class Ce extends p {
|
|
|
1864
1866
|
} catch (e) {
|
|
1865
1867
|
if (this.debugMode) {
|
|
1866
1868
|
const t = this.storageManager.getItem(V(this.projectId));
|
|
1867
|
-
|
|
1869
|
+
n.warn(
|
|
1868
1870
|
"SessionRecovery",
|
|
1869
1871
|
`Failed to parse stored recovery attempts for projectId ${this.projectId}. Data: ${t}`,
|
|
1870
1872
|
{ error: e }
|
|
@@ -1880,7 +1882,7 @@ class Ce extends p {
|
|
|
1880
1882
|
try {
|
|
1881
1883
|
this.storageManager.setItem(V(this.projectId), JSON.stringify(e));
|
|
1882
1884
|
} catch (t) {
|
|
1883
|
-
this.debugMode &&
|
|
1885
|
+
this.debugMode && n.warn("SessionRecovery", "Failed to store recovery attempts", { error: t });
|
|
1884
1886
|
}
|
|
1885
1887
|
}
|
|
1886
1888
|
/**
|
|
@@ -1894,8 +1896,8 @@ class Ce extends p {
|
|
|
1894
1896
|
* Clean up old recovery attempts
|
|
1895
1897
|
*/
|
|
1896
1898
|
cleanupOldRecoveryAttempts() {
|
|
1897
|
-
const e = this.getStoredRecoveryAttempts(), t = Date.now(), s = e.filter((
|
|
1898
|
-
s.length !== e.length && (this.storeRecoveryAttempts(s), this.debugMode &&
|
|
1899
|
+
const e = this.getStoredRecoveryAttempts(), t = Date.now(), s = e.filter((i) => t - i.timestamp <= this.config.recoveryWindowMs);
|
|
1900
|
+
s.length !== e.length && (this.storeRecoveryAttempts(s), this.debugMode && n.debug("SessionRecovery", `Cleaned up ${e.length - s.length} old recovery attempts`));
|
|
1899
1901
|
}
|
|
1900
1902
|
/**
|
|
1901
1903
|
* Check if there's a recoverable session.
|
|
@@ -1921,7 +1923,7 @@ class Ce extends p {
|
|
|
1921
1923
|
* Clear all stored recovery data
|
|
1922
1924
|
*/
|
|
1923
1925
|
clearRecoveryData() {
|
|
1924
|
-
this.storageManager.removeItem(V(this.projectId)), this.debugMode &&
|
|
1926
|
+
this.storageManager.removeItem(V(this.projectId)), this.debugMode && n.debug("SessionRecovery", "Cleared all recovery data");
|
|
1925
1927
|
}
|
|
1926
1928
|
}
|
|
1927
1929
|
class Ut extends p {
|
|
@@ -1981,7 +1983,7 @@ class Ut extends p {
|
|
|
1981
1983
|
crossTabConflicts: 0,
|
|
1982
1984
|
lastHealthCheck: Date.now()
|
|
1983
1985
|
};
|
|
1984
|
-
constructor(e, t, s,
|
|
1986
|
+
constructor(e, t, s, i, a) {
|
|
1985
1987
|
super(), this.config = {
|
|
1986
1988
|
throttleDelay: Te,
|
|
1987
1989
|
visibilityTimeout: Ve,
|
|
@@ -1993,7 +1995,7 @@ class Ut extends p {
|
|
|
1993
1995
|
maxRetries: 2,
|
|
1994
1996
|
debugMode: !1,
|
|
1995
1997
|
...a
|
|
1996
|
-
}, 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 = i ?? null, this.deviceCapabilities = this.detectDeviceCapabilities(), this.initializeRecoveryManager(), this.initializeListenerManagers(), this.setupAllListeners(), this.sessionEndConfig.enablePageUnloadHandlers && this.setupPageUnloadHandlers(), n.debug("SessionManager", "SessionManager initialized", {
|
|
1997
1999
|
sessionTimeout: this.config.timeout,
|
|
1998
2000
|
deviceCapabilities: this.deviceCapabilities,
|
|
1999
2001
|
unloadHandlersEnabled: this.sessionEndConfig.enablePageUnloadHandlers
|
|
@@ -2007,9 +2009,9 @@ class Ut extends p {
|
|
|
2007
2009
|
const e = this.get("config")?.id;
|
|
2008
2010
|
if (e)
|
|
2009
2011
|
try {
|
|
2010
|
-
this.recoveryManager = new Ce(this.storageManager, e, this.eventManager ?? void 0),
|
|
2012
|
+
this.recoveryManager = new Ce(this.storageManager, e, this.eventManager ?? void 0), n.debug("SessionManager", "Recovery manager initialized", { projectId: e });
|
|
2011
2013
|
} catch (t) {
|
|
2012
|
-
|
|
2014
|
+
n.error("SessionManager", "Failed to initialize recovery manager", { error: t, projectId: e });
|
|
2013
2015
|
}
|
|
2014
2016
|
}
|
|
2015
2017
|
/**
|
|
@@ -2037,13 +2039,13 @@ class Ut extends p {
|
|
|
2037
2039
|
const e = Date.now();
|
|
2038
2040
|
let t = "", s = !1;
|
|
2039
2041
|
if (this.recoveryManager?.hasRecoverableSession()) {
|
|
2040
|
-
const
|
|
2041
|
-
|
|
2042
|
+
const i = this.recoveryManager.attemptSessionRecovery();
|
|
2043
|
+
i.recovered && i.recoveredSessionId && (t = i.recoveredSessionId, s = !0, this.trackSessionHealth("recovery"), i.context ? (this.sessionStartTime = i.context.startTime, this.lastActivityTime = e) : (this.sessionStartTime = e, this.lastActivityTime = e), n.info("SessionManager", "Session successfully recovered", {
|
|
2042
2044
|
sessionId: t,
|
|
2043
2045
|
recoveryAttempts: this.sessionHealth.recoveryAttempts
|
|
2044
2046
|
}));
|
|
2045
2047
|
}
|
|
2046
|
-
return s || (t = $(), this.sessionStartTime = e, this.lastActivityTime = e,
|
|
2048
|
+
return s || (t = $(), this.sessionStartTime = e, this.lastActivityTime = e, n.info("SessionManager", "New session started", { sessionId: t })), this.isSessionActive = !0, this.resetInactivityTimer(), this.storeSessionContextForRecovery(), { sessionId: t, recovered: s };
|
|
2047
2049
|
}
|
|
2048
2050
|
endSession() {
|
|
2049
2051
|
if (this.sessionStartTime === 0)
|
|
@@ -2061,8 +2063,8 @@ class Ut extends p {
|
|
|
2061
2063
|
}), this.recoveryManager && (this.recoveryManager.cleanupOldRecoveryAttempts(), this.recoveryManager = null);
|
|
2062
2064
|
}
|
|
2063
2065
|
detectDeviceCapabilities() {
|
|
2064
|
-
const e = "ontouchstart" in window || navigator.maxTouchPoints > 0, t = window.matchMedia("(pointer: fine)").matches, s = !window.matchMedia("(pointer: coarse)").matches,
|
|
2065
|
-
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, i = we() === E.Mobile;
|
|
2067
|
+
return { hasTouch: e, hasMouse: t, hasKeyboard: s, isMobile: i };
|
|
2066
2068
|
}
|
|
2067
2069
|
initializeListenerManagers() {
|
|
2068
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(
|
|
@@ -2116,9 +2118,9 @@ class Ut extends p {
|
|
|
2116
2118
|
async endSessionManaged(e) {
|
|
2117
2119
|
return this.sessionEndLock = this.sessionEndLock.then(async () => {
|
|
2118
2120
|
if (this.sessionEndStats.totalSessionEnds++, this.sessionEndStats.reasonCounts[e]++, this.pendingSessionEnd)
|
|
2119
|
-
return this.sessionEndStats.duplicatePrevented++,
|
|
2121
|
+
return this.sessionEndStats.duplicatePrevented++, n.debug("SessionManager", "Session end already pending, waiting for completion", { reason: e }), this.waitForCompletion();
|
|
2120
2122
|
if (!this.shouldProceedWithSessionEnd(e))
|
|
2121
|
-
return this.sessionEndConfig.debugMode &&
|
|
2123
|
+
return this.sessionEndConfig.debugMode && n.debug(
|
|
2122
2124
|
"SessionManager",
|
|
2123
2125
|
`Session end skipped due to lower priority. Current: ${this.sessionEndReason}, Requested: ${e}`
|
|
2124
2126
|
), {
|
|
@@ -2167,27 +2169,27 @@ class Ut extends p {
|
|
|
2167
2169
|
event_trigger: e
|
|
2168
2170
|
}
|
|
2169
2171
|
}
|
|
2170
|
-
}), this.sessionEndConfig.debugMode &&
|
|
2172
|
+
}), this.sessionEndConfig.debugMode && n.warn(
|
|
2171
2173
|
"SessionManager",
|
|
2172
2174
|
`Session health degraded: ${this.sessionHealth.recoveryAttempts} recovery attempts`
|
|
2173
|
-
)), this.sessionEndConfig.debugMode &&
|
|
2175
|
+
)), this.sessionEndConfig.debugMode && n.debug("SessionManager", `Session health event tracked: ${e}`);
|
|
2174
2176
|
}
|
|
2175
2177
|
async performSessionEnd(e, t) {
|
|
2176
2178
|
const s = Date.now();
|
|
2177
|
-
let
|
|
2179
|
+
let i = 0;
|
|
2178
2180
|
try {
|
|
2179
|
-
if (
|
|
2181
|
+
if (n.info("SessionManager", "Starting session end", { method: t, reason: e, timestamp: s }), this.eventManager) {
|
|
2180
2182
|
this.eventManager.track({
|
|
2181
2183
|
type: h.SESSION_END,
|
|
2182
2184
|
session_end_reason: e
|
|
2183
|
-
}),
|
|
2185
|
+
}), i = this.eventManager.getQueueLength();
|
|
2184
2186
|
const o = await this.eventManager.flushImmediately();
|
|
2185
2187
|
this.cleanupSession();
|
|
2186
2188
|
const l = {
|
|
2187
2189
|
success: o,
|
|
2188
2190
|
reason: e,
|
|
2189
2191
|
timestamp: s,
|
|
2190
|
-
eventsFlushed:
|
|
2192
|
+
eventsFlushed: i,
|
|
2191
2193
|
method: t
|
|
2192
2194
|
};
|
|
2193
2195
|
return o ? this.sessionEndStats.successfulEnds++ : this.sessionEndStats.failedEnds++, l;
|
|
@@ -2202,11 +2204,11 @@ class Ut extends p {
|
|
|
2202
2204
|
};
|
|
2203
2205
|
return this.sessionEndStats.successfulEnds++, a;
|
|
2204
2206
|
} catch (a) {
|
|
2205
|
-
return this.sessionEndStats.failedEnds++,
|
|
2207
|
+
return this.sessionEndStats.failedEnds++, n.error("SessionManager", "Session end failed", { error: a, reason: e, method: t }), this.cleanupSession(), {
|
|
2206
2208
|
success: !1,
|
|
2207
2209
|
reason: e,
|
|
2208
2210
|
timestamp: s,
|
|
2209
|
-
eventsFlushed:
|
|
2211
|
+
eventsFlushed: i,
|
|
2210
2212
|
method: t
|
|
2211
2213
|
};
|
|
2212
2214
|
}
|
|
@@ -2215,8 +2217,8 @@ class Ut extends p {
|
|
|
2215
2217
|
this.endSession(), this.clearTimers(), this.set("sessionId", null), this.set("hasStartSession", !1);
|
|
2216
2218
|
}
|
|
2217
2219
|
endSessionManagedSync(e) {
|
|
2218
|
-
if (this.sessionEndStats.totalSessionEnds++, this.sessionEndStats.reasonCounts[e]++, this.pendingSessionEnd && (this.sessionEndStats.duplicatePrevented++,
|
|
2219
|
-
return this.sessionEndConfig.debugMode &&
|
|
2220
|
+
if (this.sessionEndStats.totalSessionEnds++, this.sessionEndStats.reasonCounts[e]++, this.pendingSessionEnd && (this.sessionEndStats.duplicatePrevented++, n.warn("SessionManager", "Sync session end called while async end pending", { reason: e })), !this.shouldProceedWithSessionEnd(e))
|
|
2221
|
+
return this.sessionEndConfig.debugMode && n.debug(
|
|
2220
2222
|
"SessionManager",
|
|
2221
2223
|
`Sync session end skipped due to lower priority. Current: ${this.sessionEndReason}, Requested: ${e}`
|
|
2222
2224
|
), {
|
|
@@ -2254,16 +2256,16 @@ class Ut extends p {
|
|
|
2254
2256
|
return a ? this.sessionEndStats.successfulEnds++ : this.sessionEndStats.failedEnds++, o;
|
|
2255
2257
|
}
|
|
2256
2258
|
this.cleanupSession();
|
|
2257
|
-
const
|
|
2259
|
+
const i = {
|
|
2258
2260
|
success: !0,
|
|
2259
2261
|
reason: e,
|
|
2260
2262
|
timestamp: t,
|
|
2261
2263
|
eventsFlushed: 0,
|
|
2262
2264
|
method: "sync"
|
|
2263
2265
|
};
|
|
2264
|
-
return this.sessionEndStats.successfulEnds++,
|
|
2265
|
-
} catch (
|
|
2266
|
-
return this.sessionEndStats.failedEnds++, this.cleanupSession(),
|
|
2266
|
+
return this.sessionEndStats.successfulEnds++, i;
|
|
2267
|
+
} catch (i) {
|
|
2268
|
+
return this.sessionEndStats.failedEnds++, this.cleanupSession(), n.error("SessionManager", "Sync session end failed", { error: i, reason: e }), {
|
|
2267
2269
|
success: !1,
|
|
2268
2270
|
reason: e,
|
|
2269
2271
|
timestamp: t,
|
|
@@ -2278,16 +2280,16 @@ class Ut extends p {
|
|
|
2278
2280
|
e || !this.get("sessionId") || (e = !0, this.clearInactivityTimer(), this.endSessionSafely("page_unload", { forceSync: !0 }));
|
|
2279
2281
|
}, s = () => {
|
|
2280
2282
|
t();
|
|
2281
|
-
},
|
|
2283
|
+
}, i = (o) => {
|
|
2282
2284
|
o.persisted || t();
|
|
2283
2285
|
}, a = () => {
|
|
2284
2286
|
document.visibilityState === "hidden" && this.get("sessionId") && !e && (this.visibilityChangeTimeout = window.setTimeout(() => {
|
|
2285
2287
|
document.visibilityState === "hidden" && this.get("sessionId") && !e && t(), this.visibilityChangeTimeout = null;
|
|
2286
2288
|
}, 1e3));
|
|
2287
2289
|
};
|
|
2288
|
-
window.addEventListener("beforeunload", s), window.addEventListener("pagehide",
|
|
2290
|
+
window.addEventListener("beforeunload", s), window.addEventListener("pagehide", i), document.addEventListener("visibilitychange", a), this.cleanupHandlers.push(
|
|
2289
2291
|
() => window.removeEventListener("beforeunload", s),
|
|
2290
|
-
() => window.removeEventListener("pagehide",
|
|
2292
|
+
() => window.removeEventListener("pagehide", i),
|
|
2291
2293
|
() => document.removeEventListener("visibilitychange", a),
|
|
2292
2294
|
() => {
|
|
2293
2295
|
this.visibilityChangeTimeout && (clearTimeout(this.visibilityChangeTimeout), this.visibilityChangeTimeout = null);
|
|
@@ -2295,9 +2297,9 @@ class Ut extends p {
|
|
|
2295
2297
|
);
|
|
2296
2298
|
}
|
|
2297
2299
|
}
|
|
2298
|
-
class
|
|
2299
|
-
constructor(e, t, s,
|
|
2300
|
-
super(), this.callbacks =
|
|
2300
|
+
class Ht extends p {
|
|
2301
|
+
constructor(e, t, s, i) {
|
|
2302
|
+
super(), this.callbacks = i, this.storageManager = e, this.projectId = t, this.tabId = $(), this.config = {
|
|
2301
2303
|
tabHeartbeatIntervalMs: qe,
|
|
2302
2304
|
tabElectionTimeoutMs: We,
|
|
2303
2305
|
debugMode: (this.get("config")?.mode === "qa" || this.get("config")?.mode === "debug") ?? !1,
|
|
@@ -2339,7 +2341,7 @@ class Pt extends p {
|
|
|
2339
2341
|
const e = new BroadcastChannel(st(this.projectId));
|
|
2340
2342
|
return this.setupBroadcastListeners(e), e;
|
|
2341
2343
|
} catch (e) {
|
|
2342
|
-
return this.config.debugMode &&
|
|
2344
|
+
return this.config.debugMode && n.warn("CrossTabSession", "Failed to initialize BroadcastChannel", { error: e }), null;
|
|
2343
2345
|
}
|
|
2344
2346
|
}
|
|
2345
2347
|
/**
|
|
@@ -2357,7 +2359,7 @@ class Pt extends p {
|
|
|
2357
2359
|
* Check if this tab should be the session leader
|
|
2358
2360
|
*/
|
|
2359
2361
|
tryJoinExistingSession(e) {
|
|
2360
|
-
this.config.debugMode &&
|
|
2362
|
+
this.config.debugMode && n.debug("CrossTabSession", `Attempting to join existing session: ${e.sessionId}`), this.tabInfo.sessionId = e.sessionId, this.requestLeadershipStatus(), e.tabCount += 1, e.lastActivity = Date.now(), this.storeSessionContext(e), this.callbacks?.onTabActivity && this.callbacks.onTabActivity();
|
|
2361
2363
|
}
|
|
2362
2364
|
/**
|
|
2363
2365
|
* Request leadership status from other tabs
|
|
@@ -2382,10 +2384,10 @@ class Pt extends p {
|
|
|
2382
2384
|
*/
|
|
2383
2385
|
startLeaderElection() {
|
|
2384
2386
|
if (this.electionTimeout) {
|
|
2385
|
-
this.config.debugMode &&
|
|
2387
|
+
this.config.debugMode && n.debug("CrossTabSession", "Leader election already in progress, skipping");
|
|
2386
2388
|
return;
|
|
2387
2389
|
}
|
|
2388
|
-
this.config.debugMode &&
|
|
2390
|
+
this.config.debugMode && n.debug("CrossTabSession", "Starting leader election");
|
|
2389
2391
|
const e = Math.floor(Math.random() * 50) + 10;
|
|
2390
2392
|
this.electionTimeout = window.setTimeout(() => {
|
|
2391
2393
|
this.electionTimeout = null, this.requestLeadershipStatus();
|
|
@@ -2396,7 +2398,7 @@ class Pt extends p {
|
|
|
2396
2398
|
*/
|
|
2397
2399
|
becomeLeader() {
|
|
2398
2400
|
if (!this.isTabLeader) {
|
|
2399
|
-
if (this.isTabLeader = !0, this.tabInfo.isLeader = !0, this.leaderTabId = this.tabId, this.config.debugMode &&
|
|
2401
|
+
if (this.isTabLeader = !0, this.tabInfo.isLeader = !0, this.leaderTabId = this.tabId, this.config.debugMode && n.debug("CrossTabSession", `Tab ${this.tabId} became session leader`), this.electionTimeout && (clearTimeout(this.electionTimeout), this.electionTimeout = null), this.tabInfo.sessionId) {
|
|
2400
2402
|
const e = this.getStoredSessionContext();
|
|
2401
2403
|
e && (e.lastActivity = Date.now(), this.storeSessionContext(e));
|
|
2402
2404
|
} else {
|
|
@@ -2447,10 +2449,10 @@ class Pt extends p {
|
|
|
2447
2449
|
setupLeadershipFallback() {
|
|
2448
2450
|
const e = this.config.tabElectionTimeoutMs + 1500;
|
|
2449
2451
|
this.fallbackLeadershipTimeout = window.setTimeout(() => {
|
|
2450
|
-
!this.isTabLeader && !this.leaderTabId && (this.tabInfo.sessionId ? (this.config.debugMode &&
|
|
2452
|
+
!this.isTabLeader && !this.leaderTabId && (this.tabInfo.sessionId ? (this.config.debugMode && n.warn(
|
|
2451
2453
|
"CrossTabSession",
|
|
2452
2454
|
`No leader detected after ${e}ms, forcing leadership for tab ${this.tabId}`
|
|
2453
|
-
), this.becomeLeader()) : (this.config.debugMode &&
|
|
2455
|
+
), this.becomeLeader()) : (this.config.debugMode && n.warn(
|
|
2454
2456
|
"CrossTabSession",
|
|
2455
2457
|
`No session or leader detected after ${e}ms, starting new session for tab ${this.tabId}`
|
|
2456
2458
|
), this.becomeLeader())), this.fallbackLeadershipTimeout = null;
|
|
@@ -2458,10 +2460,10 @@ class Pt extends p {
|
|
|
2458
2460
|
if (!this.sessionEnded && this.leaderTabId && !this.isTabLeader) {
|
|
2459
2461
|
const s = this.getStoredSessionContext();
|
|
2460
2462
|
if (s) {
|
|
2461
|
-
const
|
|
2462
|
-
|
|
2463
|
+
const i = Date.now() - s.lastActivity, a = this.config.tabHeartbeatIntervalMs * 3;
|
|
2464
|
+
i > a && (this.config.debugMode && n.warn(
|
|
2463
2465
|
"CrossTabSession",
|
|
2464
|
-
`Leader tab appears inactive (${
|
|
2466
|
+
`Leader tab appears inactive (${i}ms), attempting to become leader`
|
|
2465
2467
|
), this.leaderTabId = null, this.startLeaderElection());
|
|
2466
2468
|
}
|
|
2467
2469
|
}
|
|
@@ -2484,7 +2486,7 @@ class Pt extends p {
|
|
|
2484
2486
|
* Handle cross-tab messages
|
|
2485
2487
|
*/
|
|
2486
2488
|
handleCrossTabMessage(e) {
|
|
2487
|
-
switch (this.config.debugMode &&
|
|
2489
|
+
switch (this.config.debugMode && n.debug("CrossTabSession", `Received cross-tab message: ${e.type} from ${e.tabId}`), e.type) {
|
|
2488
2490
|
case "heartbeat":
|
|
2489
2491
|
this.handleHeartbeatMessage(e);
|
|
2490
2492
|
break;
|
|
@@ -2529,13 +2531,13 @@ class Pt extends p {
|
|
|
2529
2531
|
*/
|
|
2530
2532
|
handleSessionEndMessage(e) {
|
|
2531
2533
|
if (this.isTabLeader) {
|
|
2532
|
-
this.config.debugMode &&
|
|
2534
|
+
this.config.debugMode && n.debug("CrossTabSession", `Ignoring session end message from ${e.tabId} (this tab is leader)`);
|
|
2533
2535
|
return;
|
|
2534
2536
|
}
|
|
2535
2537
|
if (!this.leaderTabId || e.tabId !== this.leaderTabId) {
|
|
2536
2538
|
if (this.config.debugMode) {
|
|
2537
2539
|
const s = this.leaderTabId ? `; leader is ${this.leaderTabId}` : "";
|
|
2538
|
-
|
|
2540
|
+
n.debug("CrossTabSession", `Ignoring session end message from ${e.tabId}${s}`);
|
|
2539
2541
|
}
|
|
2540
2542
|
return;
|
|
2541
2543
|
}
|
|
@@ -2548,10 +2550,10 @@ class Pt extends p {
|
|
|
2548
2550
|
const t = this.getStoredSessionContext();
|
|
2549
2551
|
if (t && e.sessionId === t.sessionId) {
|
|
2550
2552
|
const s = t.tabCount;
|
|
2551
|
-
t.tabCount = Math.max(1, t.tabCount - 1), t.lastActivity = Date.now(), this.storeSessionContext(t), this.config.debugMode &&
|
|
2553
|
+
t.tabCount = Math.max(1, t.tabCount - 1), t.lastActivity = Date.now(), this.storeSessionContext(t), this.config.debugMode && n.debug(
|
|
2552
2554
|
"CrossTabSession",
|
|
2553
2555
|
`Tab count updated from ${s} to ${t.tabCount} after tab ${e.tabId} closed`
|
|
2554
|
-
), (e.data?.isLeader ?? e.tabId === this.leaderTabId) && !this.isTabLeader && (this.config.debugMode &&
|
|
2556
|
+
), (e.data?.isLeader ?? e.tabId === this.leaderTabId) && !this.isTabLeader && (this.config.debugMode && n.debug("CrossTabSession", `Leader tab ${e.tabId} closed, starting leader election`), this.leaderTabId = null, this.electionDelayTimeout = window.setTimeout(() => {
|
|
2555
2557
|
this.startLeaderElection(), this.electionDelayTimeout = null;
|
|
2556
2558
|
}, 200));
|
|
2557
2559
|
}
|
|
@@ -2575,10 +2577,10 @@ class Pt extends p {
|
|
|
2575
2577
|
* Handle election response from another tab
|
|
2576
2578
|
*/
|
|
2577
2579
|
handleElectionResponse(e) {
|
|
2578
|
-
e.data?.isLeader && (this.isTabLeader ? this.config.debugMode && (
|
|
2580
|
+
e.data?.isLeader && (this.isTabLeader ? this.config.debugMode && (n.warn(
|
|
2579
2581
|
"CrossTabSession",
|
|
2580
2582
|
`Received leadership claim from ${e.tabId} but this tab is already leader`
|
|
2581
|
-
), this.callbacks?.onCrossTabConflict && this.callbacks.onCrossTabConflict()) : (this.isTabLeader = !1, this.tabInfo.isLeader = !1, this.leaderTabId = e.tabId, this.config.debugMode &&
|
|
2583
|
+
), this.callbacks?.onCrossTabConflict && this.callbacks.onCrossTabConflict()) : (this.isTabLeader = !1, this.tabInfo.isLeader = !1, this.leaderTabId = e.tabId, this.config.debugMode && n.debug("CrossTabSession", `Acknowledging tab ${e.tabId} as leader`), this.electionTimeout && (clearTimeout(this.electionTimeout), this.electionTimeout = null), e.sessionId && (this.tabInfo.sessionId = e.sessionId, this.storeTabInfo())));
|
|
2582
2584
|
}
|
|
2583
2585
|
/**
|
|
2584
2586
|
* Start heartbeat to keep session active
|
|
@@ -2596,13 +2598,13 @@ class Pt extends p {
|
|
|
2596
2598
|
const e = Date.now(), t = this.lastHeartbeatSent ?? 0, s = this.config.tabHeartbeatIntervalMs * 0.8;
|
|
2597
2599
|
if (!this.isTabLeader && e - t < s)
|
|
2598
2600
|
return;
|
|
2599
|
-
const
|
|
2601
|
+
const i = {
|
|
2600
2602
|
type: "heartbeat",
|
|
2601
2603
|
tabId: this.tabId,
|
|
2602
2604
|
sessionId: this.tabInfo.sessionId,
|
|
2603
2605
|
timestamp: e
|
|
2604
2606
|
};
|
|
2605
|
-
this.broadcastChannel.postMessage(
|
|
2607
|
+
this.broadcastChannel.postMessage(i), this.lastHeartbeatSent = e;
|
|
2606
2608
|
}
|
|
2607
2609
|
/**
|
|
2608
2610
|
* Update tab info with current timestamp
|
|
@@ -2614,7 +2616,7 @@ class Pt extends p {
|
|
|
2614
2616
|
* End session and notify other tabs
|
|
2615
2617
|
*/
|
|
2616
2618
|
endSession(e) {
|
|
2617
|
-
this.sessionEnded || (this.sessionEnded = !0, this.config.debugMode &&
|
|
2619
|
+
this.sessionEnded || (this.sessionEnded = !0, this.config.debugMode && n.debug(
|
|
2618
2620
|
"CrossTabSession",
|
|
2619
2621
|
`Ending cross-tab session: ${e} (tab: ${this.tabId}, isLeader: ${this.isTabLeader})`
|
|
2620
2622
|
), this.announceTabClosing(), this.isTabLeader && e !== "manual_stop" && this.announceSessionEnd(e), this.tabInfoCleanupTimeout = window.setTimeout(() => {
|
|
@@ -2634,7 +2636,7 @@ class Pt extends p {
|
|
|
2634
2636
|
data: { isLeader: this.isTabLeader }
|
|
2635
2637
|
};
|
|
2636
2638
|
this.broadcastChannel.postMessage(e), this.closingAnnouncementTimeout = window.setTimeout(() => {
|
|
2637
|
-
this.config.debugMode &&
|
|
2639
|
+
this.config.debugMode && n.debug("CrossTabSession", `Tab ${this.tabId} closing announcement sent`), this.closingAnnouncementTimeout = null;
|
|
2638
2640
|
}, 100);
|
|
2639
2641
|
}
|
|
2640
2642
|
/**
|
|
@@ -2677,7 +2679,7 @@ class Pt extends p {
|
|
|
2677
2679
|
const e = this.storageManager.getItem(Y(this.projectId));
|
|
2678
2680
|
return e ? JSON.parse(e) : null;
|
|
2679
2681
|
} catch (e) {
|
|
2680
|
-
return this.config.debugMode &&
|
|
2682
|
+
return this.config.debugMode && n.warn("CrossTabSession", "Failed to parse stored session context", { error: e }), null;
|
|
2681
2683
|
}
|
|
2682
2684
|
}
|
|
2683
2685
|
/**
|
|
@@ -2687,7 +2689,7 @@ class Pt extends p {
|
|
|
2687
2689
|
try {
|
|
2688
2690
|
this.storageManager.setItem(Y(this.projectId), JSON.stringify(e));
|
|
2689
2691
|
} catch (t) {
|
|
2690
|
-
this.config.debugMode &&
|
|
2692
|
+
this.config.debugMode && n.warn("CrossTabSession", "Failed to store session context", { error: t });
|
|
2691
2693
|
}
|
|
2692
2694
|
}
|
|
2693
2695
|
/**
|
|
@@ -2703,7 +2705,7 @@ class Pt extends p {
|
|
|
2703
2705
|
try {
|
|
2704
2706
|
this.storageManager.setItem(Se(this.projectId, this.tabId), JSON.stringify(this.tabInfo));
|
|
2705
2707
|
} catch (e) {
|
|
2706
|
-
this.config.debugMode &&
|
|
2708
|
+
this.config.debugMode && n.warn("CrossTabSession", "Failed to store tab info", { error: e });
|
|
2707
2709
|
}
|
|
2708
2710
|
}
|
|
2709
2711
|
/**
|
|
@@ -2725,8 +2727,8 @@ class Pt extends p {
|
|
|
2725
2727
|
const e = this.getStoredSessionContext();
|
|
2726
2728
|
if (!e)
|
|
2727
2729
|
return this.get("config")?.sessionTimeout ?? R;
|
|
2728
|
-
const s = Date.now() - e.lastActivity,
|
|
2729
|
-
return Math.max(0,
|
|
2730
|
+
const s = Date.now() - e.lastActivity, i = this.get("config")?.sessionTimeout ?? R;
|
|
2731
|
+
return Math.max(0, i - s);
|
|
2730
2732
|
}
|
|
2731
2733
|
/**
|
|
2732
2734
|
* Update session activity from any tab
|
|
@@ -2742,7 +2744,7 @@ class Pt extends p {
|
|
|
2742
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();
|
|
2743
2745
|
}
|
|
2744
2746
|
}
|
|
2745
|
-
class
|
|
2747
|
+
class Pt extends p {
|
|
2746
2748
|
eventManager;
|
|
2747
2749
|
storageManager;
|
|
2748
2750
|
sessionStorageKey;
|
|
@@ -2758,7 +2760,7 @@ class Ht extends p {
|
|
|
2758
2760
|
const e = this.get("config")?.id;
|
|
2759
2761
|
e && this.initializeCrossTabSessionManager(e);
|
|
2760
2762
|
} catch (e) {
|
|
2761
|
-
|
|
2763
|
+
n.error("SessionHandler", "Failed to initialize cross-tab session manager", {
|
|
2762
2764
|
error: e instanceof Error ? e.message : "Unknown error"
|
|
2763
2765
|
});
|
|
2764
2766
|
} finally {
|
|
@@ -2777,42 +2779,42 @@ class Ht extends p {
|
|
|
2777
2779
|
}
|
|
2778
2780
|
startTracking() {
|
|
2779
2781
|
if (this.sessionManager) {
|
|
2780
|
-
|
|
2782
|
+
n.debug("SessionHandler", "Session tracking already active");
|
|
2781
2783
|
return;
|
|
2782
2784
|
}
|
|
2783
|
-
|
|
2785
|
+
n.debug("SessionHandler", "Starting session tracking"), this.checkOrphanedSessions();
|
|
2784
2786
|
const e = async () => {
|
|
2785
2787
|
if (this.crossTabSessionManager && this.crossTabSessionManager.updateSessionActivity(), !this.get("sessionId"))
|
|
2786
2788
|
try {
|
|
2787
|
-
const
|
|
2788
|
-
this.set("sessionId",
|
|
2789
|
-
sessionId:
|
|
2790
|
-
recovered:
|
|
2789
|
+
const i = await this.createOrJoinSession();
|
|
2790
|
+
this.set("sessionId", i.sessionId), n.info("SessionHandler", "🏁 Session started", {
|
|
2791
|
+
sessionId: i.sessionId,
|
|
2792
|
+
recovered: i.recovered,
|
|
2791
2793
|
crossTabActive: !!this.crossTabSessionManager
|
|
2792
|
-
}), this.trackSession(h.SESSION_START,
|
|
2793
|
-
} catch (
|
|
2794
|
-
|
|
2794
|
+
}), this.trackSession(h.SESSION_START, i.recovered), this.persistSession(i.sessionId), this.startHeartbeat();
|
|
2795
|
+
} catch (i) {
|
|
2796
|
+
n.error(
|
|
2795
2797
|
"SessionHandler",
|
|
2796
|
-
`Session creation failed: ${
|
|
2798
|
+
`Session creation failed: ${i instanceof Error ? i.message : "Unknown error"}`
|
|
2797
2799
|
), this.forceCleanupSession();
|
|
2798
2800
|
}
|
|
2799
2801
|
}, t = () => {
|
|
2800
2802
|
if (this.get("sessionId")) {
|
|
2801
2803
|
if (this.crossTabSessionManager && this.crossTabSessionManager.getEffectiveSessionTimeout() > 0) {
|
|
2802
|
-
(this.get("config")?.mode === "qa" || this.get("config")?.mode === "debug") &&
|
|
2804
|
+
(this.get("config")?.mode === "qa" || this.get("config")?.mode === "debug") && n.debug("SessionHandler", "Session kept alive by cross-tab activity");
|
|
2803
2805
|
return;
|
|
2804
2806
|
}
|
|
2805
|
-
this.sessionManager.endSessionManaged("inactivity").then((
|
|
2806
|
-
|
|
2807
|
+
this.sessionManager.endSessionManaged("inactivity").then((i) => {
|
|
2808
|
+
n.info("SessionHandler", "🛑 Session ended by inactivity", {
|
|
2807
2809
|
sessionId: this.get("sessionId"),
|
|
2808
|
-
reason:
|
|
2809
|
-
success:
|
|
2810
|
-
eventsFlushed:
|
|
2810
|
+
reason: i.reason,
|
|
2811
|
+
success: i.success,
|
|
2812
|
+
eventsFlushed: i.eventsFlushed
|
|
2811
2813
|
}), this.crossTabSessionManager && this.crossTabSessionManager.endSession("inactivity"), this.clearPersistedSession(), this.stopHeartbeat();
|
|
2812
|
-
}).catch((
|
|
2813
|
-
|
|
2814
|
+
}).catch((i) => {
|
|
2815
|
+
n.error(
|
|
2814
2816
|
"SessionHandler",
|
|
2815
|
-
`Session end failed: ${
|
|
2817
|
+
`Session end failed: ${i instanceof Error ? i.message : "Unknown error"}`
|
|
2816
2818
|
), this.forceCleanupSession();
|
|
2817
2819
|
});
|
|
2818
2820
|
}
|
|
@@ -2828,15 +2830,15 @@ class Ht extends p {
|
|
|
2828
2830
|
this.eventManager,
|
|
2829
2831
|
this.storageManager,
|
|
2830
2832
|
s
|
|
2831
|
-
),
|
|
2833
|
+
), n.debug("SessionHandler", "Session manager initialized"), this.startInitialSession();
|
|
2832
2834
|
}
|
|
2833
2835
|
stopTracking() {
|
|
2834
|
-
if (
|
|
2836
|
+
if (n.info("SessionHandler", "Stopping session tracking"), this.sessionManager) {
|
|
2835
2837
|
if (this.get("sessionId"))
|
|
2836
2838
|
try {
|
|
2837
2839
|
this.sessionManager.endSessionSafely("manual_stop", { forceSync: !0 }), this.clearPersistedSession(), this.stopHeartbeat();
|
|
2838
2840
|
} catch (e) {
|
|
2839
|
-
|
|
2841
|
+
n.error(
|
|
2840
2842
|
"SessionHandler",
|
|
2841
2843
|
`Manual session stop failed: ${e instanceof Error ? e.message : "Unknown error"}`
|
|
2842
2844
|
), this.forceCleanupSession();
|
|
@@ -2846,26 +2848,26 @@ class Ht extends p {
|
|
|
2846
2848
|
this._crossTabSessionManager && (this._crossTabSessionManager.destroy(), this._crossTabSessionManager = null), this._isInitializingCrossTab = !1, this.recoveryManager && (this.recoveryManager.cleanupOldRecoveryAttempts(), this.recoveryManager = null);
|
|
2847
2849
|
}
|
|
2848
2850
|
initializeSessionRecoveryManager(e) {
|
|
2849
|
-
this.recoveryManager = new Ce(this.storageManager, e, this.eventManager),
|
|
2851
|
+
this.recoveryManager = new Ce(this.storageManager, e, this.eventManager), n.debug("SessionHandler", "Session recovery manager initialized", { projectId: e });
|
|
2850
2852
|
}
|
|
2851
2853
|
initializeCrossTabSessionManager(e) {
|
|
2852
2854
|
const t = {
|
|
2853
2855
|
debugMode: (this.get("config")?.mode === "qa" || this.get("config")?.mode === "debug") ?? !1
|
|
2854
2856
|
}, l = {
|
|
2855
2857
|
onSessionStart: (c) => {
|
|
2856
|
-
(this.get("config")?.mode === "qa" || this.get("config")?.mode === "debug") &&
|
|
2858
|
+
(this.get("config")?.mode === "qa" || this.get("config")?.mode === "debug") && n.debug("SessionHandler", `Cross-tab session started: ${c}`), this.set("sessionId", c), this.trackSession(h.SESSION_START, !1), this.persistSession(c), this.startHeartbeat();
|
|
2857
2859
|
},
|
|
2858
2860
|
onSessionEnd: (c) => {
|
|
2859
|
-
(this.get("config")?.mode === "qa" || this.get("config")?.mode === "debug") &&
|
|
2861
|
+
(this.get("config")?.mode === "qa" || this.get("config")?.mode === "debug") && n.debug("SessionHandler", `Cross-tab session ended: ${c}`), this.clearPersistedSession(), this.trackSession(h.SESSION_END, !1, c);
|
|
2860
2862
|
},
|
|
2861
2863
|
onTabActivity: () => {
|
|
2862
|
-
(this.get("config")?.mode === "qa" || this.get("config")?.mode === "debug") &&
|
|
2864
|
+
(this.get("config")?.mode === "qa" || this.get("config")?.mode === "debug") && n.debug("SessionHandler", "Cross-tab activity detected");
|
|
2863
2865
|
},
|
|
2864
2866
|
onCrossTabConflict: () => {
|
|
2865
|
-
(this.get("config")?.mode === "qa" || this.get("config")?.mode === "debug") &&
|
|
2867
|
+
(this.get("config")?.mode === "qa" || this.get("config")?.mode === "debug") && n.warn("SessionHandler", "Cross-tab conflict detected"), this.sessionManager && this.sessionManager.trackSessionHealth("conflict");
|
|
2866
2868
|
}
|
|
2867
2869
|
};
|
|
2868
|
-
this._crossTabSessionManager = new
|
|
2870
|
+
this._crossTabSessionManager = new Ht(this.storageManager, e, t, l), n.debug("SessionHandler", "Cross-tab session manager initialized", { projectId: e });
|
|
2869
2871
|
}
|
|
2870
2872
|
async createOrJoinSession() {
|
|
2871
2873
|
if (this.crossTabSessionManager) {
|
|
@@ -2883,7 +2885,7 @@ class Ht extends p {
|
|
|
2883
2885
|
try {
|
|
2884
2886
|
this.crossTabSessionManager.endSession("orphaned_cleanup");
|
|
2885
2887
|
} catch (e) {
|
|
2886
|
-
(this.get("config")?.mode === "qa" || this.get("config")?.mode === "debug") &&
|
|
2888
|
+
(this.get("config")?.mode === "qa" || this.get("config")?.mode === "debug") && n.warn(
|
|
2887
2889
|
"SessionHandler",
|
|
2888
2890
|
`Cross-tab cleanup failed during force cleanup: ${e instanceof Error ? e.message : "Unknown error"}`
|
|
2889
2891
|
);
|
|
@@ -2891,12 +2893,12 @@ class Ht extends p {
|
|
|
2891
2893
|
try {
|
|
2892
2894
|
this.trackSession(h.SESSION_END, !1, "orphaned_cleanup");
|
|
2893
2895
|
} catch (e) {
|
|
2894
|
-
(this.get("config")?.mode === "qa" || this.get("config")?.mode === "debug") &&
|
|
2896
|
+
(this.get("config")?.mode === "qa" || this.get("config")?.mode === "debug") && n.warn(
|
|
2895
2897
|
"SessionHandler",
|
|
2896
2898
|
`Session tracking failed during force cleanup: ${e instanceof Error ? e.message : "Unknown error"}`
|
|
2897
2899
|
);
|
|
2898
2900
|
}
|
|
2899
|
-
(this.get("config")?.mode === "qa" || this.get("config")?.mode === "debug") &&
|
|
2901
|
+
(this.get("config")?.mode === "qa" || this.get("config")?.mode === "debug") && n.debug("SessionHandler", "Forced session cleanup completed");
|
|
2900
2902
|
}
|
|
2901
2903
|
trackSession(e, t = !1, s) {
|
|
2902
2904
|
this.eventManager.track({
|
|
@@ -2907,10 +2909,10 @@ class Ht extends p {
|
|
|
2907
2909
|
}
|
|
2908
2910
|
startInitialSession() {
|
|
2909
2911
|
if (this.get("sessionId")) {
|
|
2910
|
-
|
|
2912
|
+
n.debug("SessionHandler", "Session already exists, skipping initial session creation");
|
|
2911
2913
|
return;
|
|
2912
2914
|
}
|
|
2913
|
-
if (
|
|
2915
|
+
if (n.debug("SessionHandler", "Starting initial session"), this.crossTabSessionManager) {
|
|
2914
2916
|
const t = this.crossTabSessionManager.getSessionId();
|
|
2915
2917
|
if (t) {
|
|
2916
2918
|
this.set("sessionId", t), this.persistSession(t), this.startHeartbeat();
|
|
@@ -2918,7 +2920,7 @@ class Ht extends p {
|
|
|
2918
2920
|
}
|
|
2919
2921
|
return;
|
|
2920
2922
|
}
|
|
2921
|
-
|
|
2923
|
+
n.debug("SessionHandler", "Starting regular session (no cross-tab)");
|
|
2922
2924
|
const e = this.sessionManager.startSession();
|
|
2923
2925
|
this.set("sessionId", e.sessionId), this.trackSession(h.SESSION_START, e.recovered), this.persistSession(e.sessionId), this.startHeartbeat();
|
|
2924
2926
|
}
|
|
@@ -2926,8 +2928,8 @@ class Ht extends p {
|
|
|
2926
2928
|
const e = this.storageManager.getItem(this.sessionStorageKey);
|
|
2927
2929
|
if (e)
|
|
2928
2930
|
try {
|
|
2929
|
-
const t = JSON.parse(e),
|
|
2930
|
-
if (
|
|
2931
|
+
const t = JSON.parse(e), i = Date.now() - t.lastHeartbeat, a = this.get("config")?.sessionTimeout ?? R;
|
|
2932
|
+
if (i > a) {
|
|
2931
2933
|
const o = this.recoveryManager?.hasRecoverableSession();
|
|
2932
2934
|
if (o && this.recoveryManager) {
|
|
2933
2935
|
const l = {
|
|
@@ -2941,9 +2943,9 @@ class Ht extends p {
|
|
|
2941
2943
|
pageUrl: this.get("pageUrl")
|
|
2942
2944
|
}
|
|
2943
2945
|
};
|
|
2944
|
-
this.recoveryManager.storeSessionContextForRecovery(l), (this.get("config")?.mode === "qa" || this.get("config")?.mode === "debug") &&
|
|
2946
|
+
this.recoveryManager.storeSessionContextForRecovery(l), (this.get("config")?.mode === "qa" || this.get("config")?.mode === "debug") && n.debug("SessionHandler", `Orphaned session stored for recovery: ${t.sessionId}`);
|
|
2945
2947
|
}
|
|
2946
|
-
this.trackSession(h.SESSION_END), this.clearPersistedSession(), (this.get("config")?.mode === "qa" || this.get("config")?.mode === "debug") &&
|
|
2948
|
+
this.trackSession(h.SESSION_END), this.clearPersistedSession(), (this.get("config")?.mode === "qa" || this.get("config")?.mode === "debug") && n.debug(
|
|
2947
2949
|
"SessionHandler",
|
|
2948
2950
|
`Orphaned session ended: ${t.sessionId}, recovery available: ${o}`
|
|
2949
2951
|
);
|
|
@@ -2988,10 +2990,10 @@ class Dt extends p {
|
|
|
2988
2990
|
super(), this.eventManager = e, this.onTrack = t;
|
|
2989
2991
|
}
|
|
2990
2992
|
startTracking() {
|
|
2991
|
-
|
|
2993
|
+
n.debug("PageViewHandler", "Starting page view tracking"), this.trackInitialPageView(), this.trackCurrentPage(), window.addEventListener("popstate", this.trackCurrentPage), window.addEventListener("hashchange", this.trackCurrentPage), this.patchHistory("pushState"), this.patchHistory("replaceState");
|
|
2992
2994
|
}
|
|
2993
2995
|
stopTracking() {
|
|
2994
|
-
|
|
2996
|
+
n.debug("PageViewHandler", "Stopping page view tracking"), window.removeEventListener("popstate", this.trackCurrentPage), window.removeEventListener("hashchange", this.trackCurrentPage), this.originalPushState && (window.history.pushState = this.originalPushState), this.originalReplaceState && (window.history.replaceState = this.originalReplaceState);
|
|
2995
2997
|
}
|
|
2996
2998
|
patchHistory(e) {
|
|
2997
2999
|
e === "pushState" && !this.originalPushState ? this.originalPushState = window.history.pushState : e === "replaceState" && !this.originalReplaceState && (this.originalReplaceState = window.history.replaceState);
|
|
@@ -3004,7 +3006,7 @@ class Dt extends p {
|
|
|
3004
3006
|
const e = window.location.href, t = se(e, this.get("config").sensitiveQueryParams);
|
|
3005
3007
|
if (this.get("pageUrl") !== t) {
|
|
3006
3008
|
const s = this.get("pageUrl");
|
|
3007
|
-
|
|
3009
|
+
n.debug("PageViewHandler", "Page navigation detected", { from: s, to: t }), this.set("pageUrl", t), this.eventManager.track({
|
|
3008
3010
|
type: h.PAGE_VIEW,
|
|
3009
3011
|
page_url: this.get("pageUrl"),
|
|
3010
3012
|
from_page_url: s,
|
|
@@ -3038,21 +3040,21 @@ class xt extends p {
|
|
|
3038
3040
|
}
|
|
3039
3041
|
startTracking() {
|
|
3040
3042
|
if (this.clickHandler) {
|
|
3041
|
-
|
|
3043
|
+
n.debug("ClickHandler", "Click tracking already active");
|
|
3042
3044
|
return;
|
|
3043
3045
|
}
|
|
3044
|
-
|
|
3045
|
-
const t = e, s = t.target,
|
|
3046
|
-
if (!
|
|
3047
|
-
|
|
3046
|
+
n.debug("ClickHandler", "Starting click tracking"), this.clickHandler = (e) => {
|
|
3047
|
+
const t = e, s = t.target, i = s instanceof HTMLElement ? s : s instanceof Node && s.parentElement instanceof HTMLElement ? s.parentElement : null;
|
|
3048
|
+
if (!i) {
|
|
3049
|
+
n.warn("ClickHandler", "Click target not found or not an element");
|
|
3048
3050
|
return;
|
|
3049
3051
|
}
|
|
3050
|
-
|
|
3051
|
-
tagName:
|
|
3052
|
-
className:
|
|
3053
|
-
textContent:
|
|
3052
|
+
n.info("ClickHandler", "🖱️ Click detected on element", {
|
|
3053
|
+
tagName: i.tagName,
|
|
3054
|
+
className: i.className || "none",
|
|
3055
|
+
textContent: i.textContent?.slice(0, 50) ?? "empty"
|
|
3054
3056
|
});
|
|
3055
|
-
const a = this.findTrackingElement(
|
|
3057
|
+
const a = this.findTrackingElement(i), o = this.getRelevantClickElement(i), l = this.calculateClickCoordinates(t, i);
|
|
3056
3058
|
if (a) {
|
|
3057
3059
|
const d = this.extractTrackingData(a);
|
|
3058
3060
|
if (d) {
|
|
@@ -3066,7 +3068,7 @@ class xt extends p {
|
|
|
3066
3068
|
});
|
|
3067
3069
|
}
|
|
3068
3070
|
}
|
|
3069
|
-
const c = this.generateClickData(
|
|
3071
|
+
const c = this.generateClickData(i, o, l);
|
|
3070
3072
|
this.eventManager.track({
|
|
3071
3073
|
type: h.CLICK,
|
|
3072
3074
|
click_data: c
|
|
@@ -3085,7 +3087,7 @@ class xt extends p {
|
|
|
3085
3087
|
if (e.matches(t))
|
|
3086
3088
|
return e;
|
|
3087
3089
|
} catch (s) {
|
|
3088
|
-
|
|
3090
|
+
n.warn("ClickHandler", "Invalid selector in interactive elements check", {
|
|
3089
3091
|
selector: t,
|
|
3090
3092
|
error: s instanceof Error ? s.message : "Unknown error"
|
|
3091
3093
|
});
|
|
@@ -3097,7 +3099,7 @@ class xt extends p {
|
|
|
3097
3099
|
if (s)
|
|
3098
3100
|
return s;
|
|
3099
3101
|
} catch (s) {
|
|
3100
|
-
|
|
3102
|
+
n.warn("ClickHandler", "Invalid selector in parent element search", {
|
|
3101
3103
|
selector: t,
|
|
3102
3104
|
error: s instanceof Error ? s.message : "Unknown error"
|
|
3103
3105
|
});
|
|
@@ -3106,8 +3108,8 @@ class xt extends p {
|
|
|
3106
3108
|
return e;
|
|
3107
3109
|
}
|
|
3108
3110
|
calculateClickCoordinates(e, t) {
|
|
3109
|
-
const s = t.getBoundingClientRect(),
|
|
3110
|
-
return { x:
|
|
3111
|
+
const s = t.getBoundingClientRect(), i = e.clientX, a = e.clientY, o = s.width > 0 ? Math.max(0, Math.min(1, Number(((i - 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: i, y: a, relativeX: o, relativeY: l };
|
|
3111
3113
|
}
|
|
3112
3114
|
extractTrackingData(e) {
|
|
3113
3115
|
const t = e.getAttribute(`${z}-name`), s = e.getAttribute(`${z}-value`);
|
|
@@ -3119,9 +3121,9 @@ class xt extends p {
|
|
|
3119
3121
|
};
|
|
3120
3122
|
}
|
|
3121
3123
|
generateClickData(e, t, s) {
|
|
3122
|
-
const { x:
|
|
3124
|
+
const { x: i, 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);
|
|
3123
3125
|
return {
|
|
3124
|
-
x:
|
|
3126
|
+
x: i,
|
|
3125
3127
|
y: a,
|
|
3126
3128
|
relativeX: o,
|
|
3127
3129
|
relativeY: l,
|
|
@@ -3138,19 +3140,19 @@ class xt extends p {
|
|
|
3138
3140
|
};
|
|
3139
3141
|
}
|
|
3140
3142
|
getRelevantText(e, t) {
|
|
3141
|
-
const s = ["main", "section", "article", "body", "html", "header", "footer", "aside", "nav"],
|
|
3142
|
-
if (!
|
|
3143
|
+
const s = ["main", "section", "article", "body", "html", "header", "footer", "aside", "nav"], i = e.textContent?.trim() ?? "", a = t.textContent?.trim() ?? "";
|
|
3144
|
+
if (!i && !a)
|
|
3143
3145
|
return "";
|
|
3144
|
-
if (
|
|
3145
|
-
return
|
|
3146
|
+
if (i && i.length <= _)
|
|
3147
|
+
return i;
|
|
3146
3148
|
const o = s.includes(t.tagName.toLowerCase()), l = a.length > _ * 2;
|
|
3147
|
-
return o && l ?
|
|
3149
|
+
return o && l ? i && i.length <= _ ? i : "" : a.length <= _ ? a : i && i.length < a.length * 0.1 ? i.length <= _ ? i : i.slice(0, _ - 3) + "..." : a.slice(0, _ - 3) + "...";
|
|
3148
3150
|
}
|
|
3149
3151
|
extractElementAttributes(e) {
|
|
3150
3152
|
const t = ["id", "class", "data-testid", "aria-label", "title", "href", "type", "name"], s = {};
|
|
3151
|
-
for (const
|
|
3152
|
-
const a = e.getAttribute(
|
|
3153
|
-
a && (s[
|
|
3153
|
+
for (const i of t) {
|
|
3154
|
+
const a = e.getAttribute(i);
|
|
3155
|
+
a && (s[i] = a);
|
|
3154
3156
|
}
|
|
3155
3157
|
return s;
|
|
3156
3158
|
}
|
|
@@ -3169,14 +3171,14 @@ class Ot extends p {
|
|
|
3169
3171
|
}
|
|
3170
3172
|
startTracking() {
|
|
3171
3173
|
const e = this.get("config").scrollContainerSelectors, t = Array.isArray(e) ? e : typeof e == "string" ? [e] : [];
|
|
3172
|
-
|
|
3173
|
-
const s = t.map((
|
|
3174
|
+
n.debug("ScrollHandler", "Starting scroll tracking", { selectorsCount: t.length });
|
|
3175
|
+
const s = t.map((i) => this.safeQuerySelector(i)).filter((i) => i instanceof HTMLElement);
|
|
3174
3176
|
s.length === 0 && s.push(window);
|
|
3175
|
-
for (const
|
|
3176
|
-
this.setupScrollContainer(
|
|
3177
|
+
for (const i of s)
|
|
3178
|
+
this.setupScrollContainer(i);
|
|
3177
3179
|
}
|
|
3178
3180
|
stopTracking() {
|
|
3179
|
-
|
|
3181
|
+
n.debug("ScrollHandler", "Stopping scroll tracking", { containersCount: this.containers.length });
|
|
3180
3182
|
for (const e of this.containers)
|
|
3181
3183
|
e.debounceTimer && clearTimeout(e.debounceTimer), e.element instanceof Window ? window.removeEventListener("scroll", e.listener) : e.element.removeEventListener("scroll", e.listener);
|
|
3182
3184
|
this.containers.length = 0;
|
|
@@ -3196,21 +3198,21 @@ class Ot extends p {
|
|
|
3196
3198
|
return;
|
|
3197
3199
|
}
|
|
3198
3200
|
t.debounceTimer && clearTimeout(t.debounceTimer), t.debounceTimer = window.setTimeout(() => {
|
|
3199
|
-
const
|
|
3200
|
-
|
|
3201
|
+
const i = this.calculateScrollData(t);
|
|
3202
|
+
i && this.eventManager.track({
|
|
3201
3203
|
type: h.SCROLL,
|
|
3202
|
-
scroll_data:
|
|
3204
|
+
scroll_data: i
|
|
3203
3205
|
}), t.debounceTimer = null;
|
|
3204
3206
|
}, Me);
|
|
3205
3207
|
};
|
|
3206
3208
|
t.listener = s, this.containers.push(t), e instanceof Window ? window.addEventListener("scroll", s, { passive: !0 }) : e.addEventListener("scroll", s, { passive: !0 });
|
|
3207
3209
|
}
|
|
3208
3210
|
calculateScrollData(e) {
|
|
3209
|
-
const { element: t, lastScrollPos: s } = e,
|
|
3211
|
+
const { element: t, lastScrollPos: s } = e, i = this.getScrollTop(t), a = this.getViewportHeight(t), o = this.getScrollHeight(t);
|
|
3210
3212
|
if (t === window && o <= a)
|
|
3211
3213
|
return null;
|
|
3212
|
-
const l =
|
|
3213
|
-
return Math.abs(
|
|
3214
|
+
const l = i > s ? j.DOWN : j.UP, c = o > a ? Math.min(100, Math.max(0, Math.floor(i / (o - a) * 100))) : 0;
|
|
3215
|
+
return Math.abs(i - s) < Ue ? null : (e.lastScrollPos = i, { depth: c, direction: l });
|
|
3214
3216
|
}
|
|
3215
3217
|
getScrollTop(e) {
|
|
3216
3218
|
return e instanceof Window ? window.scrollY : e.scrollTop;
|
|
@@ -3222,14 +3224,14 @@ class Ot extends p {
|
|
|
3222
3224
|
return e instanceof Window ? document.documentElement.scrollHeight : e.scrollHeight;
|
|
3223
3225
|
}
|
|
3224
3226
|
isElementScrollable(e) {
|
|
3225
|
-
const t = getComputedStyle(e), s = t.overflowY === "auto" || t.overflowY === "scroll" || t.overflowX === "auto" || t.overflowX === "scroll" || t.overflow === "auto" || t.overflow === "scroll",
|
|
3226
|
-
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", i = e.scrollHeight > e.clientHeight || e.scrollWidth > e.clientWidth;
|
|
3228
|
+
return s && i;
|
|
3227
3229
|
}
|
|
3228
3230
|
safeQuerySelector(e) {
|
|
3229
3231
|
try {
|
|
3230
3232
|
return document.querySelector(e);
|
|
3231
3233
|
} catch (t) {
|
|
3232
|
-
return
|
|
3234
|
+
return n.clientWarn("ScrollHandler", "Invalid CSS selector", {
|
|
3233
3235
|
selector: e,
|
|
3234
3236
|
error: t instanceof Error ? t.message : "Unknown error"
|
|
3235
3237
|
}), null;
|
|
@@ -3246,7 +3248,7 @@ class Ft extends p {
|
|
|
3246
3248
|
return;
|
|
3247
3249
|
const e = this.get("config").integrations?.googleAnalytics?.measurementId;
|
|
3248
3250
|
if (!e?.trim()) {
|
|
3249
|
-
|
|
3251
|
+
n.clientWarn("GoogleAnalytics", "Google Analytics integration disabled - measurementId not configured", {
|
|
3250
3252
|
hasIntegrations: !!this.get("config").integrations,
|
|
3251
3253
|
hasGoogleAnalytics: !!this.get("config").integrations?.googleAnalytics
|
|
3252
3254
|
});
|
|
@@ -3254,22 +3256,22 @@ class Ft extends p {
|
|
|
3254
3256
|
}
|
|
3255
3257
|
const t = this.get("userId");
|
|
3256
3258
|
if (!t?.trim()) {
|
|
3257
|
-
|
|
3259
|
+
n.warn("GoogleAnalytics", "Google Analytics initialization delayed - userId not available", {
|
|
3258
3260
|
measurementId: e.substring(0, 8) + "..."
|
|
3259
3261
|
});
|
|
3260
3262
|
return;
|
|
3261
3263
|
}
|
|
3262
3264
|
try {
|
|
3263
3265
|
if (this.isScriptAlreadyLoaded()) {
|
|
3264
|
-
|
|
3266
|
+
n.info("GoogleAnalytics", "Google Analytics script already loaded", { measurementId: e }), this.isInitialized = !0;
|
|
3265
3267
|
return;
|
|
3266
3268
|
}
|
|
3267
|
-
await this.loadScript(e), this.configureGtag(e, t), this.isInitialized = !0,
|
|
3269
|
+
await this.loadScript(e), this.configureGtag(e, t), this.isInitialized = !0, n.info("GoogleAnalytics", "Google Analytics integration initialized successfully", {
|
|
3268
3270
|
measurementId: e,
|
|
3269
3271
|
userId: t
|
|
3270
3272
|
});
|
|
3271
3273
|
} catch (s) {
|
|
3272
|
-
|
|
3274
|
+
n.error("GoogleAnalytics", "Google Analytics initialization failed", {
|
|
3273
3275
|
error: s instanceof Error ? s.message : "Unknown error",
|
|
3274
3276
|
measurementId: e,
|
|
3275
3277
|
userId: t
|
|
@@ -3278,7 +3280,7 @@ class Ft extends p {
|
|
|
3278
3280
|
}
|
|
3279
3281
|
trackEvent(e, t) {
|
|
3280
3282
|
if (!e?.trim()) {
|
|
3281
|
-
|
|
3283
|
+
n.clientWarn("GoogleAnalytics", "Event tracking skipped - invalid event name provided", {
|
|
3282
3284
|
eventName: e,
|
|
3283
3285
|
hasMetadata: !!t && Object.keys(t).length > 0
|
|
3284
3286
|
});
|
|
@@ -3286,7 +3288,7 @@ class Ft extends p {
|
|
|
3286
3288
|
}
|
|
3287
3289
|
if (this.isInitialized) {
|
|
3288
3290
|
if (typeof window.gtag != "function") {
|
|
3289
|
-
|
|
3291
|
+
n.warn("GoogleAnalytics", "Event tracking failed - gtag function not available", {
|
|
3290
3292
|
eventName: e,
|
|
3291
3293
|
hasGtag: typeof window.gtag,
|
|
3292
3294
|
hasDataLayer: Array.isArray(window.dataLayer)
|
|
@@ -3296,7 +3298,7 @@ class Ft extends p {
|
|
|
3296
3298
|
try {
|
|
3297
3299
|
window.gtag("event", e, t);
|
|
3298
3300
|
} catch (s) {
|
|
3299
|
-
|
|
3301
|
+
n.error("GoogleAnalytics", "Event tracking failed", {
|
|
3300
3302
|
eventName: e,
|
|
3301
3303
|
error: s instanceof Error ? s.message : "Unknown error",
|
|
3302
3304
|
metadataKeys: Object.keys(t || {})
|
|
@@ -3307,13 +3309,13 @@ class Ft extends p {
|
|
|
3307
3309
|
cleanup() {
|
|
3308
3310
|
this.isInitialized = !1;
|
|
3309
3311
|
const e = document.getElementById("tracelog-ga-script");
|
|
3310
|
-
e && e.remove(),
|
|
3312
|
+
e && e.remove(), n.info("GoogleAnalytics", "Google Analytics integration cleanup completed");
|
|
3311
3313
|
}
|
|
3312
3314
|
isScriptAlreadyLoaded() {
|
|
3313
3315
|
if (document.getElementById("tracelog-ga-script"))
|
|
3314
3316
|
return !0;
|
|
3315
3317
|
const t = document.querySelector('script[src*="googletagmanager.com/gtag/js"]');
|
|
3316
|
-
return t ? (
|
|
3318
|
+
return t ? (n.clientWarn("GoogleAnalytics", "Google Analytics script already loaded from external source", {
|
|
3317
3319
|
scriptSrc: t.getAttribute("src"),
|
|
3318
3320
|
hasGtag: typeof window.gtag == "function"
|
|
3319
3321
|
}), !0) : !1;
|
|
@@ -3321,20 +3323,20 @@ class Ft extends p {
|
|
|
3321
3323
|
async loadScript(e) {
|
|
3322
3324
|
return new Promise((t, s) => {
|
|
3323
3325
|
try {
|
|
3324
|
-
const
|
|
3325
|
-
|
|
3326
|
+
const i = document.createElement("script");
|
|
3327
|
+
i.id = "tracelog-ga-script", i.async = !0, i.src = `https://www.googletagmanager.com/gtag/js?id=${e}`, i.onload = () => {
|
|
3326
3328
|
t();
|
|
3327
|
-
},
|
|
3329
|
+
}, i.onerror = () => {
|
|
3328
3330
|
const a = new Error("Failed to load Google Analytics script");
|
|
3329
|
-
|
|
3331
|
+
n.error("GoogleAnalytics", "Google Analytics script load failed", {
|
|
3330
3332
|
measurementId: e,
|
|
3331
3333
|
error: a.message,
|
|
3332
|
-
scriptSrc:
|
|
3334
|
+
scriptSrc: i.src
|
|
3333
3335
|
}), s(a);
|
|
3334
|
-
}, document.head.appendChild(
|
|
3335
|
-
} catch (
|
|
3336
|
-
const a =
|
|
3337
|
-
|
|
3336
|
+
}, document.head.appendChild(i);
|
|
3337
|
+
} catch (i) {
|
|
3338
|
+
const a = i instanceof Error ? i : new Error(String(i));
|
|
3339
|
+
n.error("GoogleAnalytics", "Error creating Google Analytics script", {
|
|
3338
3340
|
measurementId: e,
|
|
3339
3341
|
error: a.message
|
|
3340
3342
|
}), s(a);
|
|
@@ -3353,7 +3355,7 @@ class Ft extends p {
|
|
|
3353
3355
|
});
|
|
3354
3356
|
`, document.head.appendChild(s);
|
|
3355
3357
|
} catch (s) {
|
|
3356
|
-
throw
|
|
3358
|
+
throw n.error("GoogleAnalytics", "Failed to configure Google Analytics", {
|
|
3357
3359
|
measurementId: e,
|
|
3358
3360
|
userId: t,
|
|
3359
3361
|
error: s instanceof Error ? s.message : "Unknown error"
|
|
@@ -3366,7 +3368,7 @@ class zt {
|
|
|
3366
3368
|
fallbackStorage = /* @__PURE__ */ new Map();
|
|
3367
3369
|
storageAvailable = !1;
|
|
3368
3370
|
constructor() {
|
|
3369
|
-
this.storage = this.init(), this.storageAvailable = this.storage !== null, this.storageAvailable ||
|
|
3371
|
+
this.storage = this.init(), this.storageAvailable = this.storage !== null, this.storageAvailable || n.warn("StorageManager", "localStorage not available, using memory fallback");
|
|
3370
3372
|
}
|
|
3371
3373
|
getItem(e) {
|
|
3372
3374
|
if (!this.storageAvailable)
|
|
@@ -3374,7 +3376,7 @@ class zt {
|
|
|
3374
3376
|
try {
|
|
3375
3377
|
return this.storage ? this.storage.getItem(e) : this.fallbackStorage.get(e) ?? null;
|
|
3376
3378
|
} catch (t) {
|
|
3377
|
-
return
|
|
3379
|
+
return n.warn("StorageManager", "Storage getItem failed, using memory fallback", { key: e, error: t }), this.storageAvailable = !1, this.fallbackStorage.get(e) ?? null;
|
|
3378
3380
|
}
|
|
3379
3381
|
}
|
|
3380
3382
|
setItem(e, t) {
|
|
@@ -3389,7 +3391,7 @@ class zt {
|
|
|
3389
3391
|
}
|
|
3390
3392
|
this.fallbackStorage.set(e, t);
|
|
3391
3393
|
} catch (s) {
|
|
3392
|
-
|
|
3394
|
+
n.warn("StorageManager", "Storage setItem failed, using memory fallback", { key: e, error: s }), this.storageAvailable = !1, this.fallbackStorage.set(e, t);
|
|
3393
3395
|
}
|
|
3394
3396
|
}
|
|
3395
3397
|
removeItem(e) {
|
|
@@ -3404,7 +3406,7 @@ class zt {
|
|
|
3404
3406
|
}
|
|
3405
3407
|
this.fallbackStorage.delete(e);
|
|
3406
3408
|
} catch (t) {
|
|
3407
|
-
|
|
3409
|
+
n.warn("StorageManager", "Storage removeItem failed, using memory fallback", { key: e, error: t }), this.storageAvailable = !1, this.fallbackStorage.delete(e);
|
|
3408
3410
|
}
|
|
3409
3411
|
}
|
|
3410
3412
|
init() {
|
|
@@ -3425,19 +3427,19 @@ class Vt extends p {
|
|
|
3425
3427
|
super(), this.eventManager = e;
|
|
3426
3428
|
}
|
|
3427
3429
|
async startTracking() {
|
|
3428
|
-
|
|
3430
|
+
n.debug("PerformanceHandler", "Starting performance tracking"), await this.initWebVitals(), this.observeLongTasks(), this.reportTTFB();
|
|
3429
3431
|
}
|
|
3430
3432
|
stopTracking() {
|
|
3431
|
-
|
|
3433
|
+
n.debug("PerformanceHandler", "Stopping performance tracking", { observersCount: this.observers.length }), this.observers.forEach((e, t) => {
|
|
3432
3434
|
try {
|
|
3433
3435
|
e.disconnect();
|
|
3434
3436
|
} catch (s) {
|
|
3435
|
-
|
|
3437
|
+
n.warn("PerformanceHandler", "Failed to disconnect performance observer", {
|
|
3436
3438
|
error: s instanceof Error ? s.message : "Unknown error",
|
|
3437
3439
|
observerIndex: t
|
|
3438
3440
|
});
|
|
3439
3441
|
}
|
|
3440
|
-
}), this.observers.length = 0, this.reportedByNav.clear(),
|
|
3442
|
+
}), this.observers.length = 0, this.reportedByNav.clear(), n.debug("PerformanceHandler", "Performance tracking cleanup completed", {
|
|
3441
3443
|
remainingObservers: this.observers.length,
|
|
3442
3444
|
clearedNavReports: !0
|
|
3443
3445
|
});
|
|
@@ -3446,8 +3448,8 @@ class Vt extends p {
|
|
|
3446
3448
|
this.reportTTFB(), this.safeObserve(
|
|
3447
3449
|
"largest-contentful-paint",
|
|
3448
3450
|
(t) => {
|
|
3449
|
-
const s = t.getEntries(),
|
|
3450
|
-
|
|
3451
|
+
const s = t.getEntries(), i = s[s.length - 1];
|
|
3452
|
+
i && this.sendVital({ type: "LCP", value: Number(i.startTime.toFixed(N)) });
|
|
3451
3453
|
},
|
|
3452
3454
|
{ type: "largest-contentful-paint", buffered: !0 },
|
|
3453
3455
|
!0
|
|
@@ -3457,13 +3459,13 @@ class Vt extends p {
|
|
|
3457
3459
|
"layout-shift",
|
|
3458
3460
|
(t) => {
|
|
3459
3461
|
const s = t.getEntries();
|
|
3460
|
-
for (const
|
|
3461
|
-
if (
|
|
3462
|
+
for (const i of s) {
|
|
3463
|
+
if (i.hadRecentInput === !0)
|
|
3462
3464
|
continue;
|
|
3463
|
-
const a = typeof
|
|
3465
|
+
const a = typeof i.value == "number" ? i.value : 0;
|
|
3464
3466
|
e += a;
|
|
3465
3467
|
}
|
|
3466
|
-
this.sendVital({ type: "CLS", value: Number(e.toFixed(
|
|
3468
|
+
this.sendVital({ type: "CLS", value: Number(e.toFixed(He)) });
|
|
3467
3469
|
},
|
|
3468
3470
|
{ type: "layout-shift", buffered: !0 }
|
|
3469
3471
|
), this.safeObserve(
|
|
@@ -3478,8 +3480,8 @@ class Vt extends p {
|
|
|
3478
3480
|
"event",
|
|
3479
3481
|
(t) => {
|
|
3480
3482
|
let s = 0;
|
|
3481
|
-
const
|
|
3482
|
-
for (const a of
|
|
3483
|
+
const i = t.getEntries();
|
|
3484
|
+
for (const a of i) {
|
|
3483
3485
|
const o = (a.processingEnd ?? 0) - (a.startTime ?? 0);
|
|
3484
3486
|
s = Math.max(s, o);
|
|
3485
3487
|
}
|
|
@@ -3490,13 +3492,13 @@ class Vt extends p {
|
|
|
3490
3492
|
}
|
|
3491
3493
|
async initWebVitals() {
|
|
3492
3494
|
try {
|
|
3493
|
-
const { onLCP: e, onCLS: t, onFCP: s, onTTFB:
|
|
3495
|
+
const { onLCP: e, onCLS: t, onFCP: s, onTTFB: i, onINP: a } = await import("./web-vitals-CCnqwnC8.mjs"), o = (l) => (c) => {
|
|
3494
3496
|
const d = Number(c.value.toFixed(N));
|
|
3495
3497
|
this.sendVital({ type: l, value: d });
|
|
3496
3498
|
};
|
|
3497
|
-
e(o("LCP")), t(o("CLS")), s(o("FCP")),
|
|
3499
|
+
e(o("LCP")), t(o("CLS")), s(o("FCP")), i(o("TTFB")), a(o("INP"));
|
|
3498
3500
|
} catch (e) {
|
|
3499
|
-
|
|
3501
|
+
n.warn("PerformanceHandler", "Failed to load web-vitals library, using fallback", {
|
|
3500
3502
|
error: e instanceof Error ? e.message : "Unknown error"
|
|
3501
3503
|
}), this.observeWebVitalsFallback();
|
|
3502
3504
|
}
|
|
@@ -3505,13 +3507,13 @@ class Vt extends p {
|
|
|
3505
3507
|
try {
|
|
3506
3508
|
const e = performance.getEntriesByType("navigation")[0];
|
|
3507
3509
|
if (!e) {
|
|
3508
|
-
|
|
3510
|
+
n.debug("PerformanceHandler", "Navigation timing not available for TTFB");
|
|
3509
3511
|
return;
|
|
3510
3512
|
}
|
|
3511
3513
|
const t = e.responseStart;
|
|
3512
|
-
typeof t == "number" && Number.isFinite(t) ? this.sendVital({ type: "TTFB", value: Number(t.toFixed(N)) }) :
|
|
3514
|
+
typeof t == "number" && Number.isFinite(t) ? this.sendVital({ type: "TTFB", value: Number(t.toFixed(N)) }) : n.debug("PerformanceHandler", "TTFB value is not a valid number", { ttfb: t });
|
|
3513
3515
|
} catch (e) {
|
|
3514
|
-
|
|
3516
|
+
n.warn("PerformanceHandler", "Failed to report TTFB", {
|
|
3515
3517
|
error: e instanceof Error ? e.message : "Unknown error"
|
|
3516
3518
|
});
|
|
3517
3519
|
}
|
|
@@ -3522,8 +3524,8 @@ class Vt extends p {
|
|
|
3522
3524
|
(e) => {
|
|
3523
3525
|
const t = e.getEntries();
|
|
3524
3526
|
for (const s of t) {
|
|
3525
|
-
const
|
|
3526
|
-
a - this.lastLongTaskSentAt >= Be && (this.trackWebVital("LONG_TASK",
|
|
3527
|
+
const i = Number(s.duration.toFixed(N)), a = Date.now();
|
|
3528
|
+
a - this.lastLongTaskSentAt >= Be && (this.trackWebVital("LONG_TASK", i), this.lastLongTaskSentAt = a);
|
|
3527
3529
|
}
|
|
3528
3530
|
},
|
|
3529
3531
|
{ type: "longtask", buffered: !0 }
|
|
@@ -3533,16 +3535,16 @@ class Vt extends p {
|
|
|
3533
3535
|
const t = this.getNavigationId(), s = `${e.type}`;
|
|
3534
3536
|
if (t) {
|
|
3535
3537
|
this.reportedByNav.has(t) || this.reportedByNav.set(t, /* @__PURE__ */ new Set());
|
|
3536
|
-
const
|
|
3537
|
-
if (
|
|
3538
|
+
const i = this.reportedByNav.get(t);
|
|
3539
|
+
if (i.has(s))
|
|
3538
3540
|
return;
|
|
3539
|
-
|
|
3541
|
+
i.add(s);
|
|
3540
3542
|
}
|
|
3541
3543
|
this.trackWebVital(e.type, e.value);
|
|
3542
3544
|
}
|
|
3543
3545
|
trackWebVital(e, t) {
|
|
3544
3546
|
if (typeof t != "number" || !Number.isFinite(t)) {
|
|
3545
|
-
|
|
3547
|
+
n.warn("PerformanceHandler", "Invalid web vital value", { type: e, value: t });
|
|
3546
3548
|
return;
|
|
3547
3549
|
}
|
|
3548
3550
|
this.eventManager.track({
|
|
@@ -3558,26 +3560,26 @@ class Vt extends p {
|
|
|
3558
3560
|
const e = performance.getEntriesByType("navigation")[0];
|
|
3559
3561
|
return e ? `${Math.round(e.startTime)}_${window.location.pathname}` : null;
|
|
3560
3562
|
} catch (e) {
|
|
3561
|
-
return
|
|
3563
|
+
return n.warn("PerformanceHandler", "Failed to get navigation ID", {
|
|
3562
3564
|
error: e instanceof Error ? e.message : "Unknown error"
|
|
3563
3565
|
}), null;
|
|
3564
3566
|
}
|
|
3565
3567
|
}
|
|
3566
|
-
safeObserve(e, t, s,
|
|
3568
|
+
safeObserve(e, t, s, i = !1) {
|
|
3567
3569
|
try {
|
|
3568
3570
|
if (typeof PerformanceObserver > "u") return;
|
|
3569
3571
|
const a = PerformanceObserver.supportedEntryTypes;
|
|
3570
3572
|
if (a && !a.includes(e)) return;
|
|
3571
3573
|
const o = new PerformanceObserver((l, c) => {
|
|
3572
|
-
if (t(l, c),
|
|
3574
|
+
if (t(l, c), i)
|
|
3573
3575
|
try {
|
|
3574
3576
|
c.disconnect();
|
|
3575
3577
|
} catch {
|
|
3576
3578
|
}
|
|
3577
3579
|
});
|
|
3578
|
-
o.observe(s ?? { type: e, buffered: !0 }),
|
|
3580
|
+
o.observe(s ?? { type: e, buffered: !0 }), i || this.observers.push(o);
|
|
3579
3581
|
} catch (a) {
|
|
3580
|
-
|
|
3582
|
+
n.warn("PerformanceHandler", "Failed to create performance observer", {
|
|
3581
3583
|
type: e,
|
|
3582
3584
|
error: a instanceof Error ? a.message : "Unknown error"
|
|
3583
3585
|
});
|
|
@@ -3596,10 +3598,10 @@ class $t extends p {
|
|
|
3596
3598
|
super(), this.eventManager = e;
|
|
3597
3599
|
}
|
|
3598
3600
|
startTracking() {
|
|
3599
|
-
|
|
3601
|
+
n.debug("ErrorHandler", "Starting error tracking"), this.setupErrorListener(), this.setupUnhandledRejectionListener();
|
|
3600
3602
|
}
|
|
3601
3603
|
stopTracking() {
|
|
3602
|
-
|
|
3604
|
+
n.debug("ErrorHandler", "Stopping error tracking"), window.removeEventListener("error", this.handleError), window.removeEventListener("unhandledrejection", this.handleUnhandledRejection);
|
|
3603
3605
|
}
|
|
3604
3606
|
setupErrorListener() {
|
|
3605
3607
|
window.addEventListener("error", this.handleError);
|
|
@@ -3610,12 +3612,12 @@ class $t extends p {
|
|
|
3610
3612
|
handleError = (e) => {
|
|
3611
3613
|
const t = this.get("config");
|
|
3612
3614
|
if (!this.shouldSample(t?.errorSampling ?? 0.1)) {
|
|
3613
|
-
|
|
3615
|
+
n.debug("ErrorHandler", `Error not sampled, skipping (errorSampling: ${t?.errorSampling})`, {
|
|
3614
3616
|
errorSampling: t?.errorSampling
|
|
3615
3617
|
});
|
|
3616
3618
|
return;
|
|
3617
3619
|
}
|
|
3618
|
-
|
|
3620
|
+
n.warn(
|
|
3619
3621
|
"ErrorHandler",
|
|
3620
3622
|
`JavaScript error captured: ${e.message} (filename: ${e.filename}, lineno: ${e.lineno})`,
|
|
3621
3623
|
{
|
|
@@ -3634,12 +3636,12 @@ class $t extends p {
|
|
|
3634
3636
|
handleUnhandledRejection = (e) => {
|
|
3635
3637
|
const t = this.get("config");
|
|
3636
3638
|
if (!this.shouldSample(t?.errorSampling ?? 0.1)) {
|
|
3637
|
-
|
|
3639
|
+
n.debug("ErrorHandler", "Promise rejection not sampled, skipping", {
|
|
3638
3640
|
errorSampling: t?.errorSampling
|
|
3639
3641
|
});
|
|
3640
3642
|
return;
|
|
3641
3643
|
}
|
|
3642
|
-
|
|
3644
|
+
n.warn("ErrorHandler", `Unhandled promise rejection captured (reason: ${typeof e.reason})`, {
|
|
3643
3645
|
reason: typeof e.reason
|
|
3644
3646
|
});
|
|
3645
3647
|
let s = "Unknown rejection";
|
|
@@ -3670,37 +3672,37 @@ class jt extends p {
|
|
|
3670
3672
|
super(), this.eventManager = e, this.originalFetch = window.fetch, this.originalXHROpen = XMLHttpRequest.prototype.open, this.originalXHRSend = XMLHttpRequest.prototype.send;
|
|
3671
3673
|
}
|
|
3672
3674
|
startTracking() {
|
|
3673
|
-
|
|
3675
|
+
n.debug("NetworkHandler", "Starting network error tracking"), this.interceptFetch(), this.interceptXHR();
|
|
3674
3676
|
}
|
|
3675
3677
|
stopTracking() {
|
|
3676
|
-
|
|
3678
|
+
n.debug("NetworkHandler", "Stopping network error tracking"), window.fetch = this.originalFetch, XMLHttpRequest.prototype.open = this.originalXHROpen, XMLHttpRequest.prototype.send = this.originalXHRSend;
|
|
3677
3679
|
}
|
|
3678
3680
|
interceptFetch() {
|
|
3679
3681
|
window.fetch = async (e, t) => {
|
|
3680
|
-
const s = Date.now(),
|
|
3682
|
+
const s = Date.now(), i = typeof e == "string" ? e : e.toString(), a = t?.method ?? "GET";
|
|
3681
3683
|
try {
|
|
3682
3684
|
const o = await this.originalFetch(e, t), l = Date.now() - s;
|
|
3683
|
-
return o.ok || (
|
|
3685
|
+
return o.ok || (n.debug("NetworkHandler", "Fetch error detected", {
|
|
3684
3686
|
method: a,
|
|
3685
|
-
url: this.normalizeUrlForTracking(
|
|
3687
|
+
url: this.normalizeUrlForTracking(i),
|
|
3686
3688
|
status: o.status,
|
|
3687
3689
|
statusText: o.statusText
|
|
3688
3690
|
}), this.trackNetworkError(
|
|
3689
3691
|
a.toUpperCase(),
|
|
3690
|
-
this.normalizeUrlForTracking(
|
|
3692
|
+
this.normalizeUrlForTracking(i),
|
|
3691
3693
|
o.status,
|
|
3692
3694
|
o.statusText,
|
|
3693
3695
|
l
|
|
3694
3696
|
)), o;
|
|
3695
3697
|
} catch (o) {
|
|
3696
3698
|
const l = Date.now() - s, c = o instanceof Error ? o.message : "Network Error";
|
|
3697
|
-
throw
|
|
3699
|
+
throw n.debug("NetworkHandler", "Fetch exception caught", {
|
|
3698
3700
|
method: a,
|
|
3699
|
-
url: this.normalizeUrlForTracking(
|
|
3701
|
+
url: this.normalizeUrlForTracking(i),
|
|
3700
3702
|
error: c
|
|
3701
3703
|
}), this.trackNetworkError(
|
|
3702
3704
|
a.toUpperCase(),
|
|
3703
|
-
this.normalizeUrlForTracking(
|
|
3705
|
+
this.normalizeUrlForTracking(i),
|
|
3704
3706
|
void 0,
|
|
3705
3707
|
c,
|
|
3706
3708
|
l
|
|
@@ -3709,7 +3711,7 @@ class jt extends p {
|
|
|
3709
3711
|
};
|
|
3710
3712
|
}
|
|
3711
3713
|
interceptXHR() {
|
|
3712
|
-
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, i = this.originalXHRSend;
|
|
3713
3715
|
XMLHttpRequest.prototype.open = function(a, o, l, c, d) {
|
|
3714
3716
|
const u = l ?? !0, g = this;
|
|
3715
3717
|
return g._tracelogStartTime = Date.now(), g._tracelogMethod = a.toUpperCase(), g._tracelogUrl = o.toString(), s.call(this, a, o, u, c, d);
|
|
@@ -3720,7 +3722,7 @@ class jt extends p {
|
|
|
3720
3722
|
const y = Date.now() - l;
|
|
3721
3723
|
if (o.status === 0 || o.status >= 400) {
|
|
3722
3724
|
const I = o.statusText || "Request Failed";
|
|
3723
|
-
|
|
3725
|
+
n.debug("NetworkHandler", "XHR error detected", {
|
|
3724
3726
|
method: c,
|
|
3725
3727
|
url: t(d),
|
|
3726
3728
|
status: o.status,
|
|
@@ -3730,13 +3732,13 @@ class jt extends p {
|
|
|
3730
3732
|
}
|
|
3731
3733
|
if (u)
|
|
3732
3734
|
return u.call(o, g);
|
|
3733
|
-
},
|
|
3735
|
+
}, i.call(this, a);
|
|
3734
3736
|
};
|
|
3735
3737
|
}
|
|
3736
|
-
trackNetworkError(e, t, s,
|
|
3738
|
+
trackNetworkError(e, t, s, i, a) {
|
|
3737
3739
|
const o = this.get("config");
|
|
3738
3740
|
if (!this.shouldSample(o?.errorSampling ?? 0.1)) {
|
|
3739
|
-
|
|
3741
|
+
n.debug(
|
|
3740
3742
|
"NetworkHandler",
|
|
3741
3743
|
`Network error not sampled, skipping (errorSampling: ${o?.errorSampling}, method: ${e}, url: ${t})`,
|
|
3742
3744
|
{
|
|
@@ -3747,19 +3749,19 @@ class jt extends p {
|
|
|
3747
3749
|
);
|
|
3748
3750
|
return;
|
|
3749
3751
|
}
|
|
3750
|
-
|
|
3752
|
+
n.warn(
|
|
3751
3753
|
"NetworkHandler",
|
|
3752
|
-
`Network error tracked: ${e} ${t} (status: ${s}, statusText: ${
|
|
3753
|
-
{ method: e, url: t, status: s, statusText:
|
|
3754
|
+
`Network error tracked: ${e} ${t} (status: ${s}, statusText: ${i}, duration: ${a}ms)`,
|
|
3755
|
+
{ method: e, url: t, status: s, statusText: i, duration: a }
|
|
3754
3756
|
), this.eventManager.track({
|
|
3755
3757
|
type: h.ERROR,
|
|
3756
3758
|
error_data: {
|
|
3757
3759
|
type: D.NETWORK_ERROR,
|
|
3758
|
-
message:
|
|
3760
|
+
message: i,
|
|
3759
3761
|
method: e,
|
|
3760
3762
|
url: t,
|
|
3761
3763
|
status: s,
|
|
3762
|
-
statusText:
|
|
3764
|
+
statusText: i,
|
|
3763
3765
|
duration: a
|
|
3764
3766
|
}
|
|
3765
3767
|
});
|
|
@@ -3798,16 +3800,16 @@ class Gt extends p {
|
|
|
3798
3800
|
}
|
|
3799
3801
|
async init(e) {
|
|
3800
3802
|
if (this.isInitialized) {
|
|
3801
|
-
|
|
3803
|
+
n.debug("App", "App already initialized, skipping re-initialization", { projectId: e.id });
|
|
3802
3804
|
return;
|
|
3803
3805
|
}
|
|
3804
|
-
|
|
3806
|
+
n.info("App", "App initialization started", { projectId: e.id }), this.validateAppReadiness(e);
|
|
3805
3807
|
try {
|
|
3806
|
-
this.initStorage(), await this.setState(e), await this.setIntegrations(), this.setEventManager(), await this.initHandlers(), this.isInitialized = !0,
|
|
3808
|
+
this.initStorage(), await this.setState(e), await this.setIntegrations(), this.setEventManager(), await this.initHandlers(), this.isInitialized = !0, n.info("App", "App initialization completed successfully", {
|
|
3807
3809
|
projectId: e.id
|
|
3808
3810
|
});
|
|
3809
3811
|
} catch (t) {
|
|
3810
|
-
throw this.isInitialized = !1,
|
|
3812
|
+
throw this.isInitialized = !1, n.error("App", "App initialization failed", { projectId: e.id, error: t }), t;
|
|
3811
3813
|
}
|
|
3812
3814
|
}
|
|
3813
3815
|
/**
|
|
@@ -3818,19 +3820,19 @@ class Gt extends p {
|
|
|
3818
3820
|
*/
|
|
3819
3821
|
validateAppReadiness(e) {
|
|
3820
3822
|
if (!e?.id)
|
|
3821
|
-
throw
|
|
3823
|
+
throw n.clientError("App", "Configuration integrity check failed - missing project ID", {
|
|
3822
3824
|
hasConfig: !!e,
|
|
3823
3825
|
hasId: !!e?.id
|
|
3824
3826
|
}), new Q("Configuration integrity check failed", "app");
|
|
3825
3827
|
}
|
|
3826
3828
|
sendCustomEvent(e, t) {
|
|
3827
3829
|
if (!this.eventManager) {
|
|
3828
|
-
|
|
3830
|
+
n.warn("App", "Custom event attempted before eventManager initialization", { eventName: e });
|
|
3829
3831
|
return;
|
|
3830
3832
|
}
|
|
3831
|
-
const { valid: s, error:
|
|
3833
|
+
const { valid: s, error: i, sanitizedMetadata: a } = vt(e, t);
|
|
3832
3834
|
if (s)
|
|
3833
|
-
|
|
3835
|
+
n.debug("App", "Custom event validated and queued", { eventName: e, hasMetadata: !!a }), this.eventManager.track({
|
|
3834
3836
|
type: h.CUSTOM,
|
|
3835
3837
|
custom_event: {
|
|
3836
3838
|
name: e,
|
|
@@ -3839,23 +3841,23 @@ class Gt extends p {
|
|
|
3839
3841
|
});
|
|
3840
3842
|
else {
|
|
3841
3843
|
const o = this.get("config")?.mode;
|
|
3842
|
-
if (
|
|
3844
|
+
if (n.clientError("App", `Custom event validation failed: ${i ?? "unknown error"}`, {
|
|
3843
3845
|
eventName: e,
|
|
3844
|
-
validationError:
|
|
3846
|
+
validationError: i,
|
|
3845
3847
|
hasMetadata: !!t,
|
|
3846
3848
|
mode: o
|
|
3847
3849
|
}), o === "qa" || o === "debug")
|
|
3848
3850
|
throw new Error(
|
|
3849
|
-
`custom event "${e}" validation failed (${
|
|
3851
|
+
`custom event "${e}" validation failed (${i ?? "unknown error"}). Please, review your event data and try again.`
|
|
3850
3852
|
);
|
|
3851
3853
|
}
|
|
3852
3854
|
}
|
|
3853
3855
|
destroy() {
|
|
3854
3856
|
if (!this.isInitialized) {
|
|
3855
|
-
|
|
3857
|
+
n.warn("App", "Destroy called but app was not initialized");
|
|
3856
3858
|
return;
|
|
3857
3859
|
}
|
|
3858
|
-
|
|
3860
|
+
n.info("App", "App cleanup started"), this.googleAnalytics && this.googleAnalytics.cleanup(), this.sessionHandler && this.sessionHandler.stopTracking(), this.pageViewHandler && this.pageViewHandler.stopTracking(), this.clickHandler && this.clickHandler.stopTracking(), this.scrollHandler && this.scrollHandler.stopTracking(), this.performanceHandler && this.performanceHandler.stopTracking(), this.errorHandler && this.errorHandler.stopTracking(), this.networkHandler && this.networkHandler.stopTracking(), this.suppressNextScrollTimer && (clearTimeout(this.suppressNextScrollTimer), this.suppressNextScrollTimer = null), this.eventManager && this.eventManager.stop(), this.set("hasStartSession", !1), this.set("suppressNextScroll", !1), this.set("sessionId", null), this.isInitialized = !1, n.info("App", "App cleanup completed successfully");
|
|
3859
3861
|
}
|
|
3860
3862
|
async setState(e) {
|
|
3861
3863
|
this.setApiUrl(e.id, e.allowHttp), await this.setConfig(e), this.setUserId(), this.setDevice(), this.setPageUrl();
|
|
@@ -3902,7 +3904,7 @@ class Gt extends p {
|
|
|
3902
3904
|
initSessionHandler() {
|
|
3903
3905
|
if (!this.storageManager || !this.eventManager)
|
|
3904
3906
|
throw new Error("StorageManager and EventManager must be initialized before SessionHandler");
|
|
3905
|
-
this.sessionHandler = new
|
|
3907
|
+
this.sessionHandler = new Pt(this.storageManager, this.eventManager), this.sessionHandler.startTracking();
|
|
3906
3908
|
}
|
|
3907
3909
|
initPageViewHandler() {
|
|
3908
3910
|
if (!this.eventManager)
|
|
@@ -3958,8 +3960,8 @@ const Qt = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
|
|
|
3958
3960
|
let v = null, T = !1;
|
|
3959
3961
|
const qt = async (r) => {
|
|
3960
3962
|
try {
|
|
3961
|
-
if (
|
|
3962
|
-
throw
|
|
3963
|
+
if (n.info("API", "Library initialization started", { id: r.id }), typeof window > "u" || typeof document > "u")
|
|
3964
|
+
throw n.clientError(
|
|
3963
3965
|
"API",
|
|
3964
3966
|
"Browser environment required - this library can only be used in a browser environment",
|
|
3965
3967
|
{
|
|
@@ -3968,36 +3970,36 @@ const qt = async (r) => {
|
|
|
3968
3970
|
}
|
|
3969
3971
|
), new Error("This library can only be used in a browser environment");
|
|
3970
3972
|
if (v) {
|
|
3971
|
-
|
|
3973
|
+
n.debug("API", "Library already initialized, skipping duplicate initialization", {
|
|
3972
3974
|
projectId: r.id
|
|
3973
3975
|
});
|
|
3974
3976
|
return;
|
|
3975
3977
|
}
|
|
3976
3978
|
if (T) {
|
|
3977
|
-
|
|
3979
|
+
n.debug("API", "Concurrent initialization detected, waiting for completion", { projectId: r.id });
|
|
3978
3980
|
let s = 0;
|
|
3979
|
-
const
|
|
3980
|
-
for (; T && s <
|
|
3981
|
+
const i = me.MAX_CONCURRENT_RETRIES, a = me.CONCURRENT_RETRY_DELAY_MS;
|
|
3982
|
+
for (; T && s < i; )
|
|
3981
3983
|
await new Promise((o) => setTimeout(o, a)), s++;
|
|
3982
3984
|
if (v) {
|
|
3983
|
-
|
|
3985
|
+
n.debug("API", "Concurrent initialization completed successfully", {
|
|
3984
3986
|
projectId: r.id,
|
|
3985
3987
|
retriesUsed: s
|
|
3986
3988
|
});
|
|
3987
3989
|
return;
|
|
3988
3990
|
}
|
|
3989
3991
|
if (T)
|
|
3990
|
-
throw
|
|
3992
|
+
throw n.error("API", "Initialization timeout - concurrent initialization took too long", {
|
|
3991
3993
|
projectId: r.id,
|
|
3992
3994
|
retriesUsed: s,
|
|
3993
|
-
maxRetries:
|
|
3995
|
+
maxRetries: i
|
|
3994
3996
|
}), new Error("App initialization timeout - concurrent initialization took too long");
|
|
3995
3997
|
}
|
|
3996
|
-
T = !0,
|
|
3998
|
+
T = !0, n.debug("API", "Validating and normalizing configuration", { projectId: r.id });
|
|
3997
3999
|
const e = dt(r);
|
|
3998
|
-
|
|
4000
|
+
n.debug("API", "Creating App instance", { projectId: e.id });
|
|
3999
4001
|
const t = new Gt();
|
|
4000
|
-
await t.init(e), v = t,
|
|
4002
|
+
await t.init(e), v = t, n.info("API", "Library initialization completed successfully", {
|
|
4001
4003
|
projectId: e.id
|
|
4002
4004
|
});
|
|
4003
4005
|
} catch (e) {
|
|
@@ -4005,26 +4007,26 @@ const qt = async (r) => {
|
|
|
4005
4007
|
try {
|
|
4006
4008
|
v.destroy();
|
|
4007
4009
|
} catch (t) {
|
|
4008
|
-
|
|
4010
|
+
n.warn("API", "Failed to cleanup partially initialized app", { cleanupError: t });
|
|
4009
4011
|
}
|
|
4010
|
-
throw v = null,
|
|
4012
|
+
throw v = null, n.error("API", "Initialization failed", { error: e }), e;
|
|
4011
4013
|
} finally {
|
|
4012
4014
|
T = !1;
|
|
4013
4015
|
}
|
|
4014
4016
|
}, Wt = (r, e) => {
|
|
4015
4017
|
try {
|
|
4016
4018
|
if (!v)
|
|
4017
|
-
throw
|
|
4019
|
+
throw n.clientError("API", "Custom event failed - Library not initialized. Please call TraceLog.init() first", {
|
|
4018
4020
|
eventName: r,
|
|
4019
4021
|
hasMetadata: !!e
|
|
4020
4022
|
}), new Error("App not initialized");
|
|
4021
|
-
|
|
4023
|
+
n.debug("API", "Sending custom event", {
|
|
4022
4024
|
eventName: r,
|
|
4023
4025
|
hasMetadata: !!e,
|
|
4024
4026
|
metadataKeys: e ? Object.keys(e) : []
|
|
4025
4027
|
}), v.sendCustomEvent(r, e);
|
|
4026
4028
|
} catch (t) {
|
|
4027
|
-
if (
|
|
4029
|
+
if (n.error("API", "Event tracking failed", { eventName: r, error: t, hasMetadata: !!e }), t instanceof Error && (t.message === "App not initialized" || t.message.includes("validation failed")))
|
|
4028
4030
|
throw t;
|
|
4029
4031
|
}
|
|
4030
4032
|
}, Xt = () => v !== null, Kt = () => ({
|
|
@@ -4033,11 +4035,11 @@ const qt = async (r) => {
|
|
|
4033
4035
|
hasInstance: v !== null
|
|
4034
4036
|
}), Yt = () => {
|
|
4035
4037
|
try {
|
|
4036
|
-
if (
|
|
4037
|
-
throw
|
|
4038
|
-
v.destroy(), v = null, T = !1,
|
|
4038
|
+
if (n.info("API", "Library cleanup initiated"), !v)
|
|
4039
|
+
throw n.warn("API", "Cleanup called but Library was not initialized"), new Error("App not initialized");
|
|
4040
|
+
v.destroy(), v = null, T = !1, n.info("API", "Library cleanup completed successfully");
|
|
4039
4041
|
} catch (r) {
|
|
4040
|
-
|
|
4042
|
+
n.error("API", "Cleanup failed", { error: r, hadApp: !!v, wasInitializing: T });
|
|
4041
4043
|
}
|
|
4042
4044
|
}, Jt = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
|
|
4043
4045
|
__proto__: null,
|