@tracelog/lib 0.0.8 → 0.1.0
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 +897 -826
- package/dist/cjs/constants/limits.constants.d.ts +2 -0
- package/dist/cjs/constants/limits.constants.js +4 -1
- package/dist/cjs/handlers/scroll.handler.d.ts +10 -1
- package/dist/cjs/handlers/scroll.handler.js +157 -17
- package/dist/esm/constants/limits.constants.d.ts +2 -0
- package/dist/esm/constants/limits.constants.js +3 -0
- package/dist/esm/handlers/scroll.handler.d.ts +10 -1
- package/dist/esm/handlers/scroll.handler.js +158 -18
- package/package.json +1 -1
package/dist/browser/tracelog.js
CHANGED
|
@@ -1,19 +1,19 @@
|
|
|
1
|
-
var
|
|
2
|
-
const
|
|
1
|
+
var w = /* @__PURE__ */ ((r) => (r.Mobile = "mobile", r.Tablet = "tablet", r.Desktop = "desktop", r.Unknown = "unknown", r))(w || {});
|
|
2
|
+
const B = {};
|
|
3
3
|
class p {
|
|
4
4
|
get(e) {
|
|
5
|
-
return
|
|
5
|
+
return B[e];
|
|
6
6
|
}
|
|
7
7
|
set(e, t) {
|
|
8
|
-
const s =
|
|
9
|
-
|
|
8
|
+
const s = B[e];
|
|
9
|
+
B[e] = t, (e === "sessionId" || e === "config" || e === "hasStartSession") && i.debug("StateManager", "Critical state updated", {
|
|
10
10
|
key: e,
|
|
11
11
|
oldValue: e === "config" ? !!s : s,
|
|
12
12
|
newValue: e === "config" ? !!t : t
|
|
13
13
|
});
|
|
14
14
|
}
|
|
15
15
|
}
|
|
16
|
-
class
|
|
16
|
+
class ke extends p {
|
|
17
17
|
/**
|
|
18
18
|
* Client-facing error - Configuration/usage errors by the client
|
|
19
19
|
* Console: qa and debug modes | Events: NODE_ENV=dev
|
|
@@ -98,16 +98,16 @@ class Re extends p {
|
|
|
98
98
|
return "log";
|
|
99
99
|
}
|
|
100
100
|
}
|
|
101
|
-
logMessage(e, t, s,
|
|
101
|
+
logMessage(e, t, s, n) {
|
|
102
102
|
if (!this.shouldShowLog(e))
|
|
103
103
|
return;
|
|
104
104
|
const a = this.formatMessage(t, s), o = this.getConsoleMethod(e);
|
|
105
|
-
|
|
105
|
+
n !== void 0 ? console[o](a, n) : console[o](a);
|
|
106
106
|
}
|
|
107
107
|
/**
|
|
108
108
|
* Dispatches tracelog:log events for E2E testing and development debugging
|
|
109
109
|
*/
|
|
110
|
-
dispatchEvent(e, t, s,
|
|
110
|
+
dispatchEvent(e, t, s, n) {
|
|
111
111
|
if (!(typeof window > "u" || typeof CustomEvent > "u"))
|
|
112
112
|
try {
|
|
113
113
|
const a = new CustomEvent("tracelog:log", {
|
|
@@ -116,58 +116,58 @@ class Re extends p {
|
|
|
116
116
|
level: e,
|
|
117
117
|
namespace: t,
|
|
118
118
|
message: s,
|
|
119
|
-
data:
|
|
119
|
+
data: n
|
|
120
120
|
}
|
|
121
121
|
});
|
|
122
122
|
window.dispatchEvent(a);
|
|
123
123
|
} catch {
|
|
124
|
-
console.log(`[TraceLog:${t}] ${s}`,
|
|
124
|
+
console.log(`[TraceLog:${t}] ${s}`, n);
|
|
125
125
|
}
|
|
126
126
|
}
|
|
127
127
|
}
|
|
128
|
-
const
|
|
129
|
-
let
|
|
130
|
-
const
|
|
131
|
-
typeof window < "u" && !
|
|
132
|
-
},
|
|
128
|
+
const i = new ke();
|
|
129
|
+
let Z, we;
|
|
130
|
+
const Ne = () => {
|
|
131
|
+
typeof window < "u" && !Z && (Z = window.matchMedia("(pointer: coarse)"), we = window.matchMedia("(hover: none)"));
|
|
132
|
+
}, Ie = () => {
|
|
133
133
|
try {
|
|
134
|
-
|
|
134
|
+
i.debug("DeviceDetector", "Starting device detection");
|
|
135
135
|
const r = navigator;
|
|
136
136
|
if (r.userAgentData && typeof r.userAgentData.mobile == "boolean") {
|
|
137
|
-
if (
|
|
137
|
+
if (i.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
|
|
142
|
-
const d = r.userAgentData.mobile ?
|
|
143
|
-
return
|
|
141
|
+
return i.debug("DeviceDetector", "Device detected as tablet via platform hint"), w.Tablet;
|
|
142
|
+
const d = r.userAgentData.mobile ? w.Mobile : w.Desktop;
|
|
143
|
+
return i.debug("DeviceDetector", "Device detected via User-Agent hints", { result: d }), d;
|
|
144
144
|
}
|
|
145
|
-
|
|
146
|
-
const e = window.innerWidth, t =
|
|
145
|
+
i.debug("DeviceDetector", "Using fallback detection methods"), Ne();
|
|
146
|
+
const e = window.innerWidth, t = Z?.matches ?? !1, s = we?.matches ?? !1, n = "ontouchstart" in window || navigator.maxTouchPoints > 0, a = navigator.userAgent.toLowerCase(), o = /mobile|android|iphone|ipod|blackberry|iemobile|opera mini/.test(a), l = /tablet|ipad|android(?!.*mobile)/.test(a), c = {
|
|
147
147
|
width: e,
|
|
148
148
|
hasCoarsePointer: t,
|
|
149
149
|
hasNoHover: s,
|
|
150
|
-
hasTouchSupport:
|
|
150
|
+
hasTouchSupport: n,
|
|
151
151
|
isMobileUA: o,
|
|
152
152
|
isTabletUA: l,
|
|
153
153
|
maxTouchPoints: navigator.maxTouchPoints
|
|
154
154
|
};
|
|
155
|
-
return e <= 767 || o &&
|
|
155
|
+
return e <= 767 || o && n ? (i.debug("DeviceDetector", "Device detected as mobile", c), w.Mobile) : e >= 768 && e <= 1024 || l || t && s && n ? (i.debug("DeviceDetector", "Device detected as tablet", c), w.Tablet) : (i.debug("DeviceDetector", "Device detected as desktop", c), w.Desktop);
|
|
156
156
|
} catch (r) {
|
|
157
|
-
return
|
|
157
|
+
return i.warn("DeviceDetector", "Device detection failed, defaulting to desktop", {
|
|
158
158
|
error: r instanceof Error ? r.message : r
|
|
159
|
-
}),
|
|
159
|
+
}), w.Desktop;
|
|
160
160
|
}
|
|
161
|
-
},
|
|
162
|
-
samplingRate:
|
|
161
|
+
}, He = 2, Pe = 10, Te = 1, re = 500, ee = 3e4, te = 864e5, ae = 120, oe = 8 * 1024, ce = 10, le = 10, C = 255, M = 1e3, q = 100, de = 3, N = 2, Ue = 4, Oe = 0.75, De = 0.2, xe = 2e3, Fe = 1e3, ze = 10, F = 10, X = 3, Ve = 1e3, R = 15 * 60 * 1e3, $e = 3e4, Me = 1e3, Ae = 250, je = 2e3, he = 1e3, Ge = 1e4, Qe = 2500, ue = 1e3, ge = 3e4, fe = 1e3, We = 24, Be = 24 * 60 * 60 * 1e3, qe = Me, Xe = 5e3, Ke = 2e3, Ye = 2, Je = 3, K = 24 * 60 * 60 * 1e3, Y = 2 * 60 * 1e3, Ce = {
|
|
162
|
+
samplingRate: Te,
|
|
163
163
|
tags: [],
|
|
164
164
|
excludedUrlPaths: []
|
|
165
|
-
},
|
|
166
|
-
...
|
|
165
|
+
}, Ze = (r) => ({
|
|
166
|
+
...Ce,
|
|
167
167
|
...r,
|
|
168
168
|
sessionTimeout: R,
|
|
169
169
|
allowHttp: !1
|
|
170
|
-
}), z = "data-tl",
|
|
170
|
+
}), z = "data-tl", me = [
|
|
171
171
|
"button",
|
|
172
172
|
"a",
|
|
173
173
|
'input[type="button"]',
|
|
@@ -199,14 +199,14 @@ const ke = () => {
|
|
|
199
199
|
".menu-item",
|
|
200
200
|
"[data-testid]",
|
|
201
201
|
'[tabindex="0"]'
|
|
202
|
-
],
|
|
202
|
+
], et = ["utm_source", "utm_medium", "utm_campaign", "utm_term", "utm_content"], pe = {
|
|
203
203
|
/** Maximum number of retries when waiting for concurrent initialization */
|
|
204
204
|
MAX_CONCURRENT_RETRIES: 20,
|
|
205
205
|
/** Delay between retries when waiting for concurrent initialization (ms) */
|
|
206
206
|
CONCURRENT_RETRY_DELAY_MS: 50,
|
|
207
207
|
/** Timeout for overall initialization process (ms) */
|
|
208
208
|
INITIALIZATION_TIMEOUT_MS: 1e4
|
|
209
|
-
},
|
|
209
|
+
}, E = {
|
|
210
210
|
/** Maximum number of consecutive failures before opening circuit */
|
|
211
211
|
MAX_FAILURES: 10,
|
|
212
212
|
/** Initial backoff delay when circuit opens (ms) */
|
|
@@ -218,12 +218,12 @@ const ke = () => {
|
|
|
218
218
|
/** Time-based recovery period for circuit breaker (ms) */
|
|
219
219
|
RECOVERY_TIME_MS: 3e4
|
|
220
220
|
// 30 seconds
|
|
221
|
-
},
|
|
221
|
+
}, ve = {
|
|
222
222
|
/** Timeout for session synchronization operations (ms) */
|
|
223
223
|
SYNC_TIMEOUT_MS: 2e3,
|
|
224
224
|
/** Maximum retry attempts for session operations */
|
|
225
225
|
MAX_RETRY_ATTEMPTS: 3
|
|
226
|
-
},
|
|
226
|
+
}, tt = {
|
|
227
227
|
/** Multiplier for scroll debounce time when suppressing scroll events */
|
|
228
228
|
SUPPRESS_MULTIPLIER: 2
|
|
229
229
|
}, _e = [
|
|
@@ -233,18 +233,18 @@ const ke = () => {
|
|
|
233
233
|
/<iframe\b[^<]*(?:(?!<\/iframe>)<[^<]*)*<\/iframe>/gi,
|
|
234
234
|
/<embed\b[^>]*>/gi,
|
|
235
235
|
/<object\b[^<]*(?:(?!<\/object>)<[^<]*)*<\/object>/gi
|
|
236
|
-
],
|
|
236
|
+
], b = "tl", Se = (r) => r ? `${b}:${r}:uid` : `${b}:uid`, st = (r) => r ? `${b}:${r}:queue` : `${b}:queue`, it = (r) => r ? `${b}:${r}:session` : `${b}:session`, J = (r) => r ? `${b}:${r}:cross_tab_session` : `${b}:cross_tab_session`, be = (r, e) => `${b}:${r}:tab:${e}:info`, V = (r) => r ? `${b}:${r}:recovery` : `${b}:recovery`, nt = (r) => r ? `${b}:${r}:broadcast` : `${b}:broadcast`, rt = /* @__PURE__ */ new Set([
|
|
237
237
|
"mode",
|
|
238
238
|
"tags",
|
|
239
239
|
"samplingRate",
|
|
240
240
|
"excludedUrlPaths",
|
|
241
241
|
"ipExcluded"
|
|
242
|
-
]),
|
|
242
|
+
]), I = {
|
|
243
243
|
// Project ID validation - consistent message across all layers
|
|
244
244
|
MISSING_PROJECT_ID: "Project ID is required",
|
|
245
245
|
PROJECT_ID_EMPTY_AFTER_TRIM: "Project ID is required",
|
|
246
246
|
// Session timeout validation
|
|
247
|
-
INVALID_SESSION_TIMEOUT: `Session timeout must be between ${
|
|
247
|
+
INVALID_SESSION_TIMEOUT: `Session timeout must be between ${ee}ms (30 seconds) and ${te}ms (24 hours)`,
|
|
248
248
|
INVALID_ERROR_SAMPLING_RATE: "Error sampling must be between 0 and 1",
|
|
249
249
|
// Integration validation
|
|
250
250
|
INVALID_GOOGLE_ANALYTICS_ID: "Google Analytics measurement ID is required when integration is enabled",
|
|
@@ -254,132 +254,132 @@ const ke = () => {
|
|
|
254
254
|
INVALID_GLOBAL_METADATA: "Global metadata must be an object",
|
|
255
255
|
// Array validation
|
|
256
256
|
INVALID_SENSITIVE_QUERY_PARAMS: "Sensitive query params must be an array of strings"
|
|
257
|
-
},
|
|
258
|
-
|
|
257
|
+
}, at = () => {
|
|
258
|
+
i.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
|
-
|
|
264
|
-
const
|
|
265
|
-
if (
|
|
263
|
+
et.forEach((s) => {
|
|
264
|
+
const n = r.get(s);
|
|
265
|
+
if (n) {
|
|
266
266
|
const a = s.split("utm_")[1];
|
|
267
|
-
e[a] =
|
|
267
|
+
e[a] = n, i.debug("UTMParams", "Found UTM parameter", { param: s, key: a, value: n });
|
|
268
268
|
}
|
|
269
269
|
});
|
|
270
270
|
const t = Object.keys(e).length ? e : void 0;
|
|
271
|
-
return t ?
|
|
271
|
+
return t ? i.debug("UTMParams", "UTM parameters extracted successfully", {
|
|
272
272
|
parameterCount: Object.keys(t).length,
|
|
273
273
|
parameters: Object.keys(t)
|
|
274
|
-
}) :
|
|
274
|
+
}) : i.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 i.verbose("UUIDUtils", "Generated new UUID", { uuid: r }), r;
|
|
281
281
|
};
|
|
282
|
-
var
|
|
283
|
-
class
|
|
282
|
+
var _ = /* @__PURE__ */ ((r) => (r.HttpSkip = "http-skip", r.HttpLocal = "http-local", r))(_ || {}), g = /* @__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))(g || {}), j = /* @__PURE__ */ ((r) => (r.UP = "up", r.DOWN = "down", r))(j || {}), O = /* @__PURE__ */ ((r) => (r.JS_ERROR = "js_error", r.PROMISE_REJECTION = "promise_rejection", r.NETWORK_ERROR = "network_error", r))(O || {}), 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
|
+
class D extends Error {
|
|
284
284
|
constructor(e, t, s) {
|
|
285
285
|
super(e), this.errorCode = t, this.layer = s, this.name = this.constructor.name, Error.captureStackTrace && Error.captureStackTrace(this, this.constructor);
|
|
286
286
|
}
|
|
287
287
|
}
|
|
288
|
-
class Q extends
|
|
288
|
+
class Q extends D {
|
|
289
289
|
constructor(e = "Project ID is required", t = "config") {
|
|
290
290
|
super(e, "PROJECT_ID_INVALID", t);
|
|
291
291
|
}
|
|
292
292
|
}
|
|
293
|
-
class
|
|
293
|
+
class U extends D {
|
|
294
294
|
constructor(e, t = "config") {
|
|
295
295
|
super(e, "APP_CONFIG_INVALID", t);
|
|
296
296
|
}
|
|
297
297
|
}
|
|
298
|
-
class
|
|
298
|
+
class ot extends D {
|
|
299
299
|
constructor(e, t = "config") {
|
|
300
300
|
super(e, "SESSION_TIMEOUT_INVALID", t);
|
|
301
301
|
}
|
|
302
302
|
}
|
|
303
|
-
class
|
|
303
|
+
class ct extends D {
|
|
304
304
|
constructor(e, t = "config") {
|
|
305
305
|
super(e, "SAMPLING_RATE_INVALID", t);
|
|
306
306
|
}
|
|
307
307
|
}
|
|
308
|
-
class ye extends
|
|
308
|
+
class ye extends D {
|
|
309
309
|
constructor(e, t = "config") {
|
|
310
310
|
super(e, "INTEGRATION_INVALID", t);
|
|
311
311
|
}
|
|
312
312
|
}
|
|
313
|
-
const
|
|
313
|
+
const lt = (r) => {
|
|
314
314
|
if (!r || typeof r != "object")
|
|
315
|
-
throw
|
|
315
|
+
throw i.clientError("ConfigValidation", "Configuration must be an object", { config: r }), new U("Configuration must be an object", "config");
|
|
316
316
|
if (!("id" in r))
|
|
317
|
-
throw
|
|
317
|
+
throw i.clientError("ConfigValidation", "Project ID is missing from configuration"), new Q(I.MISSING_PROJECT_ID, "config");
|
|
318
318
|
if (r.id === null || r.id === void 0 || typeof r.id != "string")
|
|
319
|
-
throw
|
|
319
|
+
throw i.clientError("ConfigValidation", "Project ID must be a non-empty string", {
|
|
320
320
|
providedId: r.id,
|
|
321
321
|
type: typeof r.id
|
|
322
|
-
}), new Q(
|
|
323
|
-
if (r.sessionTimeout !== void 0 && (typeof r.sessionTimeout != "number" || r.sessionTimeout <
|
|
324
|
-
throw
|
|
322
|
+
}), new Q(I.MISSING_PROJECT_ID, "config");
|
|
323
|
+
if (r.sessionTimeout !== void 0 && (typeof r.sessionTimeout != "number" || r.sessionTimeout < ee || r.sessionTimeout > te))
|
|
324
|
+
throw i.clientError("ConfigValidation", "Invalid session timeout", {
|
|
325
325
|
provided: r.sessionTimeout,
|
|
326
|
-
min:
|
|
327
|
-
max:
|
|
328
|
-
}), new
|
|
326
|
+
min: ee,
|
|
327
|
+
max: te
|
|
328
|
+
}), new ot(I.INVALID_SESSION_TIMEOUT, "config");
|
|
329
329
|
if (r.globalMetadata !== void 0 && (typeof r.globalMetadata != "object" || r.globalMetadata === null))
|
|
330
|
-
throw
|
|
330
|
+
throw i.clientError("ConfigValidation", "Global metadata must be an object", {
|
|
331
331
|
provided: r.globalMetadata,
|
|
332
332
|
type: typeof r.globalMetadata
|
|
333
|
-
}), new
|
|
334
|
-
if (r.scrollContainerSelectors !== void 0 &&
|
|
333
|
+
}), new U(I.INVALID_GLOBAL_METADATA, "config");
|
|
334
|
+
if (r.scrollContainerSelectors !== void 0 && dt(r.scrollContainerSelectors), r.integrations && ht(r.integrations), r.sensitiveQueryParams !== void 0) {
|
|
335
335
|
if (!Array.isArray(r.sensitiveQueryParams))
|
|
336
|
-
throw
|
|
336
|
+
throw i.clientError("ConfigValidation", "Sensitive query params must be an array", {
|
|
337
337
|
provided: r.sensitiveQueryParams,
|
|
338
338
|
type: typeof r.sensitiveQueryParams
|
|
339
|
-
}), new
|
|
339
|
+
}), new U(I.INVALID_SENSITIVE_QUERY_PARAMS, "config");
|
|
340
340
|
for (const e of r.sensitiveQueryParams)
|
|
341
341
|
if (typeof e != "string")
|
|
342
|
-
throw
|
|
342
|
+
throw i.clientError("ConfigValidation", "All sensitive query params must be strings", {
|
|
343
343
|
param: e,
|
|
344
344
|
type: typeof e
|
|
345
|
-
}), new
|
|
345
|
+
}), new U("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 i.clientError("ConfigValidation", "Invalid error sampling rate", {
|
|
349
349
|
provided: r.errorSampling,
|
|
350
350
|
expected: "0-1"
|
|
351
|
-
}), new
|
|
352
|
-
},
|
|
351
|
+
}), new ct(I.INVALID_ERROR_SAMPLING_RATE, "config");
|
|
352
|
+
}, dt = (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 i.clientError("ConfigValidation", "Invalid scroll container selector", {
|
|
357
357
|
selector: t,
|
|
358
358
|
type: typeof t,
|
|
359
359
|
isEmpty: t === "" || typeof t == "string" && t.trim() === ""
|
|
360
|
-
}), new
|
|
360
|
+
}), new U(I.INVALID_SCROLL_CONTAINER_SELECTORS, "config");
|
|
361
361
|
if (typeof document < "u")
|
|
362
362
|
try {
|
|
363
363
|
document.querySelector(t);
|
|
364
364
|
} catch {
|
|
365
|
-
|
|
365
|
+
i.clientWarn("ConfigValidation", `Invalid CSS selector will be ignored: "${t}"`);
|
|
366
366
|
}
|
|
367
367
|
}
|
|
368
|
-
},
|
|
368
|
+
}, ht = (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 i.clientError("ConfigValidation", "Invalid Google Analytics measurement ID", {
|
|
372
372
|
provided: r.googleAnalytics.measurementId,
|
|
373
373
|
type: typeof r.googleAnalytics.measurementId
|
|
374
|
-
}), new ye(
|
|
374
|
+
}), new ye(I.INVALID_GOOGLE_ANALYTICS_ID, "config");
|
|
375
375
|
const e = r.googleAnalytics.measurementId.trim();
|
|
376
376
|
if (!e.match(/^(G-|UA-)/))
|
|
377
|
-
throw
|
|
377
|
+
throw i.clientError("ConfigValidation", 'Google Analytics measurement ID must start with "G-" or "UA-"', {
|
|
378
378
|
provided: e
|
|
379
379
|
}), new ye('Google Analytics measurement ID must start with "G-" or "UA-"', "config");
|
|
380
380
|
}
|
|
381
|
-
},
|
|
382
|
-
|
|
381
|
+
}, ut = (r) => {
|
|
382
|
+
lt(r);
|
|
383
383
|
const e = {
|
|
384
384
|
...r,
|
|
385
385
|
id: r.id.trim(),
|
|
@@ -387,17 +387,17 @@ const ot = (r) => {
|
|
|
387
387
|
sensitiveQueryParams: r.sensitiveQueryParams ?? []
|
|
388
388
|
};
|
|
389
389
|
if (!e.id)
|
|
390
|
-
throw
|
|
390
|
+
throw i.clientError("ConfigValidation", "Project ID is empty after trimming whitespace", {
|
|
391
391
|
originalId: r.id,
|
|
392
392
|
normalizedId: e.id
|
|
393
|
-
}), new Q(
|
|
393
|
+
}), new Q(I.PROJECT_ID_EMPTY_AFTER_TRIM, "config");
|
|
394
394
|
return e;
|
|
395
|
-
},
|
|
395
|
+
}, Ee = (r) => {
|
|
396
396
|
if (!r || typeof r != "string" || r.trim().length === 0)
|
|
397
|
-
return
|
|
397
|
+
return i.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)), i.warn("Sanitize", "String truncated due to length limit", {
|
|
401
401
|
originalLength: e,
|
|
402
402
|
maxLength: M,
|
|
403
403
|
truncatedLength: t.length
|
|
@@ -407,19 +407,19 @@ 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 && i.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 n = t.trim();
|
|
416
|
+
return (e > 50 || s > 0) && i.debug("Sanitize", "String sanitization completed", {
|
|
417
417
|
originalLength: e,
|
|
418
|
-
sanitizedLength:
|
|
418
|
+
sanitizedLength: n.length,
|
|
419
419
|
xssPatternMatches: s,
|
|
420
420
|
wasTruncated: e > M
|
|
421
|
-
}),
|
|
422
|
-
},
|
|
421
|
+
}), n;
|
|
422
|
+
}, gt = (r) => {
|
|
423
423
|
if (typeof r != "string")
|
|
424
424
|
return "";
|
|
425
425
|
r.length > M && (r = r.slice(0, Math.max(0, M)));
|
|
@@ -427,112 +427,112 @@ const ot = (r) => {
|
|
|
427
427
|
for (const t of _e)
|
|
428
428
|
e = e.replace(t, "");
|
|
429
429
|
return e = e.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'"), e.trim();
|
|
430
|
-
},
|
|
431
|
-
if (e >
|
|
432
|
-
return
|
|
430
|
+
}, W = (r, e = 0) => {
|
|
431
|
+
if (e > de)
|
|
432
|
+
return i.warn("Sanitize", "Maximum object depth exceeded during sanitization", {
|
|
433
433
|
depth: e,
|
|
434
|
-
maxDepth:
|
|
434
|
+
maxDepth: de
|
|
435
435
|
}), null;
|
|
436
436
|
if (r == null)
|
|
437
437
|
return null;
|
|
438
438
|
if (typeof r == "string")
|
|
439
|
-
return
|
|
439
|
+
return Ee(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 ? (i.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
|
-
const t = r.length, s = r.slice(0,
|
|
446
|
-
t >
|
|
445
|
+
const t = r.length, s = r.slice(0, q);
|
|
446
|
+
t > q && i.warn("Sanitize", "Array truncated due to length limit", {
|
|
447
447
|
originalLength: t,
|
|
448
|
-
maxLength:
|
|
448
|
+
maxLength: q,
|
|
449
449
|
depth: e
|
|
450
450
|
});
|
|
451
|
-
const
|
|
452
|
-
return t > 0 &&
|
|
451
|
+
const n = s.map((a) => W(a, e + 1)).filter((a) => a !== null);
|
|
452
|
+
return t > 0 && n.length === 0 && i.warn("Sanitize", "All array items were filtered out during sanitization", { originalLength: t, depth: e }), n;
|
|
453
453
|
}
|
|
454
454
|
if (typeof r == "object") {
|
|
455
|
-
const t = {}, s = Object.entries(r),
|
|
456
|
-
|
|
457
|
-
originalKeys:
|
|
455
|
+
const t = {}, s = Object.entries(r), n = s.length, a = s.slice(0, 20);
|
|
456
|
+
n > 20 && i.warn("Sanitize", "Object keys truncated due to limit", {
|
|
457
|
+
originalKeys: n,
|
|
458
458
|
maxKeys: 20,
|
|
459
459
|
depth: e
|
|
460
460
|
});
|
|
461
461
|
let o = 0;
|
|
462
462
|
for (const [l, c] of a) {
|
|
463
|
-
const d =
|
|
463
|
+
const d = Ee(l);
|
|
464
464
|
if (d) {
|
|
465
|
-
const
|
|
466
|
-
|
|
465
|
+
const h = W(c, e + 1);
|
|
466
|
+
h !== null ? t[d] = h : o++;
|
|
467
467
|
} else
|
|
468
468
|
o++;
|
|
469
469
|
}
|
|
470
|
-
return o > 0 &&
|
|
470
|
+
return o > 0 && i.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
|
|
477
|
-
},
|
|
478
|
-
|
|
476
|
+
return i.debug("Sanitize", "Unknown value type sanitized to null", { type: typeof r, depth: e }), null;
|
|
477
|
+
}, ft = (r) => {
|
|
478
|
+
i.debug("Sanitize", "Starting API config sanitization");
|
|
479
479
|
const e = {};
|
|
480
480
|
if (typeof r != "object" || r === null)
|
|
481
|
-
return
|
|
481
|
+
return i.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, n = 0;
|
|
485
485
|
for (const a of t)
|
|
486
|
-
if (
|
|
486
|
+
if (rt.has(a)) {
|
|
487
487
|
const o = r[a];
|
|
488
488
|
if (a === "excludedUrlPaths") {
|
|
489
489
|
const l = Array.isArray(o) ? o : typeof o == "string" ? [o] : [], c = l.length;
|
|
490
|
-
e.excludedUrlPaths = l.map((
|
|
490
|
+
e.excludedUrlPaths = l.map((h) => gt(String(h))).filter(Boolean);
|
|
491
491
|
const d = c - e.excludedUrlPaths.length;
|
|
492
|
-
d > 0 &&
|
|
492
|
+
d > 0 && i.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, i.debug("Sanitize", "Tags processed", { count: o.length })) : i.warn("Sanitize", "Tags value is not an array", { value: o, type: typeof o });
|
|
498
498
|
else {
|
|
499
|
-
const l =
|
|
500
|
-
l !== null ? e[a] = l :
|
|
499
|
+
const l = W(o);
|
|
500
|
+
l !== null ? e[a] = l : i.warn("Sanitize", "API config value sanitized to null", { key: a, originalValue: o });
|
|
501
501
|
}
|
|
502
502
|
s++;
|
|
503
503
|
} else
|
|
504
|
-
|
|
505
|
-
|
|
504
|
+
n++, i.debug("Sanitize", "API config key not allowed", { key: a });
|
|
505
|
+
i.info("Sanitize", "API config sanitization completed", {
|
|
506
506
|
originalKeys: t.length,
|
|
507
507
|
processedKeys: s,
|
|
508
|
-
filteredKeys:
|
|
508
|
+
filteredKeys: n,
|
|
509
509
|
finalKeys: Object.keys(e).length
|
|
510
510
|
});
|
|
511
511
|
} catch (t) {
|
|
512
|
-
throw
|
|
512
|
+
throw i.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
|
-
},
|
|
518
|
-
if (
|
|
519
|
-
return
|
|
517
|
+
}, mt = (r) => {
|
|
518
|
+
if (i.debug("Sanitize", "Starting metadata sanitization", { hasMetadata: r != null }), typeof r != "object" || r === null)
|
|
519
|
+
return i.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 =
|
|
525
|
-
return
|
|
524
|
+
const e = Object.keys(r).length, t = W(r), s = typeof t == "object" && t !== null ? t : {}, n = Object.keys(s).length;
|
|
525
|
+
return i.debug("Sanitize", "Metadata sanitization completed", {
|
|
526
526
|
originalKeys: e,
|
|
527
|
-
finalKeys:
|
|
528
|
-
keysFiltered: e -
|
|
527
|
+
finalKeys: n,
|
|
528
|
+
keysFiltered: e - n
|
|
529
529
|
}), s;
|
|
530
530
|
} catch (e) {
|
|
531
|
-
throw
|
|
531
|
+
throw i.error("Sanitize", "Metadata sanitization failed", {
|
|
532
532
|
error: e instanceof Error ? e.message : e
|
|
533
533
|
}), new Error(`Metadata sanitization failed: ${e instanceof Error ? e.message : "Unknown error"}`);
|
|
534
534
|
}
|
|
535
|
-
},
|
|
535
|
+
}, pt = (r) => {
|
|
536
536
|
if (typeof r != "object" || r === null)
|
|
537
537
|
return !1;
|
|
538
538
|
for (const e of Object.values(r)) {
|
|
@@ -549,27 +549,27 @@ const ot = (r) => {
|
|
|
549
549
|
}
|
|
550
550
|
}
|
|
551
551
|
return !0;
|
|
552
|
-
},
|
|
552
|
+
}, vt = (r) => typeof r != "string" ? {
|
|
553
553
|
valid: !1,
|
|
554
554
|
error: "Event name must be a string"
|
|
555
555
|
} : r.length === 0 ? {
|
|
556
556
|
valid: !1,
|
|
557
557
|
error: "Event name cannot be empty"
|
|
558
|
-
} : r.length >
|
|
558
|
+
} : r.length > ae ? {
|
|
559
559
|
valid: !1,
|
|
560
|
-
error: `Event name is too long (max ${
|
|
560
|
+
error: `Event name is too long (max ${ae} characters)`
|
|
561
561
|
} : r.includes("<") || r.includes(">") || r.includes("&") ? {
|
|
562
562
|
valid: !1,
|
|
563
563
|
error: "Event name contains invalid characters"
|
|
564
564
|
} : ["constructor", "prototype", "__proto__", "eval", "function", "var", "let", "const"].includes(r.toLowerCase()) ? {
|
|
565
565
|
valid: !1,
|
|
566
566
|
error: "Event name cannot be a reserved word"
|
|
567
|
-
} : { valid: !0 },
|
|
568
|
-
const s =
|
|
569
|
-
if (!
|
|
567
|
+
} : { valid: !0 }, St = (r, e, t) => {
|
|
568
|
+
const s = mt(e), n = `${t} "${r}" metadata error`;
|
|
569
|
+
if (!pt(s))
|
|
570
570
|
return {
|
|
571
571
|
valid: !1,
|
|
572
|
-
error: `${
|
|
572
|
+
error: `${n}: object has invalid types. Valid types are string, number, boolean or string arrays.`
|
|
573
573
|
};
|
|
574
574
|
let a;
|
|
575
575
|
try {
|
|
@@ -577,169 +577,169 @@ const ot = (r) => {
|
|
|
577
577
|
} catch {
|
|
578
578
|
return {
|
|
579
579
|
valid: !1,
|
|
580
|
-
error: `${
|
|
580
|
+
error: `${n}: object contains circular references or cannot be serialized.`
|
|
581
581
|
};
|
|
582
582
|
}
|
|
583
|
-
if (a.length >
|
|
583
|
+
if (a.length > oe)
|
|
584
584
|
return {
|
|
585
585
|
valid: !1,
|
|
586
|
-
error: `${
|
|
586
|
+
error: `${n}: object is too large (max ${oe / 1024} KB).`
|
|
587
587
|
};
|
|
588
|
-
if (Object.keys(s).length >
|
|
588
|
+
if (Object.keys(s).length > ce)
|
|
589
589
|
return {
|
|
590
590
|
valid: !1,
|
|
591
|
-
error: `${
|
|
591
|
+
error: `${n}: object has too many keys (max ${ce} keys).`
|
|
592
592
|
};
|
|
593
593
|
for (const [l, c] of Object.entries(s)) {
|
|
594
594
|
if (Array.isArray(c)) {
|
|
595
|
-
if (c.length >
|
|
595
|
+
if (c.length > le)
|
|
596
596
|
return {
|
|
597
597
|
valid: !1,
|
|
598
|
-
error: `${
|
|
598
|
+
error: `${n}: array property "${l}" is too large (max ${le} items).`
|
|
599
599
|
};
|
|
600
600
|
for (const d of c)
|
|
601
601
|
if (typeof d == "string" && d.length > 500)
|
|
602
602
|
return {
|
|
603
603
|
valid: !1,
|
|
604
|
-
error: `${
|
|
604
|
+
error: `${n}: array property "${l}" contains strings that are too long (max 500 characters).`
|
|
605
605
|
};
|
|
606
606
|
}
|
|
607
607
|
if (typeof c == "string" && c.length > M)
|
|
608
608
|
return {
|
|
609
609
|
valid: !1,
|
|
610
|
-
error: `${
|
|
610
|
+
error: `${n}: property "${l}" is too long (max ${M} characters).`
|
|
611
611
|
};
|
|
612
612
|
}
|
|
613
613
|
return {
|
|
614
614
|
valid: !0,
|
|
615
615
|
sanitizedMetadata: s
|
|
616
616
|
};
|
|
617
|
-
},
|
|
618
|
-
const t =
|
|
617
|
+
}, bt = (r, e) => {
|
|
618
|
+
const t = vt(r);
|
|
619
619
|
if (!t.valid)
|
|
620
|
-
return
|
|
620
|
+
return i.clientError("EventValidation", "Event name validation failed", { eventName: r, error: t.error }), t;
|
|
621
621
|
if (!e)
|
|
622
622
|
return { valid: !0 };
|
|
623
|
-
const s =
|
|
624
|
-
return s.valid ||
|
|
623
|
+
const s = St(r, e, "customEvent");
|
|
624
|
+
return s.valid || i.clientError("EventValidation", "Event metadata validation failed", {
|
|
625
625
|
eventName: r,
|
|
626
626
|
error: s.error
|
|
627
627
|
}), s;
|
|
628
|
-
},
|
|
628
|
+
}, se = (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:", n = t.protocol === "http:";
|
|
631
|
+
return s || e && n;
|
|
632
632
|
} catch {
|
|
633
633
|
return !1;
|
|
634
634
|
}
|
|
635
|
-
},
|
|
636
|
-
|
|
637
|
-
const t = new URL(window.location.href), s = t.hostname,
|
|
638
|
-
if (
|
|
639
|
-
throw
|
|
640
|
-
const a =
|
|
641
|
-
if (
|
|
635
|
+
}, yt = (r, e = !1) => {
|
|
636
|
+
i.debug("URLUtils", "Generating API URL", { projectId: r, allowHttp: e });
|
|
637
|
+
const t = new URL(window.location.href), s = t.hostname, n = s.split(".");
|
|
638
|
+
if (n.length === 0)
|
|
639
|
+
throw i.clientError("URLUtils", "Invalid hostname - no domain parts found", { hostname: s }), new Error("Invalid URL");
|
|
640
|
+
const a = n.slice(-2).join("."), o = e && t.protocol === "http:" ? "http" : "https", l = `${o}://${r}.${a}`;
|
|
641
|
+
if (i.debug("URLUtils", "Generated API URL", {
|
|
642
642
|
originalUrl: window.location.href,
|
|
643
643
|
hostname: s,
|
|
644
|
-
domainParts:
|
|
644
|
+
domainParts: n.length,
|
|
645
645
|
cleanDomain: a,
|
|
646
646
|
protocol: o,
|
|
647
647
|
generatedUrl: l
|
|
648
|
-
}), !
|
|
649
|
-
throw
|
|
648
|
+
}), !se(l, e))
|
|
649
|
+
throw i.clientError("URLUtils", "Generated API URL failed validation", {
|
|
650
650
|
apiUrl: l,
|
|
651
651
|
allowHttp: e
|
|
652
652
|
}), new Error("Invalid URL");
|
|
653
|
-
return
|
|
654
|
-
},
|
|
655
|
-
|
|
653
|
+
return i.debug("URLUtils", "API URL generation completed successfully", { apiUrl: l }), l;
|
|
654
|
+
}, ie = (r, e = []) => {
|
|
655
|
+
i.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, n = Array.from(s.keys()).length;
|
|
661
661
|
let a = !1;
|
|
662
662
|
const o = [];
|
|
663
663
|
if (e.forEach((c) => {
|
|
664
664
|
s.has(c) && (s.delete(c), a = !0, o.push(c));
|
|
665
|
-
}), a &&
|
|
665
|
+
}), a && i.debug("URLUtils", "Sensitive parameters removed from URL", {
|
|
666
666
|
removedParams: o,
|
|
667
|
-
originalParamCount:
|
|
667
|
+
originalParamCount: n,
|
|
668
668
|
finalParamCount: Array.from(s.keys()).length
|
|
669
669
|
}), !a && r.includes("?"))
|
|
670
|
-
return
|
|
670
|
+
return i.debug("URLUtils", "URL normalization - no changes needed"), r;
|
|
671
671
|
t.search = s.toString();
|
|
672
672
|
const l = t.toString();
|
|
673
|
-
return
|
|
673
|
+
return i.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 i.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
|
-
},
|
|
685
|
-
if (
|
|
684
|
+
}, Et = (r, e = []) => {
|
|
685
|
+
if (i.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 i.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, i.debug("URLUtils", "Extracted path from URL", { path: t });
|
|
693
693
|
} catch (c) {
|
|
694
|
-
return
|
|
694
|
+
return i.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", n = (c) => c.replaceAll(/[$()*+.?[\\\]^{|}]/g, "\\$&"), a = (c) => new RegExp(
|
|
700
|
+
"^" + c.split("*").map((d) => n(d)).join(".+") + "$"
|
|
701
701
|
), o = e.find((c) => {
|
|
702
702
|
try {
|
|
703
703
|
if (s(c)) {
|
|
704
|
-
const
|
|
705
|
-
return
|
|
704
|
+
const h = c.test(t);
|
|
705
|
+
return h && i.debug("URLUtils", "Path matched regex pattern", { path: t, pattern: c.toString() }), h;
|
|
706
706
|
}
|
|
707
707
|
if (c.includes("*")) {
|
|
708
|
-
const
|
|
709
|
-
return
|
|
708
|
+
const h = a(c), u = h.test(t);
|
|
709
|
+
return u && i.debug("URLUtils", "Path matched wildcard pattern", { path: t, pattern: c, regex: h.toString() }), u;
|
|
710
710
|
}
|
|
711
711
|
const d = c === t;
|
|
712
|
-
return d &&
|
|
712
|
+
return d && i.debug("URLUtils", "Path matched exact pattern", { path: t, pattern: c }), d;
|
|
713
713
|
} catch (d) {
|
|
714
|
-
return
|
|
714
|
+
return i.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 i.debug("URLUtils", "URL path exclusion check completed", {
|
|
722
722
|
path: t,
|
|
723
723
|
isExcluded: l,
|
|
724
724
|
matchedPattern: o ?? null,
|
|
725
725
|
totalPatternsChecked: e.length
|
|
726
726
|
}), l;
|
|
727
727
|
};
|
|
728
|
-
class
|
|
728
|
+
class wt {
|
|
729
729
|
getUrl(e, t = !1) {
|
|
730
|
-
const s =
|
|
731
|
-
if (!
|
|
730
|
+
const s = yt(e, t);
|
|
731
|
+
if (!se(s, t))
|
|
732
732
|
throw new Error("Invalid URL");
|
|
733
733
|
return s;
|
|
734
734
|
}
|
|
735
735
|
}
|
|
736
|
-
class
|
|
736
|
+
class It {
|
|
737
737
|
async get(e, t) {
|
|
738
|
-
if (t.id ===
|
|
739
|
-
return
|
|
740
|
-
|
|
741
|
-
const s = await this.load(e, t, t.id ===
|
|
742
|
-
return
|
|
738
|
+
if (t.id === _.HttpSkip)
|
|
739
|
+
return i.debug("ConfigManager", "Using special project id"), this.getDefaultConfig(t);
|
|
740
|
+
i.debug("ConfigManager", "Loading config from API", { apiUrl: e, projectId: t.id });
|
|
741
|
+
const s = await this.load(e, t, t.id === _.HttpLocal);
|
|
742
|
+
return i.info("ConfigManager", "Config loaded successfully", {
|
|
743
743
|
projectId: t.id,
|
|
744
744
|
mode: s.mode,
|
|
745
745
|
hasExcludedPaths: !!s.excludedUrlPaths?.length,
|
|
@@ -748,60 +748,60 @@ class Et {
|
|
|
748
748
|
}
|
|
749
749
|
async load(e, t, s) {
|
|
750
750
|
try {
|
|
751
|
-
const
|
|
752
|
-
if (!
|
|
751
|
+
const n = s ? `${window.location.origin}/config` : this.getUrl(e);
|
|
752
|
+
if (!n)
|
|
753
753
|
throw new Error("Config URL is not valid or not allowed");
|
|
754
|
-
const a = await fetch(
|
|
754
|
+
const a = await fetch(n, {
|
|
755
755
|
method: "GET",
|
|
756
756
|
headers: { "Content-Type": "application/json" }
|
|
757
757
|
});
|
|
758
758
|
if (!a.ok) {
|
|
759
759
|
const A = `HTTP ${a.status}: ${a.statusText}`;
|
|
760
|
-
throw
|
|
760
|
+
throw i.error("ConfigManager", "Config API request failed", {
|
|
761
761
|
status: a.status,
|
|
762
762
|
statusText: a.statusText,
|
|
763
|
-
configUrl:
|
|
763
|
+
configUrl: n
|
|
764
764
|
}), new Error(A);
|
|
765
765
|
}
|
|
766
766
|
const o = await a.json();
|
|
767
767
|
if (o == null || typeof o != "object" || Array.isArray(o))
|
|
768
|
-
throw
|
|
768
|
+
throw i.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
|
-
const l =
|
|
773
|
-
new URLSearchParams(window.location.search).get("qaMode") === "true" && !d.mode && (d.mode = L.QA,
|
|
774
|
-
const
|
|
775
|
-
return { ...d, errorSampling:
|
|
776
|
-
} catch (
|
|
777
|
-
const a =
|
|
778
|
-
throw
|
|
772
|
+
const l = ft(o), d = { ...{ ...Ce, ...l }, ...t };
|
|
773
|
+
new URLSearchParams(window.location.search).get("qaMode") === "true" && !d.mode && (d.mode = L.QA, i.info("ConfigManager", "QA mode enabled via URL parameter"));
|
|
774
|
+
const v = Object.values(L).includes(d.mode) ? 1 : d.errorSampling ?? 0.1;
|
|
775
|
+
return { ...d, errorSampling: v };
|
|
776
|
+
} catch (n) {
|
|
777
|
+
const a = n instanceof Error ? n.message : "Unknown error";
|
|
778
|
+
throw i.error("ConfigManager", "Failed to load config", { error: a, apiUrl: e }), new Error(`Failed to load config: ${a}`);
|
|
779
779
|
}
|
|
780
780
|
}
|
|
781
781
|
getUrl(e) {
|
|
782
782
|
const s = new URLSearchParams(window.location.search).get("qaMode") === "true";
|
|
783
|
-
let
|
|
784
|
-
if (s && (
|
|
785
|
-
throw
|
|
786
|
-
return
|
|
783
|
+
let n = `${e}/config`;
|
|
784
|
+
if (s && (n += "?qaMode=true"), !se(n))
|
|
785
|
+
throw i.clientError("ConfigManager", "Invalid config URL provided", { configUrl: n }), new Error("Config URL is not valid or not allowed");
|
|
786
|
+
return n;
|
|
787
787
|
}
|
|
788
788
|
getDefaultConfig(e) {
|
|
789
|
-
return
|
|
789
|
+
return Ze({
|
|
790
790
|
...e,
|
|
791
791
|
errorSampling: 1,
|
|
792
|
-
...Object.values(
|
|
792
|
+
...Object.values(_).includes(e.id) && { mode: L.DEBUG }
|
|
793
793
|
});
|
|
794
794
|
}
|
|
795
795
|
}
|
|
796
|
-
class
|
|
796
|
+
class Tt extends p {
|
|
797
797
|
storeManager;
|
|
798
798
|
queueStorageKey;
|
|
799
|
-
retryDelay =
|
|
799
|
+
retryDelay = ue;
|
|
800
800
|
retryTimeoutId = null;
|
|
801
801
|
lastAsyncSend = 0;
|
|
802
802
|
lastSyncSend = 0;
|
|
803
803
|
constructor(e) {
|
|
804
|
-
super(), this.storeManager = e, this.queueStorageKey = `${
|
|
804
|
+
super(), this.storeManager = e, this.queueStorageKey = `${st(this.get("config")?.id)}:${this.get("userId")}`, this.recoverPersistedEvents();
|
|
805
805
|
}
|
|
806
806
|
async sendEventsQueueAsync(e) {
|
|
807
807
|
return this.executeSend(e, () => this.sendQueueAsync(e));
|
|
@@ -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) ? (i.info("SenderManager", "Persisted events recovered successfully", {
|
|
824
824
|
eventsCount: e.events.length,
|
|
825
825
|
sessionId: e.sessionId
|
|
826
|
-
}), this.clearPersistedEvents()) : (
|
|
826
|
+
}), this.clearPersistedEvents()) : (i.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
|
+
i.error("SenderManager", "Failed to recover persisted events", { error: e });
|
|
831
831
|
}
|
|
832
832
|
}
|
|
833
833
|
stop() {
|
|
@@ -845,13 +845,13 @@ class wt extends p {
|
|
|
845
845
|
scheduleRetryForRecoveredEvents(e) {
|
|
846
846
|
this.retryTimeoutId === null && (this.retryTimeoutId = window.setTimeout(() => {
|
|
847
847
|
this.retryTimeoutId = null, this.sendRecoveredEvents(e);
|
|
848
|
-
}, this.retryDelay), this.retryDelay = Math.min(this.retryDelay * 2,
|
|
848
|
+
}, this.retryDelay), this.retryDelay = Math.min(this.retryDelay * 2, ge));
|
|
849
849
|
}
|
|
850
850
|
canSendAsync() {
|
|
851
|
-
return Date.now() - this.lastAsyncSend >=
|
|
851
|
+
return Date.now() - this.lastAsyncSend >= fe;
|
|
852
852
|
}
|
|
853
853
|
canSendSync() {
|
|
854
|
-
return Date.now() - this.lastSyncSend >=
|
|
854
|
+
return Date.now() - this.lastSyncSend >= fe;
|
|
855
855
|
}
|
|
856
856
|
async sendQueueAsync(e) {
|
|
857
857
|
const { url: t, payload: s } = this.prepareRequest(e);
|
|
@@ -867,9 +867,9 @@ class wt extends p {
|
|
|
867
867
|
Referer: window.location.href
|
|
868
868
|
}
|
|
869
869
|
})).ok;
|
|
870
|
-
} catch (
|
|
871
|
-
const a =
|
|
872
|
-
return
|
|
870
|
+
} catch (n) {
|
|
871
|
+
const a = n instanceof Error ? n.message : String(n), o = a.includes("CORS") || a.includes("NotSameOrigin") || a.includes("blocked");
|
|
872
|
+
return i.error("SenderManager", "Failed to send events async", {
|
|
873
873
|
error: a,
|
|
874
874
|
isCorsError: o,
|
|
875
875
|
url: t.replace(/\/\/[^/]+/, "//[DOMAIN]")
|
|
@@ -877,22 +877,22 @@ class wt extends p {
|
|
|
877
877
|
}
|
|
878
878
|
}
|
|
879
879
|
sendQueueSync(e) {
|
|
880
|
-
const { url: t, payload: s } = this.prepareRequest(e),
|
|
881
|
-
return this.isSendBeaconAvailable() && navigator.sendBeacon(t,
|
|
880
|
+
const { url: t, payload: s } = this.prepareRequest(e), n = new Blob([s], { type: "application/json" });
|
|
881
|
+
return this.isSendBeaconAvailable() && navigator.sendBeacon(t, n) ? !0 : this.sendSyncXHR(t, s);
|
|
882
882
|
}
|
|
883
883
|
sendQueue(e) {
|
|
884
884
|
if (!this.isSendBeaconAvailable())
|
|
885
885
|
return !1;
|
|
886
|
-
const { url: t, payload: s } = this.prepareRequest(e),
|
|
887
|
-
return navigator.sendBeacon(t,
|
|
886
|
+
const { url: t, payload: s } = this.prepareRequest(e), n = new Blob([s], { type: "application/json" });
|
|
887
|
+
return navigator.sendBeacon(t, n);
|
|
888
888
|
}
|
|
889
889
|
sendSyncXHR(e, t) {
|
|
890
890
|
const s = new XMLHttpRequest();
|
|
891
891
|
try {
|
|
892
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 = !0, s.timeout = xe, s.send(t), s.status >= 200 && s.status < 300;
|
|
893
|
-
} catch (
|
|
894
|
-
const a =
|
|
895
|
-
return
|
|
893
|
+
} catch (n) {
|
|
894
|
+
const a = n instanceof Error ? n.message : String(n), o = a.includes("CORS") || a.includes("NotSameOrigin") || a.includes("blocked");
|
|
895
|
+
return i.error("SenderManager", "Sync XHR failed", {
|
|
896
896
|
error: a,
|
|
897
897
|
isCorsError: o,
|
|
898
898
|
status: s.status ?? "unknown",
|
|
@@ -902,7 +902,7 @@ class wt extends p {
|
|
|
902
902
|
}
|
|
903
903
|
prepareRequest(e) {
|
|
904
904
|
return {
|
|
905
|
-
url: `${this.get("config").id ===
|
|
905
|
+
url: `${this.get("config").id === _.HttpLocal ? window.location.origin : this.get("apiUrl")}/collect`,
|
|
906
906
|
payload: JSON.stringify(e)
|
|
907
907
|
};
|
|
908
908
|
}
|
|
@@ -911,7 +911,7 @@ class wt extends p {
|
|
|
911
911
|
return e ? JSON.parse(e) : null;
|
|
912
912
|
}
|
|
913
913
|
isDataRecent(e) {
|
|
914
|
-
return (Date.now() - e.timestamp) / 36e5 <
|
|
914
|
+
return (Date.now() - e.timestamp) / 36e5 < We;
|
|
915
915
|
}
|
|
916
916
|
createRecoveryBody(e) {
|
|
917
917
|
return {
|
|
@@ -923,7 +923,7 @@ class wt extends p {
|
|
|
923
923
|
};
|
|
924
924
|
}
|
|
925
925
|
logQueue(e) {
|
|
926
|
-
|
|
926
|
+
i.info("SenderManager", " ⏩ Queue snapshot", e);
|
|
927
927
|
}
|
|
928
928
|
handleSendFailure(e) {
|
|
929
929
|
this.persistFailedEvents(e), this.scheduleRetry(e);
|
|
@@ -940,39 +940,39 @@ class wt extends p {
|
|
|
940
940
|
};
|
|
941
941
|
this.storeManager.setItem(this.queueStorageKey, JSON.stringify(t));
|
|
942
942
|
} catch (t) {
|
|
943
|
-
|
|
943
|
+
i.error("SenderManager", "Failed to persist events", { error: t });
|
|
944
944
|
}
|
|
945
945
|
}
|
|
946
946
|
clearPersistedEvents() {
|
|
947
947
|
this.storeManager.removeItem(this.queueStorageKey);
|
|
948
948
|
}
|
|
949
949
|
resetRetryState() {
|
|
950
|
-
this.retryDelay =
|
|
950
|
+
this.retryDelay = ue, this.clearRetryTimeout();
|
|
951
951
|
}
|
|
952
952
|
scheduleRetry(e) {
|
|
953
953
|
this.retryTimeoutId === null && (this.retryTimeoutId = window.setTimeout(() => {
|
|
954
954
|
this.retryTimeoutId = null, this.sendEventsQueue(e);
|
|
955
|
-
}, this.retryDelay), this.retryDelay = Math.min(this.retryDelay * 2,
|
|
955
|
+
}, this.retryDelay), this.retryDelay = Math.min(this.retryDelay * 2, ge));
|
|
956
956
|
}
|
|
957
957
|
async executeSend(e, t) {
|
|
958
958
|
if (this.shouldSkipSend())
|
|
959
959
|
return this.logQueue(e), !0;
|
|
960
960
|
if (!this.canSendAsync())
|
|
961
|
-
return
|
|
961
|
+
return i.info("SenderManager", "⏱️ Rate limited - skipping async send", {
|
|
962
962
|
eventsCount: e.events.length,
|
|
963
963
|
timeSinceLastSend: Date.now() - this.lastAsyncSend
|
|
964
964
|
}), !1;
|
|
965
|
-
|
|
965
|
+
i.info("SenderManager", "🌐 Sending events to server (async)", {
|
|
966
966
|
eventsCount: e.events.length,
|
|
967
967
|
sessionId: e.session_id,
|
|
968
968
|
userId: e.user_id
|
|
969
969
|
}), this.lastAsyncSend = Date.now();
|
|
970
970
|
try {
|
|
971
971
|
const s = await t();
|
|
972
|
-
return s ? (
|
|
972
|
+
return s ? (i.info("SenderManager", "✅ Successfully sent events to server", {
|
|
973
973
|
eventsCount: e.events.length,
|
|
974
974
|
method: "async"
|
|
975
|
-
}), this.resetRetryState(), this.clearPersistedEvents()) : (
|
|
975
|
+
}), this.resetRetryState(), this.clearPersistedEvents()) : (i.warn("SenderManager", "Failed to send events", {
|
|
976
976
|
eventsCount: e.events.length,
|
|
977
977
|
method: "async"
|
|
978
978
|
}), this.handleSendFailure(e)), s;
|
|
@@ -984,11 +984,11 @@ class wt extends p {
|
|
|
984
984
|
if (this.shouldSkipSend())
|
|
985
985
|
return this.logQueue(e), !0;
|
|
986
986
|
if (!this.canSendSync())
|
|
987
|
-
return
|
|
987
|
+
return i.info("SenderManager", "⏱️ Rate limited - skipping sync send", {
|
|
988
988
|
eventsCount: e.events.length,
|
|
989
989
|
timeSinceLastSend: Date.now() - this.lastSyncSend
|
|
990
990
|
}), !1;
|
|
991
|
-
|
|
991
|
+
i.info("SenderManager", "🌐 Sending events to server (sync)", {
|
|
992
992
|
eventsCount: e.events.length,
|
|
993
993
|
sessionId: e.session_id,
|
|
994
994
|
userId: e.user_id,
|
|
@@ -996,15 +996,15 @@ class wt extends p {
|
|
|
996
996
|
}), this.lastSyncSend = Date.now();
|
|
997
997
|
try {
|
|
998
998
|
const s = t();
|
|
999
|
-
return s ? (
|
|
999
|
+
return s ? (i.info("SenderManager", "✅ Successfully sent events to server", {
|
|
1000
1000
|
eventsCount: e.events.length,
|
|
1001
1001
|
method: "sync"
|
|
1002
|
-
}), this.resetRetryState(), this.clearPersistedEvents()) : (
|
|
1002
|
+
}), this.resetRetryState(), this.clearPersistedEvents()) : (i.warn("SenderManager", "Failed to send events", {
|
|
1003
1003
|
eventsCount: e.events.length,
|
|
1004
1004
|
method: "sync"
|
|
1005
1005
|
}), this.handleSendFailure(e)), s;
|
|
1006
1006
|
} catch {
|
|
1007
|
-
return
|
|
1007
|
+
return i.info("SenderManager", "💥 Exception during event sending", {
|
|
1008
1008
|
eventsCount: e.events.length,
|
|
1009
1009
|
method: "sync"
|
|
1010
1010
|
}), this.handleSendFailure(e), !1;
|
|
@@ -1012,7 +1012,7 @@ class wt extends p {
|
|
|
1012
1012
|
}
|
|
1013
1013
|
shouldSkipSend() {
|
|
1014
1014
|
const { id: e, mode: t } = this.get("config"), s = [L.QA, L.DEBUG];
|
|
1015
|
-
return e ===
|
|
1015
|
+
return e === _.HttpSkip ? !0 : !!t && s.includes(t) && e !== _.HttpLocal;
|
|
1016
1016
|
}
|
|
1017
1017
|
isSendBeaconAvailable() {
|
|
1018
1018
|
return typeof navigator.sendBeacon == "function";
|
|
@@ -1021,137 +1021,137 @@ class wt extends p {
|
|
|
1021
1021
|
this.retryTimeoutId !== null && (clearTimeout(this.retryTimeoutId), this.retryTimeoutId = null);
|
|
1022
1022
|
}
|
|
1023
1023
|
}
|
|
1024
|
-
class
|
|
1024
|
+
class Mt extends p {
|
|
1025
1025
|
shouldSampleEvent(e, t) {
|
|
1026
|
-
return this.get("config")?.mode === "qa" || this.get("config")?.mode === "debug" ? !0 : e ===
|
|
1026
|
+
return this.get("config")?.mode === "qa" || this.get("config")?.mode === "debug" ? !0 : e === g.WEB_VITALS ? this.isWebVitalEventSampledIn(t?.type) : this.isSampledIn();
|
|
1027
1027
|
}
|
|
1028
1028
|
isSampledIn() {
|
|
1029
|
-
const e = this.get("config").samplingRate ??
|
|
1029
|
+
const e = this.get("config").samplingRate ?? Te;
|
|
1030
1030
|
return e >= 1 ? !0 : e <= 0 ? !1 : this.getHash(this.get("userId")) % 100 / 100 < e;
|
|
1031
1031
|
}
|
|
1032
1032
|
isWebVitalEventSampledIn(e) {
|
|
1033
|
-
const t = e === "LONG_TASK", s = t ? De :
|
|
1033
|
+
const t = e === "LONG_TASK", s = t ? De : Oe;
|
|
1034
1034
|
if (s >= 1) return !0;
|
|
1035
1035
|
if (s <= 0) return !1;
|
|
1036
|
-
const
|
|
1037
|
-
return this.getHash(
|
|
1036
|
+
const n = `${this.get("userId")}|${t ? "long_task" : "web_vitals"}`;
|
|
1037
|
+
return this.getHash(n) % 100 / 100 < s;
|
|
1038
1038
|
}
|
|
1039
1039
|
getHash(e) {
|
|
1040
1040
|
let t = 0;
|
|
1041
1041
|
for (let s = 0; s < e.length; s++) {
|
|
1042
|
-
const
|
|
1043
|
-
t = (t << 5) - t +
|
|
1042
|
+
const n = e.charCodeAt(s);
|
|
1043
|
+
t = (t << 5) - t + n, t |= 0;
|
|
1044
1044
|
}
|
|
1045
1045
|
return Math.abs(t);
|
|
1046
1046
|
}
|
|
1047
1047
|
}
|
|
1048
|
-
class
|
|
1048
|
+
class At extends p {
|
|
1049
1049
|
getEventTagsIds(e, t) {
|
|
1050
1050
|
switch (e.type) {
|
|
1051
|
-
case
|
|
1051
|
+
case g.PAGE_VIEW:
|
|
1052
1052
|
return this.checkEventTypePageView(e, t);
|
|
1053
|
-
case
|
|
1053
|
+
case g.CLICK:
|
|
1054
1054
|
return this.checkEventTypeClick(e, t);
|
|
1055
1055
|
default:
|
|
1056
1056
|
return [];
|
|
1057
1057
|
}
|
|
1058
1058
|
}
|
|
1059
1059
|
checkEventTypePageView(e, t) {
|
|
1060
|
-
const s = this.get("config")?.tags?.filter((a) => a.triggerType ===
|
|
1060
|
+
const s = this.get("config")?.tags?.filter((a) => a.triggerType === g.PAGE_VIEW) ?? [];
|
|
1061
1061
|
if (s.length === 0)
|
|
1062
1062
|
return [];
|
|
1063
|
-
const
|
|
1063
|
+
const n = [];
|
|
1064
1064
|
for (const a of s) {
|
|
1065
1065
|
const { id: o, logicalOperator: l, conditions: c } = a, d = [];
|
|
1066
|
-
for (const
|
|
1067
|
-
switch (
|
|
1066
|
+
for (const u of c)
|
|
1067
|
+
switch (u.type) {
|
|
1068
1068
|
case m.URL_MATCHES: {
|
|
1069
|
-
d.push(this.matchUrlMatches(
|
|
1069
|
+
d.push(this.matchUrlMatches(u, e.page_url));
|
|
1070
1070
|
break;
|
|
1071
1071
|
}
|
|
1072
1072
|
case m.DEVICE_TYPE: {
|
|
1073
|
-
d.push(this.matchDeviceType(
|
|
1073
|
+
d.push(this.matchDeviceType(u, t));
|
|
1074
1074
|
break;
|
|
1075
1075
|
}
|
|
1076
1076
|
case m.UTM_SOURCE: {
|
|
1077
|
-
d.push(this.matchUtmCondition(
|
|
1077
|
+
d.push(this.matchUtmCondition(u, e.utm?.source));
|
|
1078
1078
|
break;
|
|
1079
1079
|
}
|
|
1080
1080
|
case m.UTM_MEDIUM: {
|
|
1081
|
-
d.push(this.matchUtmCondition(
|
|
1081
|
+
d.push(this.matchUtmCondition(u, e.utm?.medium));
|
|
1082
1082
|
break;
|
|
1083
1083
|
}
|
|
1084
1084
|
case m.UTM_CAMPAIGN: {
|
|
1085
|
-
d.push(this.matchUtmCondition(
|
|
1085
|
+
d.push(this.matchUtmCondition(u, e.utm?.campaign));
|
|
1086
1086
|
break;
|
|
1087
1087
|
}
|
|
1088
1088
|
}
|
|
1089
|
-
let
|
|
1090
|
-
|
|
1089
|
+
let h = !1;
|
|
1090
|
+
h = l === G.AND ? d.every(Boolean) : d.some(Boolean), h && n.push(o);
|
|
1091
1091
|
}
|
|
1092
|
-
return
|
|
1092
|
+
return n;
|
|
1093
1093
|
}
|
|
1094
1094
|
checkEventTypeClick(e, t) {
|
|
1095
|
-
const s = this.get("config")?.tags?.filter((a) => a.triggerType ===
|
|
1095
|
+
const s = this.get("config")?.tags?.filter((a) => a.triggerType === g.CLICK) ?? [];
|
|
1096
1096
|
if (s.length === 0)
|
|
1097
1097
|
return [];
|
|
1098
|
-
const
|
|
1098
|
+
const n = [];
|
|
1099
1099
|
for (const a of s) {
|
|
1100
1100
|
const { id: o, logicalOperator: l, conditions: c } = a, d = [];
|
|
1101
|
-
for (const
|
|
1101
|
+
for (const u of c) {
|
|
1102
1102
|
if (!e.click_data) {
|
|
1103
1103
|
d.push(!1);
|
|
1104
1104
|
continue;
|
|
1105
1105
|
}
|
|
1106
|
-
const
|
|
1107
|
-
switch (
|
|
1106
|
+
const v = e.click_data;
|
|
1107
|
+
switch (u.type) {
|
|
1108
1108
|
case m.ELEMENT_MATCHES: {
|
|
1109
|
-
d.push(this.matchElementSelector(
|
|
1109
|
+
d.push(this.matchElementSelector(u, v));
|
|
1110
1110
|
break;
|
|
1111
1111
|
}
|
|
1112
1112
|
case m.DEVICE_TYPE: {
|
|
1113
|
-
d.push(this.matchDeviceType(
|
|
1113
|
+
d.push(this.matchDeviceType(u, t));
|
|
1114
1114
|
break;
|
|
1115
1115
|
}
|
|
1116
1116
|
case m.URL_MATCHES: {
|
|
1117
|
-
d.push(this.matchUrlMatches(
|
|
1117
|
+
d.push(this.matchUrlMatches(u, e.page_url));
|
|
1118
1118
|
break;
|
|
1119
1119
|
}
|
|
1120
1120
|
case m.UTM_SOURCE: {
|
|
1121
|
-
d.push(this.matchUtmCondition(
|
|
1121
|
+
d.push(this.matchUtmCondition(u, e.utm?.source));
|
|
1122
1122
|
break;
|
|
1123
1123
|
}
|
|
1124
1124
|
case m.UTM_MEDIUM: {
|
|
1125
|
-
d.push(this.matchUtmCondition(
|
|
1125
|
+
d.push(this.matchUtmCondition(u, e.utm?.medium));
|
|
1126
1126
|
break;
|
|
1127
1127
|
}
|
|
1128
1128
|
case m.UTM_CAMPAIGN: {
|
|
1129
|
-
d.push(this.matchUtmCondition(
|
|
1129
|
+
d.push(this.matchUtmCondition(u, e.utm?.campaign));
|
|
1130
1130
|
break;
|
|
1131
1131
|
}
|
|
1132
1132
|
}
|
|
1133
1133
|
}
|
|
1134
|
-
let
|
|
1135
|
-
|
|
1134
|
+
let h = !1;
|
|
1135
|
+
h = l === G.AND ? d.every(Boolean) : d.some(Boolean), h && n.push(o);
|
|
1136
1136
|
}
|
|
1137
|
-
return
|
|
1137
|
+
return n;
|
|
1138
1138
|
}
|
|
1139
1139
|
matchUrlMatches(e, t) {
|
|
1140
1140
|
if (e.type !== m.URL_MATCHES)
|
|
1141
1141
|
return !1;
|
|
1142
|
-
const s = e.value.toLowerCase(),
|
|
1142
|
+
const s = e.value.toLowerCase(), n = t.toLowerCase();
|
|
1143
1143
|
switch (e.operator) {
|
|
1144
1144
|
case f.EQUALS:
|
|
1145
|
-
return
|
|
1145
|
+
return n === s;
|
|
1146
1146
|
case f.CONTAINS:
|
|
1147
|
-
return
|
|
1147
|
+
return n.includes(s);
|
|
1148
1148
|
case f.STARTS_WITH:
|
|
1149
|
-
return
|
|
1149
|
+
return n.startsWith(s);
|
|
1150
1150
|
case f.ENDS_WITH:
|
|
1151
|
-
return
|
|
1151
|
+
return n.endsWith(s);
|
|
1152
1152
|
case f.REGEX:
|
|
1153
1153
|
try {
|
|
1154
|
-
return new RegExp(s, "gi").test(
|
|
1154
|
+
return new RegExp(s, "gi").test(n);
|
|
1155
1155
|
} catch {
|
|
1156
1156
|
return !1;
|
|
1157
1157
|
}
|
|
@@ -1162,19 +1162,19 @@ class Tt extends p {
|
|
|
1162
1162
|
matchDeviceType(e, t) {
|
|
1163
1163
|
if (e.type !== m.DEVICE_TYPE)
|
|
1164
1164
|
return !1;
|
|
1165
|
-
const s = e.value.toLowerCase(),
|
|
1165
|
+
const s = e.value.toLowerCase(), n = t.toLowerCase();
|
|
1166
1166
|
switch (e.operator) {
|
|
1167
1167
|
case f.EQUALS:
|
|
1168
|
-
return
|
|
1168
|
+
return n === s;
|
|
1169
1169
|
case f.CONTAINS:
|
|
1170
|
-
return
|
|
1170
|
+
return n.includes(s);
|
|
1171
1171
|
case f.STARTS_WITH:
|
|
1172
|
-
return
|
|
1172
|
+
return n.startsWith(s);
|
|
1173
1173
|
case f.ENDS_WITH:
|
|
1174
|
-
return
|
|
1174
|
+
return n.endsWith(s);
|
|
1175
1175
|
case f.REGEX:
|
|
1176
1176
|
try {
|
|
1177
|
-
return new RegExp(s, "gi").test(
|
|
1177
|
+
return new RegExp(s, "gi").test(n);
|
|
1178
1178
|
} catch {
|
|
1179
1179
|
return !1;
|
|
1180
1180
|
}
|
|
@@ -1196,19 +1196,19 @@ class Tt extends p {
|
|
|
1196
1196
|
t.role ?? "",
|
|
1197
1197
|
t.ariaLabel ?? "",
|
|
1198
1198
|
...Object.values(t.dataAttributes ?? {})
|
|
1199
|
-
].join(" "),
|
|
1199
|
+
].join(" "), n = e.value.toLowerCase(), a = s.toLowerCase();
|
|
1200
1200
|
switch (e.operator) {
|
|
1201
1201
|
case f.EQUALS:
|
|
1202
|
-
return this.checkElementFieldEquals(t,
|
|
1202
|
+
return this.checkElementFieldEquals(t, n);
|
|
1203
1203
|
case f.CONTAINS:
|
|
1204
|
-
return a.includes(
|
|
1204
|
+
return a.includes(n);
|
|
1205
1205
|
case f.STARTS_WITH:
|
|
1206
|
-
return a.startsWith(
|
|
1206
|
+
return a.startsWith(n);
|
|
1207
1207
|
case f.ENDS_WITH:
|
|
1208
|
-
return a.endsWith(
|
|
1208
|
+
return a.endsWith(n);
|
|
1209
1209
|
case f.REGEX:
|
|
1210
1210
|
try {
|
|
1211
|
-
return new RegExp(
|
|
1211
|
+
return new RegExp(n, "gi").test(a);
|
|
1212
1212
|
} catch {
|
|
1213
1213
|
return !1;
|
|
1214
1214
|
}
|
|
@@ -1221,19 +1221,19 @@ class Tt extends p {
|
|
|
1221
1221
|
e.type
|
|
1222
1222
|
))
|
|
1223
1223
|
return !1;
|
|
1224
|
-
const s = t ?? "",
|
|
1224
|
+
const s = t ?? "", n = e.value.toLowerCase(), a = s.toLowerCase();
|
|
1225
1225
|
switch (e.operator) {
|
|
1226
1226
|
case f.EQUALS:
|
|
1227
|
-
return a ===
|
|
1227
|
+
return a === n;
|
|
1228
1228
|
case f.CONTAINS:
|
|
1229
|
-
return a.includes(
|
|
1229
|
+
return a.includes(n);
|
|
1230
1230
|
case f.STARTS_WITH:
|
|
1231
|
-
return a.startsWith(
|
|
1231
|
+
return a.startsWith(n);
|
|
1232
1232
|
case f.ENDS_WITH:
|
|
1233
|
-
return a.endsWith(
|
|
1233
|
+
return a.endsWith(n);
|
|
1234
1234
|
case f.REGEX:
|
|
1235
1235
|
try {
|
|
1236
|
-
return new RegExp(
|
|
1236
|
+
return new RegExp(n, "gi").test(a);
|
|
1237
1237
|
} catch {
|
|
1238
1238
|
return !1;
|
|
1239
1239
|
}
|
|
@@ -1253,22 +1253,22 @@ class Tt extends p {
|
|
|
1253
1253
|
e.role,
|
|
1254
1254
|
e.ariaLabel
|
|
1255
1255
|
];
|
|
1256
|
-
for (const
|
|
1257
|
-
if (
|
|
1258
|
-
const a =
|
|
1256
|
+
for (const n of s)
|
|
1257
|
+
if (n) {
|
|
1258
|
+
const a = n.toLowerCase(), o = t.toLowerCase();
|
|
1259
1259
|
if (a === o)
|
|
1260
1260
|
return !0;
|
|
1261
1261
|
}
|
|
1262
1262
|
if (e.dataAttributes)
|
|
1263
|
-
for (const
|
|
1264
|
-
const a =
|
|
1263
|
+
for (const n of Object.values(e.dataAttributes)) {
|
|
1264
|
+
const a = n.toLowerCase(), o = t.toLowerCase();
|
|
1265
1265
|
if (a === o)
|
|
1266
1266
|
return !0;
|
|
1267
1267
|
}
|
|
1268
1268
|
return !1;
|
|
1269
1269
|
}
|
|
1270
1270
|
}
|
|
1271
|
-
class
|
|
1271
|
+
class Ct extends p {
|
|
1272
1272
|
googleAnalytics;
|
|
1273
1273
|
samplingManager;
|
|
1274
1274
|
tagsManager;
|
|
@@ -1280,17 +1280,17 @@ class Mt extends p {
|
|
|
1280
1280
|
intervalActive = !1;
|
|
1281
1281
|
// Circuit breaker properties
|
|
1282
1282
|
failureCount = 0;
|
|
1283
|
-
MAX_FAILURES =
|
|
1283
|
+
MAX_FAILURES = E.MAX_FAILURES;
|
|
1284
1284
|
circuitOpen = !1;
|
|
1285
1285
|
circuitOpenTime = 0;
|
|
1286
|
-
backoffDelay =
|
|
1286
|
+
backoffDelay = E.INITIAL_BACKOFF_DELAY_MS;
|
|
1287
1287
|
circuitResetTimeoutId = null;
|
|
1288
1288
|
// Event deduplication properties
|
|
1289
1289
|
eventFingerprints = /* @__PURE__ */ new Map();
|
|
1290
1290
|
// Persistence storage key
|
|
1291
1291
|
PERSISTENCE_KEY = "tl:circuit_breaker_events";
|
|
1292
1292
|
constructor(e, t = null) {
|
|
1293
|
-
super(), this.storageManager = e, this.googleAnalytics = t, this.samplingManager = new
|
|
1293
|
+
super(), this.storageManager = e, this.googleAnalytics = t, this.samplingManager = new Mt(), this.tagsManager = new At(), this.dataSender = new Tt(e), this.restoreEventsFromStorage(), i.debug("EventManager", "EventManager initialized", {
|
|
1294
1294
|
hasGoogleAnalytics: !!t,
|
|
1295
1295
|
restoredEventsCount: this.eventsQueue.length
|
|
1296
1296
|
});
|
|
@@ -1299,28 +1299,28 @@ class Mt extends p {
|
|
|
1299
1299
|
type: e,
|
|
1300
1300
|
page_url: t,
|
|
1301
1301
|
from_page_url: s,
|
|
1302
|
-
scroll_data:
|
|
1302
|
+
scroll_data: n,
|
|
1303
1303
|
click_data: a,
|
|
1304
1304
|
custom_event: o,
|
|
1305
1305
|
web_vitals: l,
|
|
1306
1306
|
session_end_reason: c,
|
|
1307
1307
|
session_start_recovered: d
|
|
1308
1308
|
}) {
|
|
1309
|
-
if (
|
|
1309
|
+
if (i.info("EventManager", `📥 Event captured: ${e}`, {
|
|
1310
1310
|
type: e,
|
|
1311
1311
|
page_url: t,
|
|
1312
1312
|
hasCustomEvent: !!o,
|
|
1313
1313
|
hasClickData: !!a,
|
|
1314
|
-
hasScrollData: !!
|
|
1314
|
+
hasScrollData: !!n,
|
|
1315
1315
|
hasWebVitals: !!l
|
|
1316
1316
|
}), !this.samplingManager.shouldSampleEvent(e, l)) {
|
|
1317
|
-
|
|
1317
|
+
i.debug("EventManager", "Event filtered by sampling", { type: e, samplingActive: !0 });
|
|
1318
1318
|
return;
|
|
1319
1319
|
}
|
|
1320
1320
|
if (this.isDuplicatedEvent({
|
|
1321
1321
|
type: e,
|
|
1322
1322
|
page_url: t,
|
|
1323
|
-
scroll_data:
|
|
1323
|
+
scroll_data: n,
|
|
1324
1324
|
click_data: a,
|
|
1325
1325
|
custom_event: o,
|
|
1326
1326
|
web_vitals: l,
|
|
@@ -1329,80 +1329,80 @@ class Mt extends p {
|
|
|
1329
1329
|
})) {
|
|
1330
1330
|
const k = Date.now();
|
|
1331
1331
|
if (this.eventsQueue && this.eventsQueue.length > 0) {
|
|
1332
|
-
const
|
|
1333
|
-
|
|
1332
|
+
const P = this.eventsQueue.at(-1);
|
|
1333
|
+
P && (P.timestamp = k);
|
|
1334
1334
|
}
|
|
1335
|
-
this.lastEvent && (this.lastEvent.timestamp = k),
|
|
1335
|
+
this.lastEvent && (this.lastEvent.timestamp = k), i.debug("EventManager", "Duplicate event detected, timestamp updated", {
|
|
1336
1336
|
type: e,
|
|
1337
1337
|
queueLength: this.eventsQueue.length
|
|
1338
1338
|
});
|
|
1339
1339
|
return;
|
|
1340
1340
|
}
|
|
1341
|
-
const
|
|
1342
|
-
if (
|
|
1343
|
-
(this.get("config")?.mode === "qa" || this.get("config")?.mode === "debug") &&
|
|
1341
|
+
const u = t || this.get("pageUrl"), v = Et(u, this.get("config").excludedUrlPaths), y = this.get("hasStartSession"), A = e == g.SESSION_END;
|
|
1342
|
+
if (v && (!A || A && !y)) {
|
|
1343
|
+
(this.get("config")?.mode === "qa" || this.get("config")?.mode === "debug") && i.debug("EventManager", `Event ${e} on excluded route: ${t}`);
|
|
1344
1344
|
return;
|
|
1345
1345
|
}
|
|
1346
|
-
const
|
|
1347
|
-
|
|
1348
|
-
const
|
|
1346
|
+
const H = e === g.SESSION_START;
|
|
1347
|
+
H && this.set("hasStartSession", !0);
|
|
1348
|
+
const ne = H ? at() : void 0, x = {
|
|
1349
1349
|
type: e,
|
|
1350
|
-
page_url:
|
|
1350
|
+
page_url: v ? "excluded" : u,
|
|
1351
1351
|
timestamp: Date.now(),
|
|
1352
|
-
...
|
|
1353
|
-
...s && !
|
|
1354
|
-
...
|
|
1352
|
+
...H && { referrer: document.referrer || "Direct" },
|
|
1353
|
+
...s && !v ? { from_page_url: s } : {},
|
|
1354
|
+
...n && { scroll_data: n },
|
|
1355
1355
|
...a && { click_data: a },
|
|
1356
1356
|
...o && { custom_event: o },
|
|
1357
|
-
...
|
|
1357
|
+
...ne && { utm: ne },
|
|
1358
1358
|
...l && { web_vitals: l },
|
|
1359
1359
|
...c && { session_end_reason: c },
|
|
1360
1360
|
...d && { session_start_recovered: d }
|
|
1361
1361
|
};
|
|
1362
1362
|
if (this.get("config")?.tags?.length) {
|
|
1363
|
-
const k = this.tagsManager.getEventTagsIds(
|
|
1364
|
-
k?.length && (
|
|
1365
|
-
id:
|
|
1366
|
-
key: this.get("config")?.tags?.find((
|
|
1363
|
+
const k = this.tagsManager.getEventTagsIds(x, this.get("device"));
|
|
1364
|
+
k?.length && (x.tags = this.get("config")?.mode === "qa" || this.get("config")?.mode === "debug" ? k.map((P) => ({
|
|
1365
|
+
id: P,
|
|
1366
|
+
key: this.get("config")?.tags?.find((Re) => Re.id === P)?.key ?? ""
|
|
1367
1367
|
})) : k);
|
|
1368
1368
|
}
|
|
1369
|
-
this.lastEvent =
|
|
1369
|
+
this.lastEvent = x, this.processAndSend(x);
|
|
1370
1370
|
}
|
|
1371
1371
|
stop() {
|
|
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 =
|
|
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 = E.INITIAL_BACKOFF_DELAY_MS, this.lastEvent = null, this.dataSender.stop();
|
|
1373
1373
|
}
|
|
1374
1374
|
processAndSend(e) {
|
|
1375
|
-
if (
|
|
1375
|
+
if (i.info("EventManager", `🔄 Event processed and queued: ${e.type}`, {
|
|
1376
1376
|
type: e.type,
|
|
1377
1377
|
timestamp: e.timestamp,
|
|
1378
1378
|
page_url: e.page_url,
|
|
1379
1379
|
queueLengthBefore: this.eventsQueue.length
|
|
1380
1380
|
}), this.get("config").ipExcluded) {
|
|
1381
|
-
|
|
1381
|
+
i.info("EventManager", "❌ Event blocked: IP excluded");
|
|
1382
1382
|
return;
|
|
1383
1383
|
}
|
|
1384
|
-
if (this.eventsQueue.push(e), this.eventsQueue.length >
|
|
1384
|
+
if (this.eventsQueue.push(e), this.eventsQueue.length > re) {
|
|
1385
1385
|
const t = this.eventsQueue.shift();
|
|
1386
|
-
|
|
1387
|
-
maxLength:
|
|
1386
|
+
i.warn("EventManager", "Event queue overflow, oldest event removed", {
|
|
1387
|
+
maxLength: re,
|
|
1388
1388
|
currentLength: this.eventsQueue.length,
|
|
1389
1389
|
removedEventType: t?.type
|
|
1390
1390
|
});
|
|
1391
1391
|
}
|
|
1392
|
-
if (this.eventsQueueIntervalId || (this.initEventsQueueInterval(),
|
|
1392
|
+
if (this.eventsQueueIntervalId || (this.initEventsQueueInterval(), i.info("EventManager", "⏰ Event sender initialized - queue will be sent periodically", {
|
|
1393
1393
|
queueLength: this.eventsQueue.length
|
|
1394
|
-
})), this.googleAnalytics && e.type ===
|
|
1394
|
+
})), this.googleAnalytics && e.type === g.CUSTOM) {
|
|
1395
1395
|
const t = e.custom_event;
|
|
1396
1396
|
this.trackGoogleAnalyticsEvent(t);
|
|
1397
1397
|
}
|
|
1398
1398
|
}
|
|
1399
1399
|
trackGoogleAnalyticsEvent(e) {
|
|
1400
|
-
this.get("config").mode === "qa" || this.get("config").mode === "debug" ?
|
|
1400
|
+
this.get("config").mode === "qa" || this.get("config").mode === "debug" ? i.debug("EventManager", `Google Analytics event: ${JSON.stringify(e)}`) : this.googleAnalytics && this.googleAnalytics.trackEvent(e.name, e.metadata ?? {});
|
|
1401
1401
|
}
|
|
1402
1402
|
initEventsQueueInterval() {
|
|
1403
1403
|
if (this.eventsQueueIntervalId || this.intervalActive)
|
|
1404
1404
|
return;
|
|
1405
|
-
const e = this.get("config")?.id === "test" ?
|
|
1405
|
+
const e = this.get("config")?.id === "test" ? Qe : Ge;
|
|
1406
1406
|
this.eventsQueueIntervalId = window.setInterval(() => {
|
|
1407
1407
|
this.eventsQueue.length > 0 && this.sendEventsQueue();
|
|
1408
1408
|
}, e), this.intervalActive = !0;
|
|
@@ -1425,37 +1425,37 @@ class Mt extends p {
|
|
|
1425
1425
|
sendEventsQueue() {
|
|
1426
1426
|
if (this.eventsQueue.length === 0)
|
|
1427
1427
|
return;
|
|
1428
|
-
if (
|
|
1428
|
+
if (i.info("EventManager", "📤 Preparing to send event queue", {
|
|
1429
1429
|
queueLength: this.eventsQueue.length,
|
|
1430
1430
|
hasSessionId: !!this.get("sessionId"),
|
|
1431
1431
|
circuitOpen: this.circuitOpen
|
|
1432
1432
|
}), this.circuitOpen) {
|
|
1433
1433
|
const s = Date.now() - this.circuitOpenTime;
|
|
1434
|
-
if (s >=
|
|
1435
|
-
this.resetCircuitBreaker(),
|
|
1434
|
+
if (s >= E.RECOVERY_TIME_MS)
|
|
1435
|
+
this.resetCircuitBreaker(), i.info("EventManager", "Circuit breaker reset after timeout", {
|
|
1436
1436
|
timeSinceOpen: s,
|
|
1437
|
-
recoveryTime:
|
|
1437
|
+
recoveryTime: E.RECOVERY_TIME_MS
|
|
1438
1438
|
});
|
|
1439
1439
|
else {
|
|
1440
|
-
|
|
1440
|
+
i.debug("EventManager", "Circuit breaker is open - skipping event sending", {
|
|
1441
1441
|
queueLength: this.eventsQueue.length,
|
|
1442
1442
|
failureCount: this.failureCount,
|
|
1443
1443
|
timeSinceOpen: s,
|
|
1444
|
-
recoveryTime:
|
|
1444
|
+
recoveryTime: E.RECOVERY_TIME_MS
|
|
1445
1445
|
});
|
|
1446
1446
|
return;
|
|
1447
1447
|
}
|
|
1448
1448
|
}
|
|
1449
1449
|
if (!this.get("sessionId")) {
|
|
1450
|
-
|
|
1450
|
+
i.info("EventManager", `⏳ Queue waiting: ${this.eventsQueue.length} events waiting for active session`);
|
|
1451
1451
|
return;
|
|
1452
1452
|
}
|
|
1453
1453
|
const e = this.buildEventsPayload();
|
|
1454
|
-
this.dataSender.sendEventsQueue(e) ? (
|
|
1454
|
+
this.dataSender.sendEventsQueue(e) ? (i.info("EventManager", "✅ Event queue sent successfully", {
|
|
1455
1455
|
eventsCount: e.events.length,
|
|
1456
1456
|
sessionId: e.session_id,
|
|
1457
1457
|
uniqueEventsAfterDedup: e.events.length
|
|
1458
|
-
}), this.eventsQueue = [], this.failureCount = 0, this.backoffDelay =
|
|
1458
|
+
}), this.eventsQueue = [], this.failureCount = 0, this.backoffDelay = E.INITIAL_BACKOFF_DELAY_MS, this.clearPersistedEvents()) : (i.info("EventManager", "❌ Failed to send event queue", {
|
|
1459
1459
|
eventsCount: e.events.length,
|
|
1460
1460
|
failureCount: this.failureCount + 1,
|
|
1461
1461
|
willOpenCircuit: this.failureCount + 1 >= this.MAX_FAILURES
|
|
@@ -1464,11 +1464,11 @@ class Mt extends p {
|
|
|
1464
1464
|
buildEventsPayload() {
|
|
1465
1465
|
const e = /* @__PURE__ */ new Map();
|
|
1466
1466
|
for (const s of this.eventsQueue) {
|
|
1467
|
-
let
|
|
1468
|
-
s.click_data && (
|
|
1467
|
+
let n = `${s.type}_${s.page_url}`;
|
|
1468
|
+
s.click_data && (n += `_${s.click_data.x}_${s.click_data.y}`), s.scroll_data && (n += `_${s.scroll_data.depth}_${s.scroll_data.direction}`), s.custom_event && (n += `_${s.custom_event.name}`), s.web_vitals && (n += `_${s.web_vitals.type}`), e.has(n) || e.set(n, s);
|
|
1469
1469
|
}
|
|
1470
1470
|
const t = [...e.values()];
|
|
1471
|
-
return t.sort((s,
|
|
1471
|
+
return t.sort((s, n) => s.timestamp - n.timestamp), {
|
|
1472
1472
|
user_id: this.get("userId"),
|
|
1473
1473
|
session_id: this.get("sessionId"),
|
|
1474
1474
|
device: this.get("device"),
|
|
@@ -1482,27 +1482,27 @@ class Mt extends p {
|
|
|
1482
1482
|
getEventFingerprint(e) {
|
|
1483
1483
|
const t = `${e.type}_${e.page_url}`;
|
|
1484
1484
|
if (e.click_data) {
|
|
1485
|
-
const s = Math.round((e.click_data.x || 0) / F) * F,
|
|
1486
|
-
return `${t}_${s}_${
|
|
1485
|
+
const s = Math.round((e.click_data.x || 0) / F) * F, n = Math.round((e.click_data.y || 0) / F) * F;
|
|
1486
|
+
return `${t}_${s}_${n}_${e.click_data.tag}_${e.click_data.id}`;
|
|
1487
1487
|
}
|
|
1488
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;
|
|
1489
1489
|
}
|
|
1490
1490
|
isDuplicatedEvent(e) {
|
|
1491
|
-
const t = this.getEventFingerprint(e), s = this.eventFingerprints.get(t) ?? 0,
|
|
1492
|
-
return
|
|
1491
|
+
const t = this.getEventFingerprint(e), s = this.eventFingerprints.get(t) ?? 0, n = Date.now();
|
|
1492
|
+
return n - s < he ? !0 : (this.eventFingerprints.set(t, n), this.cleanupOldFingerprints(), !1);
|
|
1493
1493
|
}
|
|
1494
1494
|
/**
|
|
1495
1495
|
* Cleans up old fingerprints to prevent memory leaks
|
|
1496
1496
|
*/
|
|
1497
1497
|
cleanupOldFingerprints() {
|
|
1498
|
-
if (this.eventFingerprints.size <=
|
|
1498
|
+
if (this.eventFingerprints.size <= Fe)
|
|
1499
1499
|
return;
|
|
1500
|
-
const e = Date.now(), t =
|
|
1501
|
-
for (const [
|
|
1502
|
-
e - a > t && s.push(
|
|
1503
|
-
for (const
|
|
1504
|
-
this.eventFingerprints.delete(
|
|
1505
|
-
|
|
1500
|
+
const e = Date.now(), t = he * ze, s = [];
|
|
1501
|
+
for (const [n, a] of this.eventFingerprints)
|
|
1502
|
+
e - a > t && s.push(n);
|
|
1503
|
+
for (const n of s)
|
|
1504
|
+
this.eventFingerprints.delete(n);
|
|
1505
|
+
i.debug("EventManager", "Cleaned up old event fingerprints", {
|
|
1506
1506
|
totalFingerprints: this.eventFingerprints.size + s.length,
|
|
1507
1507
|
cleanedCount: s.length,
|
|
1508
1508
|
remainingCount: this.eventFingerprints.size,
|
|
@@ -1515,24 +1515,24 @@ class Mt extends p {
|
|
|
1515
1515
|
openCircuitBreaker() {
|
|
1516
1516
|
this.circuitOpen = !0, this.circuitOpenTime = Date.now(), this.persistEventsToStorage();
|
|
1517
1517
|
const e = this.eventsQueue.length;
|
|
1518
|
-
this.eventsQueue = [],
|
|
1518
|
+
this.eventsQueue = [], i.warn("EventManager", "Circuit breaker opened with time-based recovery", {
|
|
1519
1519
|
maxFailures: this.MAX_FAILURES,
|
|
1520
1520
|
persistedEvents: e,
|
|
1521
1521
|
failureCount: this.failureCount,
|
|
1522
|
-
recoveryTime:
|
|
1522
|
+
recoveryTime: E.RECOVERY_TIME_MS,
|
|
1523
1523
|
openTime: this.circuitOpenTime
|
|
1524
1524
|
}), this.backoffDelay = Math.min(
|
|
1525
|
-
this.backoffDelay *
|
|
1526
|
-
|
|
1525
|
+
this.backoffDelay * E.BACKOFF_MULTIPLIER,
|
|
1526
|
+
E.MAX_BACKOFF_DELAY_MS
|
|
1527
1527
|
);
|
|
1528
1528
|
}
|
|
1529
1529
|
/**
|
|
1530
1530
|
* Resets the circuit breaker and attempts to restore persisted events
|
|
1531
1531
|
*/
|
|
1532
1532
|
resetCircuitBreaker() {
|
|
1533
|
-
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, i.info("EventManager", "Circuit breaker reset - attempting to restore events", {
|
|
1534
1534
|
currentQueueLength: this.eventsQueue.length
|
|
1535
|
-
}), this.restoreEventsFromStorage(),
|
|
1535
|
+
}), this.restoreEventsFromStorage(), i.info("EventManager", "Circuit breaker reset completed", {
|
|
1536
1536
|
restoredQueueLength: this.eventsQueue.length,
|
|
1537
1537
|
backoffDelay: this.backoffDelay
|
|
1538
1538
|
});
|
|
@@ -1549,12 +1549,12 @@ class Mt extends p {
|
|
|
1549
1549
|
timestamp: Date.now(),
|
|
1550
1550
|
failureCount: this.failureCount
|
|
1551
1551
|
};
|
|
1552
|
-
this.storageManager.setItem(this.PERSISTENCE_KEY, JSON.stringify(e)),
|
|
1552
|
+
this.storageManager.setItem(this.PERSISTENCE_KEY, JSON.stringify(e)), i.debug("EventManager", "Events persisted to storage for recovery", {
|
|
1553
1553
|
eventsCount: this.eventsQueue.length,
|
|
1554
1554
|
failureCount: this.failureCount
|
|
1555
1555
|
});
|
|
1556
1556
|
} catch (e) {
|
|
1557
|
-
|
|
1557
|
+
i.warn("EventManager", "Failed to persist events to storage", {
|
|
1558
1558
|
error: e instanceof Error ? e.message : "Unknown error",
|
|
1559
1559
|
eventsCount: this.eventsQueue.length
|
|
1560
1560
|
});
|
|
@@ -1568,20 +1568,20 @@ class Mt extends p {
|
|
|
1568
1568
|
const e = this.storageManager.getItem(this.PERSISTENCE_KEY);
|
|
1569
1569
|
if (!e)
|
|
1570
1570
|
return;
|
|
1571
|
-
const t = JSON.parse(e), s = Date.now(),
|
|
1572
|
-
if (s - t.timestamp >
|
|
1573
|
-
this.clearPersistedEvents(),
|
|
1571
|
+
const t = JSON.parse(e), s = Date.now(), n = Be;
|
|
1572
|
+
if (s - t.timestamp > n) {
|
|
1573
|
+
this.clearPersistedEvents(), i.debug("EventManager", "Cleared expired persisted events", {
|
|
1574
1574
|
age: s - t.timestamp,
|
|
1575
|
-
maxAge:
|
|
1575
|
+
maxAge: n
|
|
1576
1576
|
});
|
|
1577
1577
|
return;
|
|
1578
1578
|
}
|
|
1579
|
-
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, i.info("EventManager", "Restored events from storage", {
|
|
1580
1580
|
restoredCount: t.events.length,
|
|
1581
1581
|
originalFailureCount: t.failureCount ?? 0
|
|
1582
1582
|
}));
|
|
1583
1583
|
} catch (e) {
|
|
1584
|
-
|
|
1584
|
+
i.warn("EventManager", "Failed to restore events from storage", {
|
|
1585
1585
|
error: e instanceof Error ? e.message : "Unknown error"
|
|
1586
1586
|
}), this.clearPersistedEvents();
|
|
1587
1587
|
}
|
|
@@ -1591,28 +1591,28 @@ class Mt extends p {
|
|
|
1591
1591
|
*/
|
|
1592
1592
|
clearPersistedEvents() {
|
|
1593
1593
|
try {
|
|
1594
|
-
this.storageManager.removeItem(this.PERSISTENCE_KEY),
|
|
1594
|
+
this.storageManager.removeItem(this.PERSISTENCE_KEY), i.debug("EventManager", "Cleared persisted events from storage");
|
|
1595
1595
|
} catch (e) {
|
|
1596
|
-
|
|
1596
|
+
i.warn("EventManager", "Failed to clear persisted events", {
|
|
1597
1597
|
error: e instanceof Error ? e.message : "Unknown error"
|
|
1598
1598
|
});
|
|
1599
1599
|
}
|
|
1600
1600
|
}
|
|
1601
1601
|
}
|
|
1602
|
-
class
|
|
1602
|
+
class _t extends p {
|
|
1603
1603
|
storageManager;
|
|
1604
1604
|
constructor(e) {
|
|
1605
1605
|
super(), this.storageManager = e;
|
|
1606
1606
|
}
|
|
1607
1607
|
getId() {
|
|
1608
|
-
const e = this.storageManager.getItem(
|
|
1608
|
+
const e = this.storageManager.getItem(Se(this.get("config")?.id));
|
|
1609
1609
|
if (e)
|
|
1610
1610
|
return e;
|
|
1611
1611
|
const t = $();
|
|
1612
|
-
return this.storageManager.setItem(
|
|
1612
|
+
return this.storageManager.setItem(Se(this.get("config")?.id), t), t;
|
|
1613
1613
|
}
|
|
1614
1614
|
}
|
|
1615
|
-
class
|
|
1615
|
+
class Lt {
|
|
1616
1616
|
onActivity;
|
|
1617
1617
|
options = { passive: !0 };
|
|
1618
1618
|
constructor(e) {
|
|
@@ -1622,18 +1622,18 @@ class _t {
|
|
|
1622
1622
|
try {
|
|
1623
1623
|
window.addEventListener("scroll", this.onActivity, this.options), window.addEventListener("resize", this.onActivity, this.options), window.addEventListener("focus", this.onActivity, this.options);
|
|
1624
1624
|
} catch (e) {
|
|
1625
|
-
throw
|
|
1625
|
+
throw i.error("ActivityListenerManager", "Failed to setup activity listeners", { error: e }), e;
|
|
1626
1626
|
}
|
|
1627
1627
|
}
|
|
1628
1628
|
cleanup() {
|
|
1629
1629
|
try {
|
|
1630
1630
|
window.removeEventListener("scroll", this.onActivity), window.removeEventListener("resize", this.onActivity), window.removeEventListener("focus", this.onActivity);
|
|
1631
1631
|
} catch (e) {
|
|
1632
|
-
|
|
1632
|
+
i.warn("ActivityListenerManager", "Error during activity listeners cleanup", { error: e });
|
|
1633
1633
|
}
|
|
1634
1634
|
}
|
|
1635
1635
|
}
|
|
1636
|
-
class
|
|
1636
|
+
class Rt {
|
|
1637
1637
|
onActivity;
|
|
1638
1638
|
options = { passive: !0 };
|
|
1639
1639
|
motionThreshold;
|
|
@@ -1644,14 +1644,14 @@ class Ct {
|
|
|
1644
1644
|
try {
|
|
1645
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);
|
|
1646
1646
|
} catch (e) {
|
|
1647
|
-
throw
|
|
1647
|
+
throw i.error("TouchListenerManager", "Failed to setup touch listeners", { error: e }), e;
|
|
1648
1648
|
}
|
|
1649
1649
|
}
|
|
1650
1650
|
cleanup() {
|
|
1651
1651
|
try {
|
|
1652
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);
|
|
1653
1653
|
} catch (e) {
|
|
1654
|
-
|
|
1654
|
+
i.warn("TouchListenerManager", "Error during touch listeners cleanup", { error: e });
|
|
1655
1655
|
}
|
|
1656
1656
|
}
|
|
1657
1657
|
handleDeviceMotion = (e) => {
|
|
@@ -1659,11 +1659,11 @@ class Ct {
|
|
|
1659
1659
|
const t = e.acceleration;
|
|
1660
1660
|
t && Math.abs(t.x ?? 0) + Math.abs(t.y ?? 0) + Math.abs(t.z ?? 0) > this.motionThreshold && this.onActivity();
|
|
1661
1661
|
} catch (t) {
|
|
1662
|
-
|
|
1662
|
+
i.warn("TouchListenerManager", "Error handling device motion event", { error: t });
|
|
1663
1663
|
}
|
|
1664
1664
|
};
|
|
1665
1665
|
}
|
|
1666
|
-
class
|
|
1666
|
+
class kt {
|
|
1667
1667
|
onActivity;
|
|
1668
1668
|
options = { passive: !0 };
|
|
1669
1669
|
constructor(e) {
|
|
@@ -1673,18 +1673,18 @@ class Lt {
|
|
|
1673
1673
|
try {
|
|
1674
1674
|
window.addEventListener("mousemove", this.onActivity, this.options), window.addEventListener("mousedown", this.onActivity, this.options), window.addEventListener("wheel", this.onActivity, this.options);
|
|
1675
1675
|
} catch (e) {
|
|
1676
|
-
throw
|
|
1676
|
+
throw i.error("MouseListenerManager", "Failed to setup mouse listeners", { error: e }), e;
|
|
1677
1677
|
}
|
|
1678
1678
|
}
|
|
1679
1679
|
cleanup() {
|
|
1680
1680
|
try {
|
|
1681
1681
|
window.removeEventListener("mousemove", this.onActivity), window.removeEventListener("mousedown", this.onActivity), window.removeEventListener("wheel", this.onActivity);
|
|
1682
1682
|
} catch (e) {
|
|
1683
|
-
|
|
1683
|
+
i.warn("MouseListenerManager", "Error during mouse listeners cleanup", { error: e });
|
|
1684
1684
|
}
|
|
1685
1685
|
}
|
|
1686
1686
|
}
|
|
1687
|
-
class
|
|
1687
|
+
class Nt {
|
|
1688
1688
|
onActivity;
|
|
1689
1689
|
options = { passive: !0 };
|
|
1690
1690
|
constructor(e) {
|
|
@@ -1694,18 +1694,18 @@ class Rt {
|
|
|
1694
1694
|
try {
|
|
1695
1695
|
window.addEventListener("keydown", this.onActivity, this.options), window.addEventListener("keypress", this.onActivity, this.options);
|
|
1696
1696
|
} catch (e) {
|
|
1697
|
-
throw
|
|
1697
|
+
throw i.error("KeyboardListenerManager", "Failed to setup keyboard listeners", { error: e }), e;
|
|
1698
1698
|
}
|
|
1699
1699
|
}
|
|
1700
1700
|
cleanup() {
|
|
1701
1701
|
try {
|
|
1702
1702
|
window.removeEventListener("keydown", this.onActivity), window.removeEventListener("keypress", this.onActivity);
|
|
1703
1703
|
} catch (e) {
|
|
1704
|
-
|
|
1704
|
+
i.warn("KeyboardListenerManager", "Error during keyboard listeners cleanup", { error: e });
|
|
1705
1705
|
}
|
|
1706
1706
|
}
|
|
1707
1707
|
}
|
|
1708
|
-
class
|
|
1708
|
+
class Ht {
|
|
1709
1709
|
onActivity;
|
|
1710
1710
|
onVisibilityChange;
|
|
1711
1711
|
isMobile;
|
|
@@ -1717,32 +1717,32 @@ class kt {
|
|
|
1717
1717
|
try {
|
|
1718
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();
|
|
1719
1719
|
} catch (e) {
|
|
1720
|
-
throw
|
|
1720
|
+
throw i.error("VisibilityListenerManager", "Failed to setup visibility listeners", { error: e }), e;
|
|
1721
1721
|
}
|
|
1722
1722
|
}
|
|
1723
1723
|
cleanup() {
|
|
1724
1724
|
try {
|
|
1725
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();
|
|
1726
1726
|
} catch (e) {
|
|
1727
|
-
|
|
1727
|
+
i.warn("VisibilityListenerManager", "Error during visibility listeners cleanup", { error: e });
|
|
1728
1728
|
}
|
|
1729
1729
|
}
|
|
1730
1730
|
setupMobileEvents() {
|
|
1731
1731
|
try {
|
|
1732
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);
|
|
1733
1733
|
} catch (e) {
|
|
1734
|
-
|
|
1734
|
+
i.warn("VisibilityListenerManager", "Failed to setup mobile listeners", { error: e });
|
|
1735
1735
|
}
|
|
1736
1736
|
}
|
|
1737
1737
|
cleanupMobileEvents() {
|
|
1738
1738
|
try {
|
|
1739
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);
|
|
1740
1740
|
} catch (e) {
|
|
1741
|
-
|
|
1741
|
+
i.warn("VisibilityListenerManager", "Error during mobile listeners cleanup", { error: e });
|
|
1742
1742
|
}
|
|
1743
1743
|
}
|
|
1744
1744
|
}
|
|
1745
|
-
class
|
|
1745
|
+
class Pt {
|
|
1746
1746
|
onInactivity;
|
|
1747
1747
|
options = { passive: !0 };
|
|
1748
1748
|
constructor(e) {
|
|
@@ -1752,65 +1752,65 @@ class Nt {
|
|
|
1752
1752
|
try {
|
|
1753
1753
|
window.addEventListener("beforeunload", this.onInactivity, this.options), window.addEventListener("pagehide", this.onInactivity, this.options);
|
|
1754
1754
|
} catch (e) {
|
|
1755
|
-
throw
|
|
1755
|
+
throw i.error("UnloadListenerManager", "Failed to setup unload listeners", { error: e }), e;
|
|
1756
1756
|
}
|
|
1757
1757
|
}
|
|
1758
1758
|
cleanup() {
|
|
1759
1759
|
try {
|
|
1760
1760
|
window.removeEventListener("beforeunload", this.onInactivity), window.removeEventListener("pagehide", this.onInactivity);
|
|
1761
1761
|
} catch (e) {
|
|
1762
|
-
|
|
1762
|
+
i.warn("UnloadListenerManager", "Error during unload listeners cleanup", { error: e });
|
|
1763
1763
|
}
|
|
1764
1764
|
}
|
|
1765
1765
|
}
|
|
1766
|
-
class
|
|
1766
|
+
class Le extends p {
|
|
1767
1767
|
config;
|
|
1768
1768
|
storageManager;
|
|
1769
1769
|
eventManager;
|
|
1770
1770
|
projectId;
|
|
1771
1771
|
debugMode;
|
|
1772
|
-
constructor(e, t, s,
|
|
1772
|
+
constructor(e, t, s, n) {
|
|
1773
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 = {
|
|
1774
1774
|
recoveryWindowMs: this.calculateRecoveryWindow(),
|
|
1775
|
-
maxRecoveryAttempts:
|
|
1775
|
+
maxRecoveryAttempts: Je,
|
|
1776
1776
|
contextPreservation: !0,
|
|
1777
|
-
...
|
|
1777
|
+
...n
|
|
1778
1778
|
};
|
|
1779
1779
|
}
|
|
1780
1780
|
/**
|
|
1781
1781
|
* Attempt to recover a session
|
|
1782
1782
|
*/
|
|
1783
1783
|
attemptSessionRecovery(e) {
|
|
1784
|
-
this.debugMode &&
|
|
1784
|
+
this.debugMode && i.debug("SessionRecovery", "Attempting session recovery");
|
|
1785
1785
|
const t = this.getStoredRecoveryAttempts(), s = this.getLastRecoveryAttempt();
|
|
1786
1786
|
if (!this.canAttemptRecovery(s))
|
|
1787
|
-
return this.debugMode &&
|
|
1787
|
+
return this.debugMode && i.debug(
|
|
1788
1788
|
"SessionRecovery",
|
|
1789
1789
|
"Session recovery not possible - outside recovery window or max attempts reached"
|
|
1790
1790
|
), {
|
|
1791
1791
|
recovered: !1
|
|
1792
1792
|
};
|
|
1793
|
-
const
|
|
1794
|
-
if (!
|
|
1795
|
-
return this.debugMode &&
|
|
1793
|
+
const n = s?.context;
|
|
1794
|
+
if (!n)
|
|
1795
|
+
return this.debugMode && i.debug("SessionRecovery", "No session context available for recovery"), {
|
|
1796
1796
|
recovered: !1
|
|
1797
1797
|
};
|
|
1798
1798
|
const a = Date.now();
|
|
1799
|
-
if (a -
|
|
1800
|
-
return this.debugMode &&
|
|
1799
|
+
if (a - n.lastActivity > this.config.recoveryWindowMs)
|
|
1800
|
+
return this.debugMode && i.debug("SessionRecovery", "Session recovery failed - outside recovery window"), {
|
|
1801
1801
|
recovered: !1
|
|
1802
1802
|
};
|
|
1803
|
-
const l =
|
|
1803
|
+
const l = n.sessionId, c = (s?.attempt ?? 0) + 1, d = {
|
|
1804
1804
|
sessionId: e ?? l,
|
|
1805
1805
|
timestamp: a,
|
|
1806
1806
|
attempt: c,
|
|
1807
1807
|
context: {
|
|
1808
|
-
...
|
|
1808
|
+
...n,
|
|
1809
1809
|
recoveryAttempts: c,
|
|
1810
1810
|
lastActivity: a
|
|
1811
1811
|
}
|
|
1812
1812
|
};
|
|
1813
|
-
return t.push(d), this.storeRecoveryAttempts(t), this.debugMode &&
|
|
1813
|
+
return t.push(d), this.storeRecoveryAttempts(t), this.debugMode && i.debug("SessionRecovery", `Session recovery successful: recovery of session ${l}`), {
|
|
1814
1814
|
recovered: !0,
|
|
1815
1815
|
recoveredSessionId: l,
|
|
1816
1816
|
context: d.context
|
|
@@ -1820,16 +1820,16 @@ class Ce extends p {
|
|
|
1820
1820
|
* Calculate the recovery window with bounds checking
|
|
1821
1821
|
*/
|
|
1822
1822
|
calculateRecoveryWindow() {
|
|
1823
|
-
const t = (this.get("config")?.sessionTimeout ?? R) *
|
|
1824
|
-
Math.min(t,
|
|
1825
|
-
|
|
1823
|
+
const t = (this.get("config")?.sessionTimeout ?? R) * Ye, s = Math.max(
|
|
1824
|
+
Math.min(t, K),
|
|
1825
|
+
Y
|
|
1826
1826
|
);
|
|
1827
|
-
return this.debugMode && (t >
|
|
1827
|
+
return this.debugMode && (t > K ? i.warn(
|
|
1828
1828
|
"SessionRecovery",
|
|
1829
|
-
`Recovery window capped at ${
|
|
1830
|
-
) : t <
|
|
1829
|
+
`Recovery window capped at ${K}ms (24h). Calculated: ${t}ms`
|
|
1830
|
+
) : t < Y && i.warn(
|
|
1831
1831
|
"SessionRecovery",
|
|
1832
|
-
`Recovery window increased to minimum ${
|
|
1832
|
+
`Recovery window increased to minimum ${Y}ms (2min). Calculated: ${t}ms`
|
|
1833
1833
|
)), s;
|
|
1834
1834
|
}
|
|
1835
1835
|
/**
|
|
@@ -1850,10 +1850,10 @@ class Ce extends p {
|
|
|
1850
1850
|
context: e
|
|
1851
1851
|
};
|
|
1852
1852
|
t.push(s);
|
|
1853
|
-
const
|
|
1854
|
-
t.length >
|
|
1853
|
+
const n = 5;
|
|
1854
|
+
t.length > n && t.splice(0, t.length - n), this.storeRecoveryAttempts(t), this.debugMode && i.debug("SessionRecovery", `Stored session context for recovery: ${e.sessionId}`);
|
|
1855
1855
|
} catch (t) {
|
|
1856
|
-
this.debugMode &&
|
|
1856
|
+
this.debugMode && i.warn("SessionRecovery", "Failed to store session context for recovery", { error: t });
|
|
1857
1857
|
}
|
|
1858
1858
|
}
|
|
1859
1859
|
/**
|
|
@@ -1866,7 +1866,7 @@ class Ce extends p {
|
|
|
1866
1866
|
} catch (e) {
|
|
1867
1867
|
if (this.debugMode) {
|
|
1868
1868
|
const t = this.storageManager.getItem(V(this.projectId));
|
|
1869
|
-
|
|
1869
|
+
i.warn(
|
|
1870
1870
|
"SessionRecovery",
|
|
1871
1871
|
`Failed to parse stored recovery attempts for projectId ${this.projectId}. Data: ${t}`,
|
|
1872
1872
|
{ error: e }
|
|
@@ -1882,7 +1882,7 @@ class Ce extends p {
|
|
|
1882
1882
|
try {
|
|
1883
1883
|
this.storageManager.setItem(V(this.projectId), JSON.stringify(e));
|
|
1884
1884
|
} catch (t) {
|
|
1885
|
-
this.debugMode &&
|
|
1885
|
+
this.debugMode && i.warn("SessionRecovery", "Failed to store recovery attempts", { error: t });
|
|
1886
1886
|
}
|
|
1887
1887
|
}
|
|
1888
1888
|
/**
|
|
@@ -1896,8 +1896,8 @@ class Ce extends p {
|
|
|
1896
1896
|
* Clean up old recovery attempts
|
|
1897
1897
|
*/
|
|
1898
1898
|
cleanupOldRecoveryAttempts() {
|
|
1899
|
-
const e = this.getStoredRecoveryAttempts(), t = Date.now(), s = e.filter((
|
|
1900
|
-
s.length !== e.length && (this.storeRecoveryAttempts(s), this.debugMode &&
|
|
1899
|
+
const e = this.getStoredRecoveryAttempts(), t = Date.now(), s = e.filter((n) => t - n.timestamp <= this.config.recoveryWindowMs);
|
|
1900
|
+
s.length !== e.length && (this.storeRecoveryAttempts(s), this.debugMode && i.debug("SessionRecovery", `Cleaned up ${e.length - s.length} old recovery attempts`));
|
|
1901
1901
|
}
|
|
1902
1902
|
/**
|
|
1903
1903
|
* Check if there's a recoverable session.
|
|
@@ -1923,7 +1923,7 @@ class Ce extends p {
|
|
|
1923
1923
|
* Clear all stored recovery data
|
|
1924
1924
|
*/
|
|
1925
1925
|
clearRecoveryData() {
|
|
1926
|
-
this.storageManager.removeItem(V(this.projectId)), this.debugMode &&
|
|
1926
|
+
this.storageManager.removeItem(V(this.projectId)), this.debugMode && i.debug("SessionRecovery", "Cleared all recovery data");
|
|
1927
1927
|
}
|
|
1928
1928
|
}
|
|
1929
1929
|
class Ut extends p {
|
|
@@ -1983,11 +1983,11 @@ class Ut extends p {
|
|
|
1983
1983
|
crossTabConflicts: 0,
|
|
1984
1984
|
lastHealthCheck: Date.now()
|
|
1985
1985
|
};
|
|
1986
|
-
constructor(e, t, s,
|
|
1986
|
+
constructor(e, t, s, n, a) {
|
|
1987
1987
|
super(), this.config = {
|
|
1988
|
-
throttleDelay:
|
|
1989
|
-
visibilityTimeout:
|
|
1990
|
-
motionThreshold:
|
|
1988
|
+
throttleDelay: Me,
|
|
1989
|
+
visibilityTimeout: je,
|
|
1990
|
+
motionThreshold: He,
|
|
1991
1991
|
timeout: this.get("config")?.sessionTimeout ?? R
|
|
1992
1992
|
}, this.sessionEndConfig = {
|
|
1993
1993
|
enablePageUnloadHandlers: !0,
|
|
@@ -1995,7 +1995,7 @@ class Ut extends p {
|
|
|
1995
1995
|
maxRetries: 2,
|
|
1996
1996
|
debugMode: !1,
|
|
1997
1997
|
...a
|
|
1998
|
-
}, this.onActivity = e, this.onInactivity = t, this.eventManager = s ?? null, this.storageManager =
|
|
1998
|
+
}, this.onActivity = e, this.onInactivity = t, this.eventManager = s ?? null, this.storageManager = n ?? null, this.deviceCapabilities = this.detectDeviceCapabilities(), this.initializeRecoveryManager(), this.initializeListenerManagers(), this.setupAllListeners(), this.sessionEndConfig.enablePageUnloadHandlers && this.setupPageUnloadHandlers(), i.debug("SessionManager", "SessionManager initialized", {
|
|
1999
1999
|
sessionTimeout: this.config.timeout,
|
|
2000
2000
|
deviceCapabilities: this.deviceCapabilities,
|
|
2001
2001
|
unloadHandlersEnabled: this.sessionEndConfig.enablePageUnloadHandlers
|
|
@@ -2009,9 +2009,9 @@ class Ut extends p {
|
|
|
2009
2009
|
const e = this.get("config")?.id;
|
|
2010
2010
|
if (e)
|
|
2011
2011
|
try {
|
|
2012
|
-
this.recoveryManager = new
|
|
2012
|
+
this.recoveryManager = new Le(this.storageManager, e, this.eventManager ?? void 0), i.debug("SessionManager", "Recovery manager initialized", { projectId: e });
|
|
2013
2013
|
} catch (t) {
|
|
2014
|
-
|
|
2014
|
+
i.error("SessionManager", "Failed to initialize recovery manager", { error: t, projectId: e });
|
|
2015
2015
|
}
|
|
2016
2016
|
}
|
|
2017
2017
|
/**
|
|
@@ -2039,13 +2039,13 @@ class Ut extends p {
|
|
|
2039
2039
|
const e = Date.now();
|
|
2040
2040
|
let t = "", s = !1;
|
|
2041
2041
|
if (this.recoveryManager?.hasRecoverableSession()) {
|
|
2042
|
-
const
|
|
2043
|
-
|
|
2042
|
+
const n = this.recoveryManager.attemptSessionRecovery();
|
|
2043
|
+
n.recovered && n.recoveredSessionId && (t = n.recoveredSessionId, s = !0, this.trackSessionHealth("recovery"), n.context ? (this.sessionStartTime = n.context.startTime, this.lastActivityTime = e) : (this.sessionStartTime = e, this.lastActivityTime = e), i.info("SessionManager", "Session successfully recovered", {
|
|
2044
2044
|
sessionId: t,
|
|
2045
2045
|
recoveryAttempts: this.sessionHealth.recoveryAttempts
|
|
2046
2046
|
}));
|
|
2047
2047
|
}
|
|
2048
|
-
return s || (t = $(), this.sessionStartTime = e, this.lastActivityTime = e,
|
|
2048
|
+
return s || (t = $(), this.sessionStartTime = e, this.lastActivityTime = e, i.info("SessionManager", "New session started", { sessionId: t })), this.isSessionActive = !0, this.resetInactivityTimer(), this.storeSessionContextForRecovery(), { sessionId: t, recovered: s };
|
|
2049
2049
|
}
|
|
2050
2050
|
endSession() {
|
|
2051
2051
|
if (this.sessionStartTime === 0)
|
|
@@ -2063,13 +2063,13 @@ class Ut extends p {
|
|
|
2063
2063
|
}), this.recoveryManager && (this.recoveryManager.cleanupOldRecoveryAttempts(), this.recoveryManager = null);
|
|
2064
2064
|
}
|
|
2065
2065
|
detectDeviceCapabilities() {
|
|
2066
|
-
const e = "ontouchstart" in window || navigator.maxTouchPoints > 0, t = window.matchMedia("(pointer: fine)").matches, s = !window.matchMedia("(pointer: coarse)").matches,
|
|
2067
|
-
return { hasTouch: e, hasMouse: t, hasKeyboard: s, isMobile:
|
|
2066
|
+
const e = "ontouchstart" in window || navigator.maxTouchPoints > 0, t = window.matchMedia("(pointer: fine)").matches, s = !window.matchMedia("(pointer: coarse)").matches, n = Ie() === w.Mobile;
|
|
2067
|
+
return { hasTouch: e, hasMouse: t, hasKeyboard: s, isMobile: n };
|
|
2068
2068
|
}
|
|
2069
2069
|
initializeListenerManagers() {
|
|
2070
|
-
this.listenerManagers.push(new
|
|
2071
|
-
new
|
|
2072
|
-
), this.listenerManagers.push(new
|
|
2070
|
+
this.listenerManagers.push(new Lt(this.handleActivity)), this.deviceCapabilities.hasTouch && this.listenerManagers.push(new Rt(this.handleActivity, this.config.motionThreshold)), this.deviceCapabilities.hasMouse && this.listenerManagers.push(new kt(this.handleActivity)), this.deviceCapabilities.hasKeyboard && this.listenerManagers.push(new Nt(this.handleActivity)), this.listenerManagers.push(
|
|
2071
|
+
new Ht(this.handleActivity, this.handleVisibilityChange, this.deviceCapabilities.isMobile)
|
|
2072
|
+
), this.listenerManagers.push(new Pt(this.handleInactivity));
|
|
2073
2073
|
}
|
|
2074
2074
|
setupAllListeners() {
|
|
2075
2075
|
this.listenerManagers.forEach((e) => e.setup());
|
|
@@ -2118,9 +2118,9 @@ class Ut extends p {
|
|
|
2118
2118
|
async endSessionManaged(e) {
|
|
2119
2119
|
return this.sessionEndLock = this.sessionEndLock.then(async () => {
|
|
2120
2120
|
if (this.sessionEndStats.totalSessionEnds++, this.sessionEndStats.reasonCounts[e]++, this.pendingSessionEnd)
|
|
2121
|
-
return this.sessionEndStats.duplicatePrevented++,
|
|
2121
|
+
return this.sessionEndStats.duplicatePrevented++, i.debug("SessionManager", "Session end already pending, waiting for completion", { reason: e }), this.waitForCompletion();
|
|
2122
2122
|
if (!this.shouldProceedWithSessionEnd(e))
|
|
2123
|
-
return this.sessionEndConfig.debugMode &&
|
|
2123
|
+
return this.sessionEndConfig.debugMode && i.debug(
|
|
2124
2124
|
"SessionManager",
|
|
2125
2125
|
`Session end skipped due to lower priority. Current: ${this.sessionEndReason}, Requested: ${e}`
|
|
2126
2126
|
), {
|
|
@@ -2161,7 +2161,7 @@ class Ut extends p {
|
|
|
2161
2161
|
break;
|
|
2162
2162
|
}
|
|
2163
2163
|
this.sessionHealth.lastHealthCheck = t, this.sessionHealth.recoveryAttempts > 3 && this.eventManager && (this.eventManager.track({
|
|
2164
|
-
type:
|
|
2164
|
+
type: g.CUSTOM,
|
|
2165
2165
|
custom_event: {
|
|
2166
2166
|
name: "session_health_degraded",
|
|
2167
2167
|
metadata: {
|
|
@@ -2169,27 +2169,27 @@ class Ut extends p {
|
|
|
2169
2169
|
event_trigger: e
|
|
2170
2170
|
}
|
|
2171
2171
|
}
|
|
2172
|
-
}), this.sessionEndConfig.debugMode &&
|
|
2172
|
+
}), this.sessionEndConfig.debugMode && i.warn(
|
|
2173
2173
|
"SessionManager",
|
|
2174
2174
|
`Session health degraded: ${this.sessionHealth.recoveryAttempts} recovery attempts`
|
|
2175
|
-
)), this.sessionEndConfig.debugMode &&
|
|
2175
|
+
)), this.sessionEndConfig.debugMode && i.debug("SessionManager", `Session health event tracked: ${e}`);
|
|
2176
2176
|
}
|
|
2177
2177
|
async performSessionEnd(e, t) {
|
|
2178
2178
|
const s = Date.now();
|
|
2179
|
-
let
|
|
2179
|
+
let n = 0;
|
|
2180
2180
|
try {
|
|
2181
|
-
if (
|
|
2181
|
+
if (i.info("SessionManager", "Starting session end", { method: t, reason: e, timestamp: s }), this.eventManager) {
|
|
2182
2182
|
this.eventManager.track({
|
|
2183
|
-
type:
|
|
2183
|
+
type: g.SESSION_END,
|
|
2184
2184
|
session_end_reason: e
|
|
2185
|
-
}),
|
|
2185
|
+
}), n = this.eventManager.getQueueLength();
|
|
2186
2186
|
const o = await this.eventManager.flushImmediately();
|
|
2187
2187
|
this.cleanupSession();
|
|
2188
2188
|
const l = {
|
|
2189
2189
|
success: o,
|
|
2190
2190
|
reason: e,
|
|
2191
2191
|
timestamp: s,
|
|
2192
|
-
eventsFlushed:
|
|
2192
|
+
eventsFlushed: n,
|
|
2193
2193
|
method: t
|
|
2194
2194
|
};
|
|
2195
2195
|
return o ? this.sessionEndStats.successfulEnds++ : this.sessionEndStats.failedEnds++, l;
|
|
@@ -2204,11 +2204,11 @@ class Ut extends p {
|
|
|
2204
2204
|
};
|
|
2205
2205
|
return this.sessionEndStats.successfulEnds++, a;
|
|
2206
2206
|
} catch (a) {
|
|
2207
|
-
return this.sessionEndStats.failedEnds++,
|
|
2207
|
+
return this.sessionEndStats.failedEnds++, i.error("SessionManager", "Session end failed", { error: a, reason: e, method: t }), this.cleanupSession(), {
|
|
2208
2208
|
success: !1,
|
|
2209
2209
|
reason: e,
|
|
2210
2210
|
timestamp: s,
|
|
2211
|
-
eventsFlushed:
|
|
2211
|
+
eventsFlushed: n,
|
|
2212
2212
|
method: t
|
|
2213
2213
|
};
|
|
2214
2214
|
}
|
|
@@ -2217,8 +2217,8 @@ class Ut extends p {
|
|
|
2217
2217
|
this.endSession(), this.clearTimers(), this.set("sessionId", null), this.set("hasStartSession", !1);
|
|
2218
2218
|
}
|
|
2219
2219
|
endSessionManagedSync(e) {
|
|
2220
|
-
if (this.sessionEndStats.totalSessionEnds++, this.sessionEndStats.reasonCounts[e]++, this.pendingSessionEnd && (this.sessionEndStats.duplicatePrevented++,
|
|
2221
|
-
return this.sessionEndConfig.debugMode &&
|
|
2220
|
+
if (this.sessionEndStats.totalSessionEnds++, this.sessionEndStats.reasonCounts[e]++, this.pendingSessionEnd && (this.sessionEndStats.duplicatePrevented++, i.warn("SessionManager", "Sync session end called while async end pending", { reason: e })), !this.shouldProceedWithSessionEnd(e))
|
|
2221
|
+
return this.sessionEndConfig.debugMode && i.debug(
|
|
2222
2222
|
"SessionManager",
|
|
2223
2223
|
`Sync session end skipped due to lower priority. Current: ${this.sessionEndReason}, Requested: ${e}`
|
|
2224
2224
|
), {
|
|
@@ -2241,7 +2241,7 @@ class Ut extends p {
|
|
|
2241
2241
|
try {
|
|
2242
2242
|
if (this.eventManager) {
|
|
2243
2243
|
this.eventManager.track({
|
|
2244
|
-
type:
|
|
2244
|
+
type: g.SESSION_END,
|
|
2245
2245
|
session_end_reason: e
|
|
2246
2246
|
}), s = this.eventManager.getQueueLength();
|
|
2247
2247
|
const a = this.eventManager.flushImmediatelySync();
|
|
@@ -2256,16 +2256,16 @@ class Ut extends p {
|
|
|
2256
2256
|
return a ? this.sessionEndStats.successfulEnds++ : this.sessionEndStats.failedEnds++, o;
|
|
2257
2257
|
}
|
|
2258
2258
|
this.cleanupSession();
|
|
2259
|
-
const
|
|
2259
|
+
const n = {
|
|
2260
2260
|
success: !0,
|
|
2261
2261
|
reason: e,
|
|
2262
2262
|
timestamp: t,
|
|
2263
2263
|
eventsFlushed: 0,
|
|
2264
2264
|
method: "sync"
|
|
2265
2265
|
};
|
|
2266
|
-
return this.sessionEndStats.successfulEnds++,
|
|
2267
|
-
} catch (
|
|
2268
|
-
return this.sessionEndStats.failedEnds++, this.cleanupSession(),
|
|
2266
|
+
return this.sessionEndStats.successfulEnds++, n;
|
|
2267
|
+
} catch (n) {
|
|
2268
|
+
return this.sessionEndStats.failedEnds++, this.cleanupSession(), i.error("SessionManager", "Sync session end failed", { error: n, reason: e }), {
|
|
2269
2269
|
success: !1,
|
|
2270
2270
|
reason: e,
|
|
2271
2271
|
timestamp: t,
|
|
@@ -2280,16 +2280,16 @@ class Ut extends p {
|
|
|
2280
2280
|
e || !this.get("sessionId") || (e = !0, this.clearInactivityTimer(), this.endSessionSafely("page_unload", { forceSync: !0 }));
|
|
2281
2281
|
}, s = () => {
|
|
2282
2282
|
t();
|
|
2283
|
-
},
|
|
2283
|
+
}, n = (o) => {
|
|
2284
2284
|
o.persisted || t();
|
|
2285
2285
|
}, a = () => {
|
|
2286
2286
|
document.visibilityState === "hidden" && this.get("sessionId") && !e && (this.visibilityChangeTimeout = window.setTimeout(() => {
|
|
2287
2287
|
document.visibilityState === "hidden" && this.get("sessionId") && !e && t(), this.visibilityChangeTimeout = null;
|
|
2288
2288
|
}, 1e3));
|
|
2289
2289
|
};
|
|
2290
|
-
window.addEventListener("beforeunload", s), window.addEventListener("pagehide",
|
|
2290
|
+
window.addEventListener("beforeunload", s), window.addEventListener("pagehide", n), document.addEventListener("visibilitychange", a), this.cleanupHandlers.push(
|
|
2291
2291
|
() => window.removeEventListener("beforeunload", s),
|
|
2292
|
-
() => window.removeEventListener("pagehide",
|
|
2292
|
+
() => window.removeEventListener("pagehide", n),
|
|
2293
2293
|
() => document.removeEventListener("visibilitychange", a),
|
|
2294
2294
|
() => {
|
|
2295
2295
|
this.visibilityChangeTimeout && (clearTimeout(this.visibilityChangeTimeout), this.visibilityChangeTimeout = null);
|
|
@@ -2297,11 +2297,11 @@ class Ut extends p {
|
|
|
2297
2297
|
);
|
|
2298
2298
|
}
|
|
2299
2299
|
}
|
|
2300
|
-
class
|
|
2301
|
-
constructor(e, t, s,
|
|
2302
|
-
super(), this.callbacks =
|
|
2303
|
-
tabHeartbeatIntervalMs:
|
|
2304
|
-
tabElectionTimeoutMs:
|
|
2300
|
+
class Ot extends p {
|
|
2301
|
+
constructor(e, t, s, n) {
|
|
2302
|
+
super(), this.callbacks = n, this.storageManager = e, this.projectId = t, this.tabId = $(), this.config = {
|
|
2303
|
+
tabHeartbeatIntervalMs: Xe,
|
|
2304
|
+
tabElectionTimeoutMs: Ke,
|
|
2305
2305
|
debugMode: (this.get("config")?.mode === "qa" || this.get("config")?.mode === "debug") ?? !1,
|
|
2306
2306
|
...s
|
|
2307
2307
|
}, this.tabInfo = {
|
|
@@ -2338,10 +2338,10 @@ class Ht extends p {
|
|
|
2338
2338
|
if (!this.isBroadcastChannelSupported())
|
|
2339
2339
|
return null;
|
|
2340
2340
|
try {
|
|
2341
|
-
const e = new BroadcastChannel(
|
|
2341
|
+
const e = new BroadcastChannel(nt(this.projectId));
|
|
2342
2342
|
return this.setupBroadcastListeners(e), e;
|
|
2343
2343
|
} catch (e) {
|
|
2344
|
-
return this.config.debugMode &&
|
|
2344
|
+
return this.config.debugMode && i.warn("CrossTabSession", "Failed to initialize BroadcastChannel", { error: e }), null;
|
|
2345
2345
|
}
|
|
2346
2346
|
}
|
|
2347
2347
|
/**
|
|
@@ -2359,7 +2359,7 @@ class Ht extends p {
|
|
|
2359
2359
|
* Check if this tab should be the session leader
|
|
2360
2360
|
*/
|
|
2361
2361
|
tryJoinExistingSession(e) {
|
|
2362
|
-
this.config.debugMode &&
|
|
2362
|
+
this.config.debugMode && i.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();
|
|
2363
2363
|
}
|
|
2364
2364
|
/**
|
|
2365
2365
|
* Request leadership status from other tabs
|
|
@@ -2384,10 +2384,10 @@ class Ht extends p {
|
|
|
2384
2384
|
*/
|
|
2385
2385
|
startLeaderElection() {
|
|
2386
2386
|
if (this.electionTimeout) {
|
|
2387
|
-
this.config.debugMode &&
|
|
2387
|
+
this.config.debugMode && i.debug("CrossTabSession", "Leader election already in progress, skipping");
|
|
2388
2388
|
return;
|
|
2389
2389
|
}
|
|
2390
|
-
this.config.debugMode &&
|
|
2390
|
+
this.config.debugMode && i.debug("CrossTabSession", "Starting leader election");
|
|
2391
2391
|
const e = Math.floor(Math.random() * 50) + 10;
|
|
2392
2392
|
this.electionTimeout = window.setTimeout(() => {
|
|
2393
2393
|
this.electionTimeout = null, this.requestLeadershipStatus();
|
|
@@ -2398,7 +2398,7 @@ class Ht extends p {
|
|
|
2398
2398
|
*/
|
|
2399
2399
|
becomeLeader() {
|
|
2400
2400
|
if (!this.isTabLeader) {
|
|
2401
|
-
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 && i.debug("CrossTabSession", `Tab ${this.tabId} became session leader`), this.electionTimeout && (clearTimeout(this.electionTimeout), this.electionTimeout = null), this.tabInfo.sessionId) {
|
|
2402
2402
|
const e = this.getStoredSessionContext();
|
|
2403
2403
|
e && (e.lastActivity = Date.now(), this.storeSessionContext(e));
|
|
2404
2404
|
} else {
|
|
@@ -2449,10 +2449,10 @@ class Ht extends p {
|
|
|
2449
2449
|
setupLeadershipFallback() {
|
|
2450
2450
|
const e = this.config.tabElectionTimeoutMs + 1500;
|
|
2451
2451
|
this.fallbackLeadershipTimeout = window.setTimeout(() => {
|
|
2452
|
-
!this.isTabLeader && !this.leaderTabId && (this.tabInfo.sessionId ? (this.config.debugMode &&
|
|
2452
|
+
!this.isTabLeader && !this.leaderTabId && (this.tabInfo.sessionId ? (this.config.debugMode && i.warn(
|
|
2453
2453
|
"CrossTabSession",
|
|
2454
2454
|
`No leader detected after ${e}ms, forcing leadership for tab ${this.tabId}`
|
|
2455
|
-
), this.becomeLeader()) : (this.config.debugMode &&
|
|
2455
|
+
), this.becomeLeader()) : (this.config.debugMode && i.warn(
|
|
2456
2456
|
"CrossTabSession",
|
|
2457
2457
|
`No session or leader detected after ${e}ms, starting new session for tab ${this.tabId}`
|
|
2458
2458
|
), this.becomeLeader())), this.fallbackLeadershipTimeout = null;
|
|
@@ -2460,10 +2460,10 @@ class Ht extends p {
|
|
|
2460
2460
|
if (!this.sessionEnded && this.leaderTabId && !this.isTabLeader) {
|
|
2461
2461
|
const s = this.getStoredSessionContext();
|
|
2462
2462
|
if (s) {
|
|
2463
|
-
const
|
|
2464
|
-
|
|
2463
|
+
const n = Date.now() - s.lastActivity, a = this.config.tabHeartbeatIntervalMs * 3;
|
|
2464
|
+
n > a && (this.config.debugMode && i.warn(
|
|
2465
2465
|
"CrossTabSession",
|
|
2466
|
-
`Leader tab appears inactive (${
|
|
2466
|
+
`Leader tab appears inactive (${n}ms), attempting to become leader`
|
|
2467
2467
|
), this.leaderTabId = null, this.startLeaderElection());
|
|
2468
2468
|
}
|
|
2469
2469
|
}
|
|
@@ -2486,7 +2486,7 @@ class Ht extends p {
|
|
|
2486
2486
|
* Handle cross-tab messages
|
|
2487
2487
|
*/
|
|
2488
2488
|
handleCrossTabMessage(e) {
|
|
2489
|
-
switch (this.config.debugMode &&
|
|
2489
|
+
switch (this.config.debugMode && i.debug("CrossTabSession", `Received cross-tab message: ${e.type} from ${e.tabId}`), e.type) {
|
|
2490
2490
|
case "heartbeat":
|
|
2491
2491
|
this.handleHeartbeatMessage(e);
|
|
2492
2492
|
break;
|
|
@@ -2531,13 +2531,13 @@ class Ht extends p {
|
|
|
2531
2531
|
*/
|
|
2532
2532
|
handleSessionEndMessage(e) {
|
|
2533
2533
|
if (this.isTabLeader) {
|
|
2534
|
-
this.config.debugMode &&
|
|
2534
|
+
this.config.debugMode && i.debug("CrossTabSession", `Ignoring session end message from ${e.tabId} (this tab is leader)`);
|
|
2535
2535
|
return;
|
|
2536
2536
|
}
|
|
2537
2537
|
if (!this.leaderTabId || e.tabId !== this.leaderTabId) {
|
|
2538
2538
|
if (this.config.debugMode) {
|
|
2539
2539
|
const s = this.leaderTabId ? `; leader is ${this.leaderTabId}` : "";
|
|
2540
|
-
|
|
2540
|
+
i.debug("CrossTabSession", `Ignoring session end message from ${e.tabId}${s}`);
|
|
2541
2541
|
}
|
|
2542
2542
|
return;
|
|
2543
2543
|
}
|
|
@@ -2550,10 +2550,10 @@ class Ht extends p {
|
|
|
2550
2550
|
const t = this.getStoredSessionContext();
|
|
2551
2551
|
if (t && e.sessionId === t.sessionId) {
|
|
2552
2552
|
const s = t.tabCount;
|
|
2553
|
-
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 && i.debug(
|
|
2554
2554
|
"CrossTabSession",
|
|
2555
2555
|
`Tab count updated from ${s} to ${t.tabCount} after tab ${e.tabId} closed`
|
|
2556
|
-
), (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 && i.debug("CrossTabSession", `Leader tab ${e.tabId} closed, starting leader election`), this.leaderTabId = null, this.electionDelayTimeout = window.setTimeout(() => {
|
|
2557
2557
|
this.startLeaderElection(), this.electionDelayTimeout = null;
|
|
2558
2558
|
}, 200));
|
|
2559
2559
|
}
|
|
@@ -2577,10 +2577,10 @@ class Ht extends p {
|
|
|
2577
2577
|
* Handle election response from another tab
|
|
2578
2578
|
*/
|
|
2579
2579
|
handleElectionResponse(e) {
|
|
2580
|
-
e.data?.isLeader && (this.isTabLeader ? this.config.debugMode && (
|
|
2580
|
+
e.data?.isLeader && (this.isTabLeader ? this.config.debugMode && (i.warn(
|
|
2581
2581
|
"CrossTabSession",
|
|
2582
2582
|
`Received leadership claim from ${e.tabId} but this tab is already leader`
|
|
2583
|
-
), 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 && i.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())));
|
|
2584
2584
|
}
|
|
2585
2585
|
/**
|
|
2586
2586
|
* Start heartbeat to keep session active
|
|
@@ -2598,13 +2598,13 @@ class Ht extends p {
|
|
|
2598
2598
|
const e = Date.now(), t = this.lastHeartbeatSent ?? 0, s = this.config.tabHeartbeatIntervalMs * 0.8;
|
|
2599
2599
|
if (!this.isTabLeader && e - t < s)
|
|
2600
2600
|
return;
|
|
2601
|
-
const
|
|
2601
|
+
const n = {
|
|
2602
2602
|
type: "heartbeat",
|
|
2603
2603
|
tabId: this.tabId,
|
|
2604
2604
|
sessionId: this.tabInfo.sessionId,
|
|
2605
2605
|
timestamp: e
|
|
2606
2606
|
};
|
|
2607
|
-
this.broadcastChannel.postMessage(
|
|
2607
|
+
this.broadcastChannel.postMessage(n), this.lastHeartbeatSent = e;
|
|
2608
2608
|
}
|
|
2609
2609
|
/**
|
|
2610
2610
|
* Update tab info with current timestamp
|
|
@@ -2616,7 +2616,7 @@ class Ht extends p {
|
|
|
2616
2616
|
* End session and notify other tabs
|
|
2617
2617
|
*/
|
|
2618
2618
|
endSession(e) {
|
|
2619
|
-
this.sessionEnded || (this.sessionEnded = !0, this.config.debugMode &&
|
|
2619
|
+
this.sessionEnded || (this.sessionEnded = !0, this.config.debugMode && i.debug(
|
|
2620
2620
|
"CrossTabSession",
|
|
2621
2621
|
`Ending cross-tab session: ${e} (tab: ${this.tabId}, isLeader: ${this.isTabLeader})`
|
|
2622
2622
|
), this.announceTabClosing(), this.isTabLeader && e !== "manual_stop" && this.announceSessionEnd(e), this.tabInfoCleanupTimeout = window.setTimeout(() => {
|
|
@@ -2636,7 +2636,7 @@ class Ht extends p {
|
|
|
2636
2636
|
data: { isLeader: this.isTabLeader }
|
|
2637
2637
|
};
|
|
2638
2638
|
this.broadcastChannel.postMessage(e), this.closingAnnouncementTimeout = window.setTimeout(() => {
|
|
2639
|
-
this.config.debugMode &&
|
|
2639
|
+
this.config.debugMode && i.debug("CrossTabSession", `Tab ${this.tabId} closing announcement sent`), this.closingAnnouncementTimeout = null;
|
|
2640
2640
|
}, 100);
|
|
2641
2641
|
}
|
|
2642
2642
|
/**
|
|
@@ -2676,10 +2676,10 @@ class Ht extends p {
|
|
|
2676
2676
|
*/
|
|
2677
2677
|
getStoredSessionContext() {
|
|
2678
2678
|
try {
|
|
2679
|
-
const e = this.storageManager.getItem(
|
|
2679
|
+
const e = this.storageManager.getItem(J(this.projectId));
|
|
2680
2680
|
return e ? JSON.parse(e) : null;
|
|
2681
2681
|
} catch (e) {
|
|
2682
|
-
return this.config.debugMode &&
|
|
2682
|
+
return this.config.debugMode && i.warn("CrossTabSession", "Failed to parse stored session context", { error: e }), null;
|
|
2683
2683
|
}
|
|
2684
2684
|
}
|
|
2685
2685
|
/**
|
|
@@ -2687,32 +2687,32 @@ class Ht extends p {
|
|
|
2687
2687
|
*/
|
|
2688
2688
|
storeSessionContext(e) {
|
|
2689
2689
|
try {
|
|
2690
|
-
this.storageManager.setItem(
|
|
2690
|
+
this.storageManager.setItem(J(this.projectId), JSON.stringify(e));
|
|
2691
2691
|
} catch (t) {
|
|
2692
|
-
this.config.debugMode &&
|
|
2692
|
+
this.config.debugMode && i.warn("CrossTabSession", "Failed to store session context", { error: t });
|
|
2693
2693
|
}
|
|
2694
2694
|
}
|
|
2695
2695
|
/**
|
|
2696
2696
|
* Clear stored session context
|
|
2697
2697
|
*/
|
|
2698
2698
|
clearStoredSessionContext() {
|
|
2699
|
-
this.storageManager.removeItem(
|
|
2699
|
+
this.storageManager.removeItem(J(this.projectId));
|
|
2700
2700
|
}
|
|
2701
2701
|
/**
|
|
2702
2702
|
* Store tab info to localStorage
|
|
2703
2703
|
*/
|
|
2704
2704
|
storeTabInfo() {
|
|
2705
2705
|
try {
|
|
2706
|
-
this.storageManager.setItem(
|
|
2706
|
+
this.storageManager.setItem(be(this.projectId, this.tabId), JSON.stringify(this.tabInfo));
|
|
2707
2707
|
} catch (e) {
|
|
2708
|
-
this.config.debugMode &&
|
|
2708
|
+
this.config.debugMode && i.warn("CrossTabSession", "Failed to store tab info", { error: e });
|
|
2709
2709
|
}
|
|
2710
2710
|
}
|
|
2711
2711
|
/**
|
|
2712
2712
|
* Clear tab info from localStorage
|
|
2713
2713
|
*/
|
|
2714
2714
|
clearTabInfo() {
|
|
2715
|
-
this.storageManager.removeItem(
|
|
2715
|
+
this.storageManager.removeItem(be(this.projectId, this.tabId));
|
|
2716
2716
|
}
|
|
2717
2717
|
/**
|
|
2718
2718
|
* Check if BroadcastChannel is supported
|
|
@@ -2727,8 +2727,8 @@ class Ht extends p {
|
|
|
2727
2727
|
const e = this.getStoredSessionContext();
|
|
2728
2728
|
if (!e)
|
|
2729
2729
|
return this.get("config")?.sessionTimeout ?? R;
|
|
2730
|
-
const s = Date.now() - e.lastActivity,
|
|
2731
|
-
return Math.max(0,
|
|
2730
|
+
const s = Date.now() - e.lastActivity, n = this.get("config")?.sessionTimeout ?? R;
|
|
2731
|
+
return Math.max(0, n - s);
|
|
2732
2732
|
}
|
|
2733
2733
|
/**
|
|
2734
2734
|
* Update session activity from any tab
|
|
@@ -2744,7 +2744,7 @@ class Ht extends p {
|
|
|
2744
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();
|
|
2745
2745
|
}
|
|
2746
2746
|
}
|
|
2747
|
-
class
|
|
2747
|
+
class Dt extends p {
|
|
2748
2748
|
eventManager;
|
|
2749
2749
|
storageManager;
|
|
2750
2750
|
sessionStorageKey;
|
|
@@ -2760,7 +2760,7 @@ class Pt extends p {
|
|
|
2760
2760
|
const e = this.get("config")?.id;
|
|
2761
2761
|
e && this.initializeCrossTabSessionManager(e);
|
|
2762
2762
|
} catch (e) {
|
|
2763
|
-
|
|
2763
|
+
i.error("SessionHandler", "Failed to initialize cross-tab session manager", {
|
|
2764
2764
|
error: e instanceof Error ? e.message : "Unknown error"
|
|
2765
2765
|
});
|
|
2766
2766
|
} finally {
|
|
@@ -2773,56 +2773,56 @@ class Pt extends p {
|
|
|
2773
2773
|
return typeof BroadcastChannel < "u" && typeof navigator < "u" && "serviceWorker" in navigator;
|
|
2774
2774
|
}
|
|
2775
2775
|
constructor(e, t) {
|
|
2776
|
-
super(), this.eventManager = t, this.storageManager = e, this.sessionStorageKey =
|
|
2776
|
+
super(), this.eventManager = t, this.storageManager = e, this.sessionStorageKey = it(this.get("config")?.id);
|
|
2777
2777
|
const s = this.get("config")?.id;
|
|
2778
2778
|
s && this.initializeSessionRecoveryManager(s);
|
|
2779
2779
|
}
|
|
2780
2780
|
startTracking() {
|
|
2781
2781
|
if (this.sessionManager) {
|
|
2782
|
-
|
|
2782
|
+
i.debug("SessionHandler", "Session tracking already active");
|
|
2783
2783
|
return;
|
|
2784
2784
|
}
|
|
2785
|
-
|
|
2785
|
+
i.debug("SessionHandler", "Starting session tracking"), this.checkOrphanedSessions();
|
|
2786
2786
|
const e = async () => {
|
|
2787
2787
|
if (this.crossTabSessionManager && this.crossTabSessionManager.updateSessionActivity(), !this.get("sessionId"))
|
|
2788
2788
|
try {
|
|
2789
|
-
const
|
|
2790
|
-
this.set("sessionId",
|
|
2791
|
-
sessionId:
|
|
2792
|
-
recovered:
|
|
2789
|
+
const n = await this.createOrJoinSession();
|
|
2790
|
+
this.set("sessionId", n.sessionId), i.info("SessionHandler", "🏁 Session started", {
|
|
2791
|
+
sessionId: n.sessionId,
|
|
2792
|
+
recovered: n.recovered,
|
|
2793
2793
|
crossTabActive: !!this.crossTabSessionManager
|
|
2794
|
-
}), this.trackSession(
|
|
2795
|
-
} catch (
|
|
2796
|
-
|
|
2794
|
+
}), this.trackSession(g.SESSION_START, n.recovered), this.persistSession(n.sessionId), this.startHeartbeat();
|
|
2795
|
+
} catch (n) {
|
|
2796
|
+
i.error(
|
|
2797
2797
|
"SessionHandler",
|
|
2798
|
-
`Session creation failed: ${
|
|
2798
|
+
`Session creation failed: ${n instanceof Error ? n.message : "Unknown error"}`
|
|
2799
2799
|
), this.forceCleanupSession();
|
|
2800
2800
|
}
|
|
2801
2801
|
}, t = () => {
|
|
2802
2802
|
if (this.get("sessionId")) {
|
|
2803
2803
|
if (this.crossTabSessionManager && this.crossTabSessionManager.getEffectiveSessionTimeout() > 0) {
|
|
2804
|
-
(this.get("config")?.mode === "qa" || this.get("config")?.mode === "debug") &&
|
|
2804
|
+
(this.get("config")?.mode === "qa" || this.get("config")?.mode === "debug") && i.debug("SessionHandler", "Session kept alive by cross-tab activity");
|
|
2805
2805
|
return;
|
|
2806
2806
|
}
|
|
2807
|
-
this.sessionManager.endSessionManaged("inactivity").then((
|
|
2808
|
-
|
|
2807
|
+
this.sessionManager.endSessionManaged("inactivity").then((n) => {
|
|
2808
|
+
i.info("SessionHandler", "🛑 Session ended by inactivity", {
|
|
2809
2809
|
sessionId: this.get("sessionId"),
|
|
2810
|
-
reason:
|
|
2811
|
-
success:
|
|
2812
|
-
eventsFlushed:
|
|
2810
|
+
reason: n.reason,
|
|
2811
|
+
success: n.success,
|
|
2812
|
+
eventsFlushed: n.eventsFlushed
|
|
2813
2813
|
}), this.crossTabSessionManager && this.crossTabSessionManager.endSession("inactivity"), this.clearPersistedSession(), this.stopHeartbeat();
|
|
2814
|
-
}).catch((
|
|
2815
|
-
|
|
2814
|
+
}).catch((n) => {
|
|
2815
|
+
i.error(
|
|
2816
2816
|
"SessionHandler",
|
|
2817
|
-
`Session end failed: ${
|
|
2817
|
+
`Session end failed: ${n instanceof Error ? n.message : "Unknown error"}`
|
|
2818
2818
|
), this.forceCleanupSession();
|
|
2819
2819
|
});
|
|
2820
2820
|
}
|
|
2821
2821
|
}, s = {
|
|
2822
2822
|
enablePageUnloadHandlers: !0,
|
|
2823
2823
|
debugMode: (this.get("config")?.mode === "qa" || this.get("config")?.mode === "debug") ?? !1,
|
|
2824
|
-
syncTimeoutMs:
|
|
2825
|
-
maxRetries:
|
|
2824
|
+
syncTimeoutMs: ve.SYNC_TIMEOUT_MS,
|
|
2825
|
+
maxRetries: ve.MAX_RETRY_ATTEMPTS
|
|
2826
2826
|
};
|
|
2827
2827
|
this.sessionManager = new Ut(
|
|
2828
2828
|
e,
|
|
@@ -2830,15 +2830,15 @@ class Pt extends p {
|
|
|
2830
2830
|
this.eventManager,
|
|
2831
2831
|
this.storageManager,
|
|
2832
2832
|
s
|
|
2833
|
-
),
|
|
2833
|
+
), i.debug("SessionHandler", "Session manager initialized"), this.startInitialSession();
|
|
2834
2834
|
}
|
|
2835
2835
|
stopTracking() {
|
|
2836
|
-
if (
|
|
2836
|
+
if (i.info("SessionHandler", "Stopping session tracking"), this.sessionManager) {
|
|
2837
2837
|
if (this.get("sessionId"))
|
|
2838
2838
|
try {
|
|
2839
2839
|
this.sessionManager.endSessionSafely("manual_stop", { forceSync: !0 }), this.clearPersistedSession(), this.stopHeartbeat();
|
|
2840
2840
|
} catch (e) {
|
|
2841
|
-
|
|
2841
|
+
i.error(
|
|
2842
2842
|
"SessionHandler",
|
|
2843
2843
|
`Manual session stop failed: ${e instanceof Error ? e.message : "Unknown error"}`
|
|
2844
2844
|
), this.forceCleanupSession();
|
|
@@ -2848,26 +2848,26 @@ class Pt extends p {
|
|
|
2848
2848
|
this._crossTabSessionManager && (this._crossTabSessionManager.destroy(), this._crossTabSessionManager = null), this._isInitializingCrossTab = !1, this.recoveryManager && (this.recoveryManager.cleanupOldRecoveryAttempts(), this.recoveryManager = null);
|
|
2849
2849
|
}
|
|
2850
2850
|
initializeSessionRecoveryManager(e) {
|
|
2851
|
-
this.recoveryManager = new
|
|
2851
|
+
this.recoveryManager = new Le(this.storageManager, e, this.eventManager), i.debug("SessionHandler", "Session recovery manager initialized", { projectId: e });
|
|
2852
2852
|
}
|
|
2853
2853
|
initializeCrossTabSessionManager(e) {
|
|
2854
2854
|
const t = {
|
|
2855
2855
|
debugMode: (this.get("config")?.mode === "qa" || this.get("config")?.mode === "debug") ?? !1
|
|
2856
2856
|
}, l = {
|
|
2857
2857
|
onSessionStart: (c) => {
|
|
2858
|
-
(this.get("config")?.mode === "qa" || this.get("config")?.mode === "debug") &&
|
|
2858
|
+
(this.get("config")?.mode === "qa" || this.get("config")?.mode === "debug") && i.debug("SessionHandler", `Cross-tab session started: ${c}`), this.set("sessionId", c), this.trackSession(g.SESSION_START, !1), this.persistSession(c), this.startHeartbeat();
|
|
2859
2859
|
},
|
|
2860
2860
|
onSessionEnd: (c) => {
|
|
2861
|
-
(this.get("config")?.mode === "qa" || this.get("config")?.mode === "debug") &&
|
|
2861
|
+
(this.get("config")?.mode === "qa" || this.get("config")?.mode === "debug") && i.debug("SessionHandler", `Cross-tab session ended: ${c}`), this.clearPersistedSession(), this.trackSession(g.SESSION_END, !1, c);
|
|
2862
2862
|
},
|
|
2863
2863
|
onTabActivity: () => {
|
|
2864
|
-
(this.get("config")?.mode === "qa" || this.get("config")?.mode === "debug") &&
|
|
2864
|
+
(this.get("config")?.mode === "qa" || this.get("config")?.mode === "debug") && i.debug("SessionHandler", "Cross-tab activity detected");
|
|
2865
2865
|
},
|
|
2866
2866
|
onCrossTabConflict: () => {
|
|
2867
|
-
(this.get("config")?.mode === "qa" || this.get("config")?.mode === "debug") &&
|
|
2867
|
+
(this.get("config")?.mode === "qa" || this.get("config")?.mode === "debug") && i.warn("SessionHandler", "Cross-tab conflict detected"), this.sessionManager && this.sessionManager.trackSessionHealth("conflict");
|
|
2868
2868
|
}
|
|
2869
2869
|
};
|
|
2870
|
-
this._crossTabSessionManager = new
|
|
2870
|
+
this._crossTabSessionManager = new Ot(this.storageManager, e, t, l), i.debug("SessionHandler", "Cross-tab session manager initialized", { projectId: e });
|
|
2871
2871
|
}
|
|
2872
2872
|
async createOrJoinSession() {
|
|
2873
2873
|
if (this.crossTabSessionManager) {
|
|
@@ -2885,34 +2885,34 @@ class Pt extends p {
|
|
|
2885
2885
|
try {
|
|
2886
2886
|
this.crossTabSessionManager.endSession("orphaned_cleanup");
|
|
2887
2887
|
} catch (e) {
|
|
2888
|
-
(this.get("config")?.mode === "qa" || this.get("config")?.mode === "debug") &&
|
|
2888
|
+
(this.get("config")?.mode === "qa" || this.get("config")?.mode === "debug") && i.warn(
|
|
2889
2889
|
"SessionHandler",
|
|
2890
2890
|
`Cross-tab cleanup failed during force cleanup: ${e instanceof Error ? e.message : "Unknown error"}`
|
|
2891
2891
|
);
|
|
2892
2892
|
}
|
|
2893
2893
|
try {
|
|
2894
|
-
this.trackSession(
|
|
2894
|
+
this.trackSession(g.SESSION_END, !1, "orphaned_cleanup");
|
|
2895
2895
|
} catch (e) {
|
|
2896
|
-
(this.get("config")?.mode === "qa" || this.get("config")?.mode === "debug") &&
|
|
2896
|
+
(this.get("config")?.mode === "qa" || this.get("config")?.mode === "debug") && i.warn(
|
|
2897
2897
|
"SessionHandler",
|
|
2898
2898
|
`Session tracking failed during force cleanup: ${e instanceof Error ? e.message : "Unknown error"}`
|
|
2899
2899
|
);
|
|
2900
2900
|
}
|
|
2901
|
-
(this.get("config")?.mode === "qa" || this.get("config")?.mode === "debug") &&
|
|
2901
|
+
(this.get("config")?.mode === "qa" || this.get("config")?.mode === "debug") && i.debug("SessionHandler", "Forced session cleanup completed");
|
|
2902
2902
|
}
|
|
2903
2903
|
trackSession(e, t = !1, s) {
|
|
2904
2904
|
this.eventManager.track({
|
|
2905
2905
|
type: e,
|
|
2906
|
-
...e ===
|
|
2907
|
-
...e ===
|
|
2906
|
+
...e === g.SESSION_START && t && { session_start_recovered: t },
|
|
2907
|
+
...e === g.SESSION_END && { session_end_reason: s ?? "orphaned_cleanup" }
|
|
2908
2908
|
});
|
|
2909
2909
|
}
|
|
2910
2910
|
startInitialSession() {
|
|
2911
2911
|
if (this.get("sessionId")) {
|
|
2912
|
-
|
|
2912
|
+
i.debug("SessionHandler", "Session already exists, skipping initial session creation");
|
|
2913
2913
|
return;
|
|
2914
2914
|
}
|
|
2915
|
-
if (
|
|
2915
|
+
if (i.debug("SessionHandler", "Starting initial session"), this.crossTabSessionManager) {
|
|
2916
2916
|
const t = this.crossTabSessionManager.getSessionId();
|
|
2917
2917
|
if (t) {
|
|
2918
2918
|
this.set("sessionId", t), this.persistSession(t), this.startHeartbeat();
|
|
@@ -2920,16 +2920,16 @@ class Pt extends p {
|
|
|
2920
2920
|
}
|
|
2921
2921
|
return;
|
|
2922
2922
|
}
|
|
2923
|
-
|
|
2923
|
+
i.debug("SessionHandler", "Starting regular session (no cross-tab)");
|
|
2924
2924
|
const e = this.sessionManager.startSession();
|
|
2925
|
-
this.set("sessionId", e.sessionId), this.trackSession(
|
|
2925
|
+
this.set("sessionId", e.sessionId), this.trackSession(g.SESSION_START, e.recovered), this.persistSession(e.sessionId), this.startHeartbeat();
|
|
2926
2926
|
}
|
|
2927
2927
|
checkOrphanedSessions() {
|
|
2928
2928
|
const e = this.storageManager.getItem(this.sessionStorageKey);
|
|
2929
2929
|
if (e)
|
|
2930
2930
|
try {
|
|
2931
|
-
const t = JSON.parse(e),
|
|
2932
|
-
if (
|
|
2931
|
+
const t = JSON.parse(e), n = Date.now() - t.lastHeartbeat, a = this.get("config")?.sessionTimeout ?? R;
|
|
2932
|
+
if (n > a) {
|
|
2933
2933
|
const o = this.recoveryManager?.hasRecoverableSession();
|
|
2934
2934
|
if (o && this.recoveryManager) {
|
|
2935
2935
|
const l = {
|
|
@@ -2943,9 +2943,9 @@ class Pt extends p {
|
|
|
2943
2943
|
pageUrl: this.get("pageUrl")
|
|
2944
2944
|
}
|
|
2945
2945
|
};
|
|
2946
|
-
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") && i.debug("SessionHandler", `Orphaned session stored for recovery: ${t.sessionId}`);
|
|
2947
2947
|
}
|
|
2948
|
-
this.trackSession(
|
|
2948
|
+
this.trackSession(g.SESSION_END), this.clearPersistedSession(), (this.get("config")?.mode === "qa" || this.get("config")?.mode === "debug") && i.debug(
|
|
2949
2949
|
"SessionHandler",
|
|
2950
2950
|
`Orphaned session ended: ${t.sessionId}, recovery available: ${o}`
|
|
2951
2951
|
);
|
|
@@ -2975,13 +2975,13 @@ class Pt extends p {
|
|
|
2975
2975
|
} catch {
|
|
2976
2976
|
this.clearPersistedSession();
|
|
2977
2977
|
}
|
|
2978
|
-
},
|
|
2978
|
+
}, $e);
|
|
2979
2979
|
}
|
|
2980
2980
|
stopHeartbeat() {
|
|
2981
2981
|
this.heartbeatInterval && (clearInterval(this.heartbeatInterval), this.heartbeatInterval = null);
|
|
2982
2982
|
}
|
|
2983
2983
|
}
|
|
2984
|
-
class
|
|
2984
|
+
class xt extends p {
|
|
2985
2985
|
eventManager;
|
|
2986
2986
|
onTrack;
|
|
2987
2987
|
originalPushState;
|
|
@@ -2990,10 +2990,10 @@ class Dt extends p {
|
|
|
2990
2990
|
super(), this.eventManager = e, this.onTrack = t;
|
|
2991
2991
|
}
|
|
2992
2992
|
startTracking() {
|
|
2993
|
-
|
|
2993
|
+
i.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");
|
|
2994
2994
|
}
|
|
2995
2995
|
stopTracking() {
|
|
2996
|
-
|
|
2996
|
+
i.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);
|
|
2997
2997
|
}
|
|
2998
2998
|
patchHistory(e) {
|
|
2999
2999
|
e === "pushState" && !this.originalPushState ? this.originalPushState = window.history.pushState : e === "replaceState" && !this.originalReplaceState && (this.originalReplaceState = window.history.replaceState);
|
|
@@ -3003,11 +3003,11 @@ class Dt extends p {
|
|
|
3003
3003
|
};
|
|
3004
3004
|
}
|
|
3005
3005
|
trackCurrentPage = () => {
|
|
3006
|
-
const e = window.location.href, t =
|
|
3006
|
+
const e = window.location.href, t = ie(e, this.get("config").sensitiveQueryParams);
|
|
3007
3007
|
if (this.get("pageUrl") !== t) {
|
|
3008
3008
|
const s = this.get("pageUrl");
|
|
3009
|
-
|
|
3010
|
-
type:
|
|
3009
|
+
i.debug("PageViewHandler", "Page navigation detected", { from: s, to: t }), this.set("pageUrl", t), this.eventManager.track({
|
|
3010
|
+
type: g.PAGE_VIEW,
|
|
3011
3011
|
page_url: this.get("pageUrl"),
|
|
3012
3012
|
from_page_url: s,
|
|
3013
3013
|
...this.extractPageViewData() && { page_view: this.extractPageViewData() }
|
|
@@ -3016,7 +3016,7 @@ class Dt extends p {
|
|
|
3016
3016
|
};
|
|
3017
3017
|
trackInitialPageView() {
|
|
3018
3018
|
this.eventManager.track({
|
|
3019
|
-
type:
|
|
3019
|
+
type: g.PAGE_VIEW,
|
|
3020
3020
|
page_url: this.get("pageUrl"),
|
|
3021
3021
|
...this.extractPageViewData() && { page_view: this.extractPageViewData() }
|
|
3022
3022
|
}), this.onTrack();
|
|
@@ -3032,7 +3032,7 @@ class Dt extends p {
|
|
|
3032
3032
|
return Object.values(t).some((s) => !!s) ? t : void 0;
|
|
3033
3033
|
}
|
|
3034
3034
|
}
|
|
3035
|
-
class
|
|
3035
|
+
class Ft extends p {
|
|
3036
3036
|
eventManager;
|
|
3037
3037
|
clickHandler;
|
|
3038
3038
|
constructor(e) {
|
|
@@ -3040,37 +3040,37 @@ class xt extends p {
|
|
|
3040
3040
|
}
|
|
3041
3041
|
startTracking() {
|
|
3042
3042
|
if (this.clickHandler) {
|
|
3043
|
-
|
|
3043
|
+
i.debug("ClickHandler", "Click tracking already active");
|
|
3044
3044
|
return;
|
|
3045
3045
|
}
|
|
3046
|
-
|
|
3047
|
-
const t = e, s = t.target,
|
|
3048
|
-
if (!
|
|
3049
|
-
|
|
3046
|
+
i.debug("ClickHandler", "Starting click tracking"), this.clickHandler = (e) => {
|
|
3047
|
+
const t = e, s = t.target, n = s instanceof HTMLElement ? s : s instanceof Node && s.parentElement instanceof HTMLElement ? s.parentElement : null;
|
|
3048
|
+
if (!n) {
|
|
3049
|
+
i.warn("ClickHandler", "Click target not found or not an element");
|
|
3050
3050
|
return;
|
|
3051
3051
|
}
|
|
3052
|
-
|
|
3053
|
-
tagName:
|
|
3054
|
-
className:
|
|
3055
|
-
textContent:
|
|
3052
|
+
i.info("ClickHandler", "🖱️ Click detected on element", {
|
|
3053
|
+
tagName: n.tagName,
|
|
3054
|
+
className: n.className || "none",
|
|
3055
|
+
textContent: n.textContent?.slice(0, 50) ?? "empty"
|
|
3056
3056
|
});
|
|
3057
|
-
const a = this.findTrackingElement(
|
|
3057
|
+
const a = this.findTrackingElement(n), o = this.getRelevantClickElement(n), l = this.calculateClickCoordinates(t, n);
|
|
3058
3058
|
if (a) {
|
|
3059
3059
|
const d = this.extractTrackingData(a);
|
|
3060
3060
|
if (d) {
|
|
3061
|
-
const
|
|
3061
|
+
const h = this.createCustomEventData(d);
|
|
3062
3062
|
this.eventManager.track({
|
|
3063
|
-
type:
|
|
3063
|
+
type: g.CUSTOM,
|
|
3064
3064
|
custom_event: {
|
|
3065
|
-
name:
|
|
3066
|
-
...
|
|
3065
|
+
name: h.name,
|
|
3066
|
+
...h.value && { metadata: { value: h.value } }
|
|
3067
3067
|
}
|
|
3068
3068
|
});
|
|
3069
3069
|
}
|
|
3070
3070
|
}
|
|
3071
|
-
const c = this.generateClickData(
|
|
3071
|
+
const c = this.generateClickData(n, o, l);
|
|
3072
3072
|
this.eventManager.track({
|
|
3073
|
-
type:
|
|
3073
|
+
type: g.CLICK,
|
|
3074
3074
|
click_data: c
|
|
3075
3075
|
});
|
|
3076
3076
|
}, window.addEventListener("click", this.clickHandler, !0);
|
|
@@ -3082,24 +3082,24 @@ class xt extends p {
|
|
|
3082
3082
|
return e.hasAttribute(`${z}-name`) ? e : e.closest(`[${z}-name]`) || void 0;
|
|
3083
3083
|
}
|
|
3084
3084
|
getRelevantClickElement(e) {
|
|
3085
|
-
for (const t of
|
|
3085
|
+
for (const t of me)
|
|
3086
3086
|
try {
|
|
3087
3087
|
if (e.matches(t))
|
|
3088
3088
|
return e;
|
|
3089
3089
|
} catch (s) {
|
|
3090
|
-
|
|
3090
|
+
i.warn("ClickHandler", "Invalid selector in interactive elements check", {
|
|
3091
3091
|
selector: t,
|
|
3092
3092
|
error: s instanceof Error ? s.message : "Unknown error"
|
|
3093
3093
|
});
|
|
3094
3094
|
continue;
|
|
3095
3095
|
}
|
|
3096
|
-
for (const t of
|
|
3096
|
+
for (const t of me)
|
|
3097
3097
|
try {
|
|
3098
3098
|
const s = e.closest(t);
|
|
3099
3099
|
if (s)
|
|
3100
3100
|
return s;
|
|
3101
3101
|
} catch (s) {
|
|
3102
|
-
|
|
3102
|
+
i.warn("ClickHandler", "Invalid selector in parent element search", {
|
|
3103
3103
|
selector: t,
|
|
3104
3104
|
error: s instanceof Error ? s.message : "Unknown error"
|
|
3105
3105
|
});
|
|
@@ -3108,8 +3108,8 @@ class xt extends p {
|
|
|
3108
3108
|
return e;
|
|
3109
3109
|
}
|
|
3110
3110
|
calculateClickCoordinates(e, t) {
|
|
3111
|
-
const s = t.getBoundingClientRect(),
|
|
3112
|
-
return { x:
|
|
3111
|
+
const s = t.getBoundingClientRect(), n = e.clientX, a = e.clientY, o = s.width > 0 ? Math.max(0, Math.min(1, Number(((n - s.left) / s.width).toFixed(3)))) : 0, l = s.height > 0 ? Math.max(0, Math.min(1, Number(((a - s.top) / s.height).toFixed(3)))) : 0;
|
|
3112
|
+
return { x: n, y: a, relativeX: o, relativeY: l };
|
|
3113
3113
|
}
|
|
3114
3114
|
extractTrackingData(e) {
|
|
3115
3115
|
const t = e.getAttribute(`${z}-name`), s = e.getAttribute(`${z}-value`);
|
|
@@ -3121,38 +3121,38 @@ class xt extends p {
|
|
|
3121
3121
|
};
|
|
3122
3122
|
}
|
|
3123
3123
|
generateClickData(e, t, s) {
|
|
3124
|
-
const { x:
|
|
3124
|
+
const { x: n, y: a, relativeX: o, relativeY: l } = s, c = this.getRelevantText(e, t), d = this.extractElementAttributes(t), h = t.getAttribute("href"), u = t.getAttribute("title"), v = t.getAttribute("alt"), y = t.getAttribute("role"), A = t.getAttribute("aria-label"), H = typeof t.className == "string" ? t.className : String(t.className);
|
|
3125
3125
|
return {
|
|
3126
|
-
x:
|
|
3126
|
+
x: n,
|
|
3127
3127
|
y: a,
|
|
3128
3128
|
relativeX: o,
|
|
3129
3129
|
relativeY: l,
|
|
3130
3130
|
tag: t.tagName.toLowerCase(),
|
|
3131
3131
|
...t.id && { id: t.id },
|
|
3132
|
-
...t.className && { class:
|
|
3132
|
+
...t.className && { class: H },
|
|
3133
3133
|
...c && { text: c },
|
|
3134
|
-
...
|
|
3135
|
-
...
|
|
3136
|
-
...
|
|
3137
|
-
...
|
|
3134
|
+
...h && { href: h },
|
|
3135
|
+
...u && { title: u },
|
|
3136
|
+
...v && { alt: v },
|
|
3137
|
+
...y && { role: y },
|
|
3138
3138
|
...A && { ariaLabel: A },
|
|
3139
3139
|
...Object.keys(d).length > 0 && { dataAttributes: d }
|
|
3140
3140
|
};
|
|
3141
3141
|
}
|
|
3142
3142
|
getRelevantText(e, t) {
|
|
3143
|
-
const s = ["main", "section", "article", "body", "html", "header", "footer", "aside", "nav"],
|
|
3144
|
-
if (!
|
|
3143
|
+
const s = ["main", "section", "article", "body", "html", "header", "footer", "aside", "nav"], n = e.textContent?.trim() ?? "", a = t.textContent?.trim() ?? "";
|
|
3144
|
+
if (!n && !a)
|
|
3145
3145
|
return "";
|
|
3146
|
-
if (
|
|
3147
|
-
return
|
|
3148
|
-
const o = s.includes(t.tagName.toLowerCase()), l = a.length >
|
|
3149
|
-
return o && l ?
|
|
3146
|
+
if (n && n.length <= C)
|
|
3147
|
+
return n;
|
|
3148
|
+
const o = s.includes(t.tagName.toLowerCase()), l = a.length > C * 2;
|
|
3149
|
+
return o && l ? n && n.length <= C ? n : "" : a.length <= C ? a : n && n.length < a.length * 0.1 ? n.length <= C ? n : n.slice(0, C - 3) + "..." : a.slice(0, C - 3) + "...";
|
|
3150
3150
|
}
|
|
3151
3151
|
extractElementAttributes(e) {
|
|
3152
3152
|
const t = ["id", "class", "data-testid", "aria-label", "title", "href", "type", "name"], s = {};
|
|
3153
|
-
for (const
|
|
3154
|
-
const a = e.getAttribute(
|
|
3155
|
-
a && (s[
|
|
3153
|
+
for (const n of t) {
|
|
3154
|
+
const a = e.getAttribute(n);
|
|
3155
|
+
a && (s[n] = a);
|
|
3156
3156
|
}
|
|
3157
3157
|
return s;
|
|
3158
3158
|
}
|
|
@@ -3163,28 +3163,38 @@ class xt extends p {
|
|
|
3163
3163
|
};
|
|
3164
3164
|
}
|
|
3165
3165
|
}
|
|
3166
|
-
class
|
|
3166
|
+
class zt extends p {
|
|
3167
3167
|
eventManager;
|
|
3168
3168
|
containers = [];
|
|
3169
|
+
pendingSelectors = [];
|
|
3170
|
+
mutationObserver = null;
|
|
3171
|
+
windowFallbackNeeded = !1;
|
|
3169
3172
|
constructor(e) {
|
|
3170
3173
|
super(), this.eventManager = e;
|
|
3171
3174
|
}
|
|
3172
3175
|
startTracking() {
|
|
3173
3176
|
const e = this.get("config").scrollContainerSelectors, t = Array.isArray(e) ? e : typeof e == "string" ? [e] : [];
|
|
3174
|
-
|
|
3175
|
-
|
|
3176
|
-
|
|
3177
|
-
|
|
3178
|
-
|
|
3177
|
+
if (i.debug("ScrollHandler", "Starting scroll tracking", { selectorsCount: t.length }), t.length === 0) {
|
|
3178
|
+
this.setupScrollContainer(window);
|
|
3179
|
+
return;
|
|
3180
|
+
}
|
|
3181
|
+
const s = [], n = [];
|
|
3182
|
+
for (const a of t) {
|
|
3183
|
+
const o = this.safeQuerySelector(a);
|
|
3184
|
+
o instanceof HTMLElement ? s.push(o) : o === null && n.push(a);
|
|
3185
|
+
}
|
|
3186
|
+
for (const a of s)
|
|
3187
|
+
this.setupScrollContainer(a);
|
|
3188
|
+
n.length > 0 ? (this.windowFallbackNeeded = !0, this.setupPendingSelectors(n)) : this.containers.length === 0 && this.setupScrollContainer(window);
|
|
3179
3189
|
}
|
|
3180
3190
|
stopTracking() {
|
|
3181
|
-
|
|
3191
|
+
i.debug("ScrollHandler", "Stopping scroll tracking", { containersCount: this.containers.length });
|
|
3182
3192
|
for (const e of this.containers)
|
|
3183
3193
|
e.debounceTimer && clearTimeout(e.debounceTimer), e.element instanceof Window ? window.removeEventListener("scroll", e.listener) : e.element.removeEventListener("scroll", e.listener);
|
|
3184
|
-
this.containers.length = 0;
|
|
3194
|
+
this.containers.length = 0, this.mutationObserver && (this.mutationObserver.disconnect(), this.mutationObserver = null), this.pendingSelectors.length = 0;
|
|
3185
3195
|
}
|
|
3186
3196
|
setupScrollContainer(e) {
|
|
3187
|
-
if (
|
|
3197
|
+
if (this.containers.some((n) => n.element === e))
|
|
3188
3198
|
return;
|
|
3189
3199
|
const t = {
|
|
3190
3200
|
element: e,
|
|
@@ -3198,21 +3208,31 @@ class Ot extends p {
|
|
|
3198
3208
|
return;
|
|
3199
3209
|
}
|
|
3200
3210
|
t.debounceTimer && clearTimeout(t.debounceTimer), t.debounceTimer = window.setTimeout(() => {
|
|
3201
|
-
const
|
|
3202
|
-
|
|
3203
|
-
type:
|
|
3204
|
-
scroll_data:
|
|
3211
|
+
const n = this.calculateScrollData(t);
|
|
3212
|
+
n && this.eventManager.track({
|
|
3213
|
+
type: g.SCROLL,
|
|
3214
|
+
scroll_data: n
|
|
3205
3215
|
}), t.debounceTimer = null;
|
|
3206
|
-
},
|
|
3216
|
+
}, Ae);
|
|
3207
3217
|
};
|
|
3208
3218
|
t.listener = s, this.containers.push(t), e instanceof Window ? window.addEventListener("scroll", s, { passive: !0 }) : e.addEventListener("scroll", s, { passive: !0 });
|
|
3209
3219
|
}
|
|
3210
3220
|
calculateScrollData(e) {
|
|
3211
|
-
const { element: t, lastScrollPos: s } = e,
|
|
3212
|
-
if (t
|
|
3213
|
-
|
|
3214
|
-
|
|
3215
|
-
|
|
3221
|
+
const { element: t, lastScrollPos: s } = e, n = this.getScrollTop(t), a = this.getViewportHeight(t), o = this.getScrollHeight(t), l = this.getViewportWidth(t), c = this.getScrollWidth(t);
|
|
3222
|
+
if (t instanceof HTMLElement) {
|
|
3223
|
+
if (!this.hasScrollableOverflow(t))
|
|
3224
|
+
return null;
|
|
3225
|
+
const v = o > a, y = c > l;
|
|
3226
|
+
if (!v && !y)
|
|
3227
|
+
return null;
|
|
3228
|
+
}
|
|
3229
|
+
if (t instanceof Window) {
|
|
3230
|
+
const v = o > a, y = c > l;
|
|
3231
|
+
if (!v && !y)
|
|
3232
|
+
return null;
|
|
3233
|
+
}
|
|
3234
|
+
const d = n > s ? j.DOWN : j.UP, h = o > a ? Math.min(100, Math.max(0, Math.floor(n / (o - a) * 100))) : 0;
|
|
3235
|
+
return Math.abs(n - s) < Pe ? null : (e.lastScrollPos = n, { depth: h, direction: d });
|
|
3216
3236
|
}
|
|
3217
3237
|
getScrollTop(e) {
|
|
3218
3238
|
return e instanceof Window ? window.scrollY : e.scrollTop;
|
|
@@ -3223,22 +3243,73 @@ class Ot extends p {
|
|
|
3223
3243
|
getScrollHeight(e) {
|
|
3224
3244
|
return e instanceof Window ? document.documentElement.scrollHeight : e.scrollHeight;
|
|
3225
3245
|
}
|
|
3226
|
-
|
|
3227
|
-
|
|
3228
|
-
|
|
3246
|
+
getViewportWidth(e) {
|
|
3247
|
+
return e instanceof Window ? window.innerWidth : e.clientWidth;
|
|
3248
|
+
}
|
|
3249
|
+
getScrollWidth(e) {
|
|
3250
|
+
return e instanceof Window ? document.documentElement.scrollWidth : e.scrollWidth;
|
|
3251
|
+
}
|
|
3252
|
+
hasScrollableOverflow(e) {
|
|
3253
|
+
const t = getComputedStyle(e);
|
|
3254
|
+
return t.overflowY === "auto" || t.overflowY === "scroll" || t.overflowX === "auto" || t.overflowX === "scroll" || t.overflow === "auto" || t.overflow === "scroll";
|
|
3229
3255
|
}
|
|
3230
3256
|
safeQuerySelector(e) {
|
|
3231
3257
|
try {
|
|
3232
3258
|
return document.querySelector(e);
|
|
3233
3259
|
} catch (t) {
|
|
3234
|
-
return
|
|
3260
|
+
return i.clientWarn("ScrollHandler", "Invalid CSS selector", {
|
|
3235
3261
|
selector: e,
|
|
3236
3262
|
error: t instanceof Error ? t.message : "Unknown error"
|
|
3237
3263
|
}), null;
|
|
3238
3264
|
}
|
|
3239
3265
|
}
|
|
3266
|
+
setupPendingSelectors(e) {
|
|
3267
|
+
i.debug("ScrollHandler", "Setting up pending selectors with retry logic", {
|
|
3268
|
+
selectors: e,
|
|
3269
|
+
maxRetries: X
|
|
3270
|
+
});
|
|
3271
|
+
for (const t of e)
|
|
3272
|
+
this.pendingSelectors.push({ selector: t, retryCount: 0 });
|
|
3273
|
+
this.startMutationObserver(), this.retryPendingSelectors();
|
|
3274
|
+
}
|
|
3275
|
+
startMutationObserver() {
|
|
3276
|
+
this.mutationObserver || (this.mutationObserver = new MutationObserver(() => {
|
|
3277
|
+
this.checkPendingSelectors();
|
|
3278
|
+
}), this.mutationObserver.observe(document.body, {
|
|
3279
|
+
childList: !0,
|
|
3280
|
+
subtree: !0
|
|
3281
|
+
}), i.debug("ScrollHandler", "MutationObserver started for pending selectors"));
|
|
3282
|
+
}
|
|
3283
|
+
checkPendingSelectors() {
|
|
3284
|
+
const e = [];
|
|
3285
|
+
for (const t of this.pendingSelectors) {
|
|
3286
|
+
const s = this.safeQuerySelector(t.selector);
|
|
3287
|
+
s instanceof HTMLElement ? (i.debug("ScrollHandler", "Found pending selector", { selector: t.selector }), this.setupScrollContainer(s)) : e.push(t);
|
|
3288
|
+
}
|
|
3289
|
+
this.pendingSelectors.length = 0, this.pendingSelectors.push(...e), this.pendingSelectors.length === 0 && this.mutationObserver && (this.mutationObserver.disconnect(), this.mutationObserver = null, i.debug("ScrollHandler", "All pending selectors resolved, MutationObserver stopped"));
|
|
3290
|
+
}
|
|
3291
|
+
retryPendingSelectors() {
|
|
3292
|
+
setTimeout(() => {
|
|
3293
|
+
if (this.pendingSelectors.length === 0) return;
|
|
3294
|
+
const e = [];
|
|
3295
|
+
for (const t of this.pendingSelectors) {
|
|
3296
|
+
t.retryCount++;
|
|
3297
|
+
const s = this.safeQuerySelector(t.selector);
|
|
3298
|
+
s instanceof HTMLElement ? (i.debug("ScrollHandler", "Retry found pending selector", {
|
|
3299
|
+
selector: t.selector,
|
|
3300
|
+
retryCount: t.retryCount
|
|
3301
|
+
}), this.setupScrollContainer(s)) : t.retryCount < X ? e.push(t) : i.clientWarn("ScrollHandler", "Selector not found after max retries", {
|
|
3302
|
+
selector: t.selector,
|
|
3303
|
+
maxRetries: X
|
|
3304
|
+
});
|
|
3305
|
+
}
|
|
3306
|
+
this.pendingSelectors.length = 0, this.pendingSelectors.push(...e), this.pendingSelectors.length > 0 ? this.retryPendingSelectors() : (this.mutationObserver && (this.mutationObserver.disconnect(), this.mutationObserver = null), this.windowFallbackNeeded && this.containers.length === 0 && (i.debug("ScrollHandler", "No scroll containers found, using window fallback"), this.setupScrollContainer(window)), i.debug("ScrollHandler", "All pending selectors resolved or timed out", {
|
|
3307
|
+
containersCount: this.containers.length
|
|
3308
|
+
}));
|
|
3309
|
+
}, Ve);
|
|
3310
|
+
}
|
|
3240
3311
|
}
|
|
3241
|
-
class
|
|
3312
|
+
class Vt extends p {
|
|
3242
3313
|
isInitialized = !1;
|
|
3243
3314
|
constructor() {
|
|
3244
3315
|
super();
|
|
@@ -3248,7 +3319,7 @@ class Ft extends p {
|
|
|
3248
3319
|
return;
|
|
3249
3320
|
const e = this.get("config").integrations?.googleAnalytics?.measurementId;
|
|
3250
3321
|
if (!e?.trim()) {
|
|
3251
|
-
|
|
3322
|
+
i.clientWarn("GoogleAnalytics", "Google Analytics integration disabled - measurementId not configured", {
|
|
3252
3323
|
hasIntegrations: !!this.get("config").integrations,
|
|
3253
3324
|
hasGoogleAnalytics: !!this.get("config").integrations?.googleAnalytics
|
|
3254
3325
|
});
|
|
@@ -3256,22 +3327,22 @@ class Ft extends p {
|
|
|
3256
3327
|
}
|
|
3257
3328
|
const t = this.get("userId");
|
|
3258
3329
|
if (!t?.trim()) {
|
|
3259
|
-
|
|
3330
|
+
i.warn("GoogleAnalytics", "Google Analytics initialization delayed - userId not available", {
|
|
3260
3331
|
measurementId: e.substring(0, 8) + "..."
|
|
3261
3332
|
});
|
|
3262
3333
|
return;
|
|
3263
3334
|
}
|
|
3264
3335
|
try {
|
|
3265
3336
|
if (this.isScriptAlreadyLoaded()) {
|
|
3266
|
-
|
|
3337
|
+
i.info("GoogleAnalytics", "Google Analytics script already loaded", { measurementId: e }), this.isInitialized = !0;
|
|
3267
3338
|
return;
|
|
3268
3339
|
}
|
|
3269
|
-
await this.loadScript(e), this.configureGtag(e, t), this.isInitialized = !0,
|
|
3340
|
+
await this.loadScript(e), this.configureGtag(e, t), this.isInitialized = !0, i.info("GoogleAnalytics", "Google Analytics integration initialized successfully", {
|
|
3270
3341
|
measurementId: e,
|
|
3271
3342
|
userId: t
|
|
3272
3343
|
});
|
|
3273
3344
|
} catch (s) {
|
|
3274
|
-
|
|
3345
|
+
i.error("GoogleAnalytics", "Google Analytics initialization failed", {
|
|
3275
3346
|
error: s instanceof Error ? s.message : "Unknown error",
|
|
3276
3347
|
measurementId: e,
|
|
3277
3348
|
userId: t
|
|
@@ -3280,7 +3351,7 @@ class Ft extends p {
|
|
|
3280
3351
|
}
|
|
3281
3352
|
trackEvent(e, t) {
|
|
3282
3353
|
if (!e?.trim()) {
|
|
3283
|
-
|
|
3354
|
+
i.clientWarn("GoogleAnalytics", "Event tracking skipped - invalid event name provided", {
|
|
3284
3355
|
eventName: e,
|
|
3285
3356
|
hasMetadata: !!t && Object.keys(t).length > 0
|
|
3286
3357
|
});
|
|
@@ -3288,7 +3359,7 @@ class Ft extends p {
|
|
|
3288
3359
|
}
|
|
3289
3360
|
if (this.isInitialized) {
|
|
3290
3361
|
if (typeof window.gtag != "function") {
|
|
3291
|
-
|
|
3362
|
+
i.warn("GoogleAnalytics", "Event tracking failed - gtag function not available", {
|
|
3292
3363
|
eventName: e,
|
|
3293
3364
|
hasGtag: typeof window.gtag,
|
|
3294
3365
|
hasDataLayer: Array.isArray(window.dataLayer)
|
|
@@ -3298,7 +3369,7 @@ class Ft extends p {
|
|
|
3298
3369
|
try {
|
|
3299
3370
|
window.gtag("event", e, t);
|
|
3300
3371
|
} catch (s) {
|
|
3301
|
-
|
|
3372
|
+
i.error("GoogleAnalytics", "Event tracking failed", {
|
|
3302
3373
|
eventName: e,
|
|
3303
3374
|
error: s instanceof Error ? s.message : "Unknown error",
|
|
3304
3375
|
metadataKeys: Object.keys(t || {})
|
|
@@ -3309,13 +3380,13 @@ class Ft extends p {
|
|
|
3309
3380
|
cleanup() {
|
|
3310
3381
|
this.isInitialized = !1;
|
|
3311
3382
|
const e = document.getElementById("tracelog-ga-script");
|
|
3312
|
-
e && e.remove(),
|
|
3383
|
+
e && e.remove(), i.info("GoogleAnalytics", "Google Analytics integration cleanup completed");
|
|
3313
3384
|
}
|
|
3314
3385
|
isScriptAlreadyLoaded() {
|
|
3315
3386
|
if (document.getElementById("tracelog-ga-script"))
|
|
3316
3387
|
return !0;
|
|
3317
3388
|
const t = document.querySelector('script[src*="googletagmanager.com/gtag/js"]');
|
|
3318
|
-
return t ? (
|
|
3389
|
+
return t ? (i.clientWarn("GoogleAnalytics", "Google Analytics script already loaded from external source", {
|
|
3319
3390
|
scriptSrc: t.getAttribute("src"),
|
|
3320
3391
|
hasGtag: typeof window.gtag == "function"
|
|
3321
3392
|
}), !0) : !1;
|
|
@@ -3323,20 +3394,20 @@ class Ft extends p {
|
|
|
3323
3394
|
async loadScript(e) {
|
|
3324
3395
|
return new Promise((t, s) => {
|
|
3325
3396
|
try {
|
|
3326
|
-
const
|
|
3327
|
-
|
|
3397
|
+
const n = document.createElement("script");
|
|
3398
|
+
n.id = "tracelog-ga-script", n.async = !0, n.src = `https://www.googletagmanager.com/gtag/js?id=${e}`, n.onload = () => {
|
|
3328
3399
|
t();
|
|
3329
|
-
},
|
|
3400
|
+
}, n.onerror = () => {
|
|
3330
3401
|
const a = new Error("Failed to load Google Analytics script");
|
|
3331
|
-
|
|
3402
|
+
i.error("GoogleAnalytics", "Google Analytics script load failed", {
|
|
3332
3403
|
measurementId: e,
|
|
3333
3404
|
error: a.message,
|
|
3334
|
-
scriptSrc:
|
|
3405
|
+
scriptSrc: n.src
|
|
3335
3406
|
}), s(a);
|
|
3336
|
-
}, document.head.appendChild(
|
|
3337
|
-
} catch (
|
|
3338
|
-
const a =
|
|
3339
|
-
|
|
3407
|
+
}, document.head.appendChild(n);
|
|
3408
|
+
} catch (n) {
|
|
3409
|
+
const a = n instanceof Error ? n : new Error(String(n));
|
|
3410
|
+
i.error("GoogleAnalytics", "Error creating Google Analytics script", {
|
|
3340
3411
|
measurementId: e,
|
|
3341
3412
|
error: a.message
|
|
3342
3413
|
}), s(a);
|
|
@@ -3355,7 +3426,7 @@ class Ft extends p {
|
|
|
3355
3426
|
});
|
|
3356
3427
|
`, document.head.appendChild(s);
|
|
3357
3428
|
} catch (s) {
|
|
3358
|
-
throw
|
|
3429
|
+
throw i.error("GoogleAnalytics", "Failed to configure Google Analytics", {
|
|
3359
3430
|
measurementId: e,
|
|
3360
3431
|
userId: t,
|
|
3361
3432
|
error: s instanceof Error ? s.message : "Unknown error"
|
|
@@ -3363,12 +3434,12 @@ class Ft extends p {
|
|
|
3363
3434
|
}
|
|
3364
3435
|
}
|
|
3365
3436
|
}
|
|
3366
|
-
class
|
|
3437
|
+
class $t {
|
|
3367
3438
|
storage = null;
|
|
3368
3439
|
fallbackStorage = /* @__PURE__ */ new Map();
|
|
3369
3440
|
storageAvailable = !1;
|
|
3370
3441
|
constructor() {
|
|
3371
|
-
this.storage = this.init(), this.storageAvailable = this.storage !== null, this.storageAvailable ||
|
|
3442
|
+
this.storage = this.init(), this.storageAvailable = this.storage !== null, this.storageAvailable || i.warn("StorageManager", "localStorage not available, using memory fallback");
|
|
3372
3443
|
}
|
|
3373
3444
|
getItem(e) {
|
|
3374
3445
|
if (!this.storageAvailable)
|
|
@@ -3376,7 +3447,7 @@ class zt {
|
|
|
3376
3447
|
try {
|
|
3377
3448
|
return this.storage ? this.storage.getItem(e) : this.fallbackStorage.get(e) ?? null;
|
|
3378
3449
|
} catch (t) {
|
|
3379
|
-
return
|
|
3450
|
+
return i.warn("StorageManager", "Storage getItem failed, using memory fallback", { key: e, error: t }), this.storageAvailable = !1, this.fallbackStorage.get(e) ?? null;
|
|
3380
3451
|
}
|
|
3381
3452
|
}
|
|
3382
3453
|
setItem(e, t) {
|
|
@@ -3391,7 +3462,7 @@ class zt {
|
|
|
3391
3462
|
}
|
|
3392
3463
|
this.fallbackStorage.set(e, t);
|
|
3393
3464
|
} catch (s) {
|
|
3394
|
-
|
|
3465
|
+
i.warn("StorageManager", "Storage setItem failed, using memory fallback", { key: e, error: s }), this.storageAvailable = !1, this.fallbackStorage.set(e, t);
|
|
3395
3466
|
}
|
|
3396
3467
|
}
|
|
3397
3468
|
removeItem(e) {
|
|
@@ -3406,7 +3477,7 @@ class zt {
|
|
|
3406
3477
|
}
|
|
3407
3478
|
this.fallbackStorage.delete(e);
|
|
3408
3479
|
} catch (t) {
|
|
3409
|
-
|
|
3480
|
+
i.warn("StorageManager", "Storage removeItem failed, using memory fallback", { key: e, error: t }), this.storageAvailable = !1, this.fallbackStorage.delete(e);
|
|
3410
3481
|
}
|
|
3411
3482
|
}
|
|
3412
3483
|
init() {
|
|
@@ -3418,7 +3489,7 @@ class zt {
|
|
|
3418
3489
|
}
|
|
3419
3490
|
}
|
|
3420
3491
|
}
|
|
3421
|
-
class
|
|
3492
|
+
class jt extends p {
|
|
3422
3493
|
eventManager;
|
|
3423
3494
|
reportedByNav = /* @__PURE__ */ new Map();
|
|
3424
3495
|
observers = [];
|
|
@@ -3427,19 +3498,19 @@ class Vt extends p {
|
|
|
3427
3498
|
super(), this.eventManager = e;
|
|
3428
3499
|
}
|
|
3429
3500
|
async startTracking() {
|
|
3430
|
-
|
|
3501
|
+
i.debug("PerformanceHandler", "Starting performance tracking"), await this.initWebVitals(), this.observeLongTasks(), this.reportTTFB();
|
|
3431
3502
|
}
|
|
3432
3503
|
stopTracking() {
|
|
3433
|
-
|
|
3504
|
+
i.debug("PerformanceHandler", "Stopping performance tracking", { observersCount: this.observers.length }), this.observers.forEach((e, t) => {
|
|
3434
3505
|
try {
|
|
3435
3506
|
e.disconnect();
|
|
3436
3507
|
} catch (s) {
|
|
3437
|
-
|
|
3508
|
+
i.warn("PerformanceHandler", "Failed to disconnect performance observer", {
|
|
3438
3509
|
error: s instanceof Error ? s.message : "Unknown error",
|
|
3439
3510
|
observerIndex: t
|
|
3440
3511
|
});
|
|
3441
3512
|
}
|
|
3442
|
-
}), this.observers.length = 0, this.reportedByNav.clear(),
|
|
3513
|
+
}), this.observers.length = 0, this.reportedByNav.clear(), i.debug("PerformanceHandler", "Performance tracking cleanup completed", {
|
|
3443
3514
|
remainingObservers: this.observers.length,
|
|
3444
3515
|
clearedNavReports: !0
|
|
3445
3516
|
});
|
|
@@ -3448,8 +3519,8 @@ class Vt extends p {
|
|
|
3448
3519
|
this.reportTTFB(), this.safeObserve(
|
|
3449
3520
|
"largest-contentful-paint",
|
|
3450
3521
|
(t) => {
|
|
3451
|
-
const s = t.getEntries(),
|
|
3452
|
-
|
|
3522
|
+
const s = t.getEntries(), n = s[s.length - 1];
|
|
3523
|
+
n && this.sendVital({ type: "LCP", value: Number(n.startTime.toFixed(N)) });
|
|
3453
3524
|
},
|
|
3454
3525
|
{ type: "largest-contentful-paint", buffered: !0 },
|
|
3455
3526
|
!0
|
|
@@ -3459,13 +3530,13 @@ class Vt extends p {
|
|
|
3459
3530
|
"layout-shift",
|
|
3460
3531
|
(t) => {
|
|
3461
3532
|
const s = t.getEntries();
|
|
3462
|
-
for (const
|
|
3463
|
-
if (
|
|
3533
|
+
for (const n of s) {
|
|
3534
|
+
if (n.hadRecentInput === !0)
|
|
3464
3535
|
continue;
|
|
3465
|
-
const a = typeof
|
|
3536
|
+
const a = typeof n.value == "number" ? n.value : 0;
|
|
3466
3537
|
e += a;
|
|
3467
3538
|
}
|
|
3468
|
-
this.sendVital({ type: "CLS", value: Number(e.toFixed(
|
|
3539
|
+
this.sendVital({ type: "CLS", value: Number(e.toFixed(Ue)) });
|
|
3469
3540
|
},
|
|
3470
3541
|
{ type: "layout-shift", buffered: !0 }
|
|
3471
3542
|
), this.safeObserve(
|
|
@@ -3480,8 +3551,8 @@ class Vt extends p {
|
|
|
3480
3551
|
"event",
|
|
3481
3552
|
(t) => {
|
|
3482
3553
|
let s = 0;
|
|
3483
|
-
const
|
|
3484
|
-
for (const a of
|
|
3554
|
+
const n = t.getEntries();
|
|
3555
|
+
for (const a of n) {
|
|
3485
3556
|
const o = (a.processingEnd ?? 0) - (a.startTime ?? 0);
|
|
3486
3557
|
s = Math.max(s, o);
|
|
3487
3558
|
}
|
|
@@ -3492,13 +3563,13 @@ class Vt extends p {
|
|
|
3492
3563
|
}
|
|
3493
3564
|
async initWebVitals() {
|
|
3494
3565
|
try {
|
|
3495
|
-
const { onLCP: e, onCLS: t, onFCP: s, onTTFB:
|
|
3566
|
+
const { onLCP: e, onCLS: t, onFCP: s, onTTFB: n, onINP: a } = await import("./web-vitals-CCnqwnC8.mjs"), o = (l) => (c) => {
|
|
3496
3567
|
const d = Number(c.value.toFixed(N));
|
|
3497
3568
|
this.sendVital({ type: l, value: d });
|
|
3498
3569
|
};
|
|
3499
|
-
e(o("LCP")), t(o("CLS")), s(o("FCP")),
|
|
3570
|
+
e(o("LCP")), t(o("CLS")), s(o("FCP")), n(o("TTFB")), a(o("INP"));
|
|
3500
3571
|
} catch (e) {
|
|
3501
|
-
|
|
3572
|
+
i.warn("PerformanceHandler", "Failed to load web-vitals library, using fallback", {
|
|
3502
3573
|
error: e instanceof Error ? e.message : "Unknown error"
|
|
3503
3574
|
}), this.observeWebVitalsFallback();
|
|
3504
3575
|
}
|
|
@@ -3507,13 +3578,13 @@ class Vt extends p {
|
|
|
3507
3578
|
try {
|
|
3508
3579
|
const e = performance.getEntriesByType("navigation")[0];
|
|
3509
3580
|
if (!e) {
|
|
3510
|
-
|
|
3581
|
+
i.debug("PerformanceHandler", "Navigation timing not available for TTFB");
|
|
3511
3582
|
return;
|
|
3512
3583
|
}
|
|
3513
3584
|
const t = e.responseStart;
|
|
3514
|
-
typeof t == "number" && Number.isFinite(t) ? this.sendVital({ type: "TTFB", value: Number(t.toFixed(N)) }) :
|
|
3585
|
+
typeof t == "number" && Number.isFinite(t) ? this.sendVital({ type: "TTFB", value: Number(t.toFixed(N)) }) : i.debug("PerformanceHandler", "TTFB value is not a valid number", { ttfb: t });
|
|
3515
3586
|
} catch (e) {
|
|
3516
|
-
|
|
3587
|
+
i.warn("PerformanceHandler", "Failed to report TTFB", {
|
|
3517
3588
|
error: e instanceof Error ? e.message : "Unknown error"
|
|
3518
3589
|
});
|
|
3519
3590
|
}
|
|
@@ -3524,8 +3595,8 @@ class Vt extends p {
|
|
|
3524
3595
|
(e) => {
|
|
3525
3596
|
const t = e.getEntries();
|
|
3526
3597
|
for (const s of t) {
|
|
3527
|
-
const
|
|
3528
|
-
a - this.lastLongTaskSentAt >=
|
|
3598
|
+
const n = Number(s.duration.toFixed(N)), a = Date.now();
|
|
3599
|
+
a - this.lastLongTaskSentAt >= qe && (this.trackWebVital("LONG_TASK", n), this.lastLongTaskSentAt = a);
|
|
3529
3600
|
}
|
|
3530
3601
|
},
|
|
3531
3602
|
{ type: "longtask", buffered: !0 }
|
|
@@ -3535,20 +3606,20 @@ class Vt extends p {
|
|
|
3535
3606
|
const t = this.getNavigationId(), s = `${e.type}`;
|
|
3536
3607
|
if (t) {
|
|
3537
3608
|
this.reportedByNav.has(t) || this.reportedByNav.set(t, /* @__PURE__ */ new Set());
|
|
3538
|
-
const
|
|
3539
|
-
if (
|
|
3609
|
+
const n = this.reportedByNav.get(t);
|
|
3610
|
+
if (n.has(s))
|
|
3540
3611
|
return;
|
|
3541
|
-
|
|
3612
|
+
n.add(s);
|
|
3542
3613
|
}
|
|
3543
3614
|
this.trackWebVital(e.type, e.value);
|
|
3544
3615
|
}
|
|
3545
3616
|
trackWebVital(e, t) {
|
|
3546
3617
|
if (typeof t != "number" || !Number.isFinite(t)) {
|
|
3547
|
-
|
|
3618
|
+
i.warn("PerformanceHandler", "Invalid web vital value", { type: e, value: t });
|
|
3548
3619
|
return;
|
|
3549
3620
|
}
|
|
3550
3621
|
this.eventManager.track({
|
|
3551
|
-
type:
|
|
3622
|
+
type: g.WEB_VITALS,
|
|
3552
3623
|
web_vitals: {
|
|
3553
3624
|
type: e,
|
|
3554
3625
|
value: t
|
|
@@ -3560,33 +3631,33 @@ class Vt extends p {
|
|
|
3560
3631
|
const e = performance.getEntriesByType("navigation")[0];
|
|
3561
3632
|
return e ? `${Math.round(e.startTime)}_${window.location.pathname}` : null;
|
|
3562
3633
|
} catch (e) {
|
|
3563
|
-
return
|
|
3634
|
+
return i.warn("PerformanceHandler", "Failed to get navigation ID", {
|
|
3564
3635
|
error: e instanceof Error ? e.message : "Unknown error"
|
|
3565
3636
|
}), null;
|
|
3566
3637
|
}
|
|
3567
3638
|
}
|
|
3568
|
-
safeObserve(e, t, s,
|
|
3639
|
+
safeObserve(e, t, s, n = !1) {
|
|
3569
3640
|
try {
|
|
3570
3641
|
if (typeof PerformanceObserver > "u") return;
|
|
3571
3642
|
const a = PerformanceObserver.supportedEntryTypes;
|
|
3572
3643
|
if (a && !a.includes(e)) return;
|
|
3573
3644
|
const o = new PerformanceObserver((l, c) => {
|
|
3574
|
-
if (t(l, c),
|
|
3645
|
+
if (t(l, c), n)
|
|
3575
3646
|
try {
|
|
3576
3647
|
c.disconnect();
|
|
3577
3648
|
} catch {
|
|
3578
3649
|
}
|
|
3579
3650
|
});
|
|
3580
|
-
o.observe(s ?? { type: e, buffered: !0 }),
|
|
3651
|
+
o.observe(s ?? { type: e, buffered: !0 }), n || this.observers.push(o);
|
|
3581
3652
|
} catch (a) {
|
|
3582
|
-
|
|
3653
|
+
i.warn("PerformanceHandler", "Failed to create performance observer", {
|
|
3583
3654
|
type: e,
|
|
3584
3655
|
error: a instanceof Error ? a.message : "Unknown error"
|
|
3585
3656
|
});
|
|
3586
3657
|
}
|
|
3587
3658
|
}
|
|
3588
3659
|
}
|
|
3589
|
-
class
|
|
3660
|
+
class Gt extends p {
|
|
3590
3661
|
eventManager;
|
|
3591
3662
|
piiPatterns = [
|
|
3592
3663
|
/\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Z|a-z]{2,}\b/g,
|
|
@@ -3598,10 +3669,10 @@ class $t extends p {
|
|
|
3598
3669
|
super(), this.eventManager = e;
|
|
3599
3670
|
}
|
|
3600
3671
|
startTracking() {
|
|
3601
|
-
|
|
3672
|
+
i.debug("ErrorHandler", "Starting error tracking"), this.setupErrorListener(), this.setupUnhandledRejectionListener();
|
|
3602
3673
|
}
|
|
3603
3674
|
stopTracking() {
|
|
3604
|
-
|
|
3675
|
+
i.debug("ErrorHandler", "Stopping error tracking"), window.removeEventListener("error", this.handleError), window.removeEventListener("unhandledrejection", this.handleUnhandledRejection);
|
|
3605
3676
|
}
|
|
3606
3677
|
setupErrorListener() {
|
|
3607
3678
|
window.addEventListener("error", this.handleError);
|
|
@@ -3612,12 +3683,12 @@ class $t extends p {
|
|
|
3612
3683
|
handleError = (e) => {
|
|
3613
3684
|
const t = this.get("config");
|
|
3614
3685
|
if (!this.shouldSample(t?.errorSampling ?? 0.1)) {
|
|
3615
|
-
|
|
3686
|
+
i.debug("ErrorHandler", `Error not sampled, skipping (errorSampling: ${t?.errorSampling})`, {
|
|
3616
3687
|
errorSampling: t?.errorSampling
|
|
3617
3688
|
});
|
|
3618
3689
|
return;
|
|
3619
3690
|
}
|
|
3620
|
-
|
|
3691
|
+
i.warn(
|
|
3621
3692
|
"ErrorHandler",
|
|
3622
3693
|
`JavaScript error captured: ${e.message} (filename: ${e.filename}, lineno: ${e.lineno})`,
|
|
3623
3694
|
{
|
|
@@ -3626,9 +3697,9 @@ class $t extends p {
|
|
|
3626
3697
|
lineno: e.lineno
|
|
3627
3698
|
}
|
|
3628
3699
|
), this.eventManager.track({
|
|
3629
|
-
type:
|
|
3700
|
+
type: g.ERROR,
|
|
3630
3701
|
error_data: {
|
|
3631
|
-
type:
|
|
3702
|
+
type: O.JS_ERROR,
|
|
3632
3703
|
message: this.sanitizeText(e.message || "Unknown error")
|
|
3633
3704
|
}
|
|
3634
3705
|
});
|
|
@@ -3636,19 +3707,19 @@ class $t extends p {
|
|
|
3636
3707
|
handleUnhandledRejection = (e) => {
|
|
3637
3708
|
const t = this.get("config");
|
|
3638
3709
|
if (!this.shouldSample(t?.errorSampling ?? 0.1)) {
|
|
3639
|
-
|
|
3710
|
+
i.debug("ErrorHandler", "Promise rejection not sampled, skipping", {
|
|
3640
3711
|
errorSampling: t?.errorSampling
|
|
3641
3712
|
});
|
|
3642
3713
|
return;
|
|
3643
3714
|
}
|
|
3644
|
-
|
|
3715
|
+
i.warn("ErrorHandler", `Unhandled promise rejection captured (reason: ${typeof e.reason})`, {
|
|
3645
3716
|
reason: typeof e.reason
|
|
3646
3717
|
});
|
|
3647
3718
|
let s = "Unknown rejection";
|
|
3648
3719
|
e.reason && (typeof e.reason == "string" ? s = e.reason : e.reason instanceof Error ? s = e.reason.message || e.reason.toString() : s = String(e.reason)), this.eventManager.track({
|
|
3649
|
-
type:
|
|
3720
|
+
type: g.ERROR,
|
|
3650
3721
|
error_data: {
|
|
3651
|
-
type:
|
|
3722
|
+
type: O.PROMISE_REJECTION,
|
|
3652
3723
|
message: this.sanitizeText(s)
|
|
3653
3724
|
}
|
|
3654
3725
|
});
|
|
@@ -3663,7 +3734,7 @@ class $t extends p {
|
|
|
3663
3734
|
return Math.random() < e;
|
|
3664
3735
|
}
|
|
3665
3736
|
}
|
|
3666
|
-
class
|
|
3737
|
+
class Qt extends p {
|
|
3667
3738
|
eventManager;
|
|
3668
3739
|
originalFetch;
|
|
3669
3740
|
originalXHROpen;
|
|
@@ -3672,37 +3743,37 @@ class jt extends p {
|
|
|
3672
3743
|
super(), this.eventManager = e, this.originalFetch = window.fetch, this.originalXHROpen = XMLHttpRequest.prototype.open, this.originalXHRSend = XMLHttpRequest.prototype.send;
|
|
3673
3744
|
}
|
|
3674
3745
|
startTracking() {
|
|
3675
|
-
|
|
3746
|
+
i.debug("NetworkHandler", "Starting network error tracking"), this.interceptFetch(), this.interceptXHR();
|
|
3676
3747
|
}
|
|
3677
3748
|
stopTracking() {
|
|
3678
|
-
|
|
3749
|
+
i.debug("NetworkHandler", "Stopping network error tracking"), window.fetch = this.originalFetch, XMLHttpRequest.prototype.open = this.originalXHROpen, XMLHttpRequest.prototype.send = this.originalXHRSend;
|
|
3679
3750
|
}
|
|
3680
3751
|
interceptFetch() {
|
|
3681
3752
|
window.fetch = async (e, t) => {
|
|
3682
|
-
const s = Date.now(),
|
|
3753
|
+
const s = Date.now(), n = typeof e == "string" ? e : e.toString(), a = t?.method ?? "GET";
|
|
3683
3754
|
try {
|
|
3684
3755
|
const o = await this.originalFetch(e, t), l = Date.now() - s;
|
|
3685
|
-
return o.ok || (
|
|
3756
|
+
return o.ok || (i.debug("NetworkHandler", "Fetch error detected", {
|
|
3686
3757
|
method: a,
|
|
3687
|
-
url: this.normalizeUrlForTracking(
|
|
3758
|
+
url: this.normalizeUrlForTracking(n),
|
|
3688
3759
|
status: o.status,
|
|
3689
3760
|
statusText: o.statusText
|
|
3690
3761
|
}), this.trackNetworkError(
|
|
3691
3762
|
a.toUpperCase(),
|
|
3692
|
-
this.normalizeUrlForTracking(
|
|
3763
|
+
this.normalizeUrlForTracking(n),
|
|
3693
3764
|
o.status,
|
|
3694
3765
|
o.statusText,
|
|
3695
3766
|
l
|
|
3696
3767
|
)), o;
|
|
3697
3768
|
} catch (o) {
|
|
3698
3769
|
const l = Date.now() - s, c = o instanceof Error ? o.message : "Network Error";
|
|
3699
|
-
throw
|
|
3770
|
+
throw i.debug("NetworkHandler", "Fetch exception caught", {
|
|
3700
3771
|
method: a,
|
|
3701
|
-
url: this.normalizeUrlForTracking(
|
|
3772
|
+
url: this.normalizeUrlForTracking(n),
|
|
3702
3773
|
error: c
|
|
3703
3774
|
}), this.trackNetworkError(
|
|
3704
3775
|
a.toUpperCase(),
|
|
3705
|
-
this.normalizeUrlForTracking(
|
|
3776
|
+
this.normalizeUrlForTracking(n),
|
|
3706
3777
|
void 0,
|
|
3707
3778
|
c,
|
|
3708
3779
|
l
|
|
@@ -3711,34 +3782,34 @@ class jt extends p {
|
|
|
3711
3782
|
};
|
|
3712
3783
|
}
|
|
3713
3784
|
interceptXHR() {
|
|
3714
|
-
const e = this.trackNetworkError.bind(this), t = this.normalizeUrlForTracking.bind(this), s = this.originalXHROpen,
|
|
3785
|
+
const e = this.trackNetworkError.bind(this), t = this.normalizeUrlForTracking.bind(this), s = this.originalXHROpen, n = this.originalXHRSend;
|
|
3715
3786
|
XMLHttpRequest.prototype.open = function(a, o, l, c, d) {
|
|
3716
|
-
const
|
|
3717
|
-
return
|
|
3787
|
+
const h = l ?? !0, u = this;
|
|
3788
|
+
return u._tracelogStartTime = Date.now(), u._tracelogMethod = a.toUpperCase(), u._tracelogUrl = o.toString(), s.call(this, a, o, h, c, d);
|
|
3718
3789
|
}, XMLHttpRequest.prototype.send = function(a) {
|
|
3719
|
-
const o = this, l = o._tracelogStartTime ?? Date.now(), c = o._tracelogMethod ?? "GET", d = o._tracelogUrl ?? "",
|
|
3720
|
-
return o.onreadystatechange = (
|
|
3790
|
+
const o = this, l = o._tracelogStartTime ?? Date.now(), c = o._tracelogMethod ?? "GET", d = o._tracelogUrl ?? "", h = o.onreadystatechange;
|
|
3791
|
+
return o.onreadystatechange = (u) => {
|
|
3721
3792
|
if (o.readyState === XMLHttpRequest.DONE) {
|
|
3722
|
-
const
|
|
3793
|
+
const v = Date.now() - l;
|
|
3723
3794
|
if (o.status === 0 || o.status >= 400) {
|
|
3724
|
-
const
|
|
3725
|
-
|
|
3795
|
+
const y = o.statusText || "Request Failed";
|
|
3796
|
+
i.debug("NetworkHandler", "XHR error detected", {
|
|
3726
3797
|
method: c,
|
|
3727
3798
|
url: t(d),
|
|
3728
3799
|
status: o.status,
|
|
3729
|
-
statusText:
|
|
3730
|
-
}), e(c, t(d), o.status,
|
|
3800
|
+
statusText: y
|
|
3801
|
+
}), e(c, t(d), o.status, y, v);
|
|
3731
3802
|
}
|
|
3732
3803
|
}
|
|
3733
|
-
if (
|
|
3734
|
-
return
|
|
3735
|
-
},
|
|
3804
|
+
if (h)
|
|
3805
|
+
return h.call(o, u);
|
|
3806
|
+
}, n.call(this, a);
|
|
3736
3807
|
};
|
|
3737
3808
|
}
|
|
3738
|
-
trackNetworkError(e, t, s,
|
|
3809
|
+
trackNetworkError(e, t, s, n, a) {
|
|
3739
3810
|
const o = this.get("config");
|
|
3740
3811
|
if (!this.shouldSample(o?.errorSampling ?? 0.1)) {
|
|
3741
|
-
|
|
3812
|
+
i.debug(
|
|
3742
3813
|
"NetworkHandler",
|
|
3743
3814
|
`Network error not sampled, skipping (errorSampling: ${o?.errorSampling}, method: ${e}, url: ${t})`,
|
|
3744
3815
|
{
|
|
@@ -3749,19 +3820,19 @@ class jt extends p {
|
|
|
3749
3820
|
);
|
|
3750
3821
|
return;
|
|
3751
3822
|
}
|
|
3752
|
-
|
|
3823
|
+
i.warn(
|
|
3753
3824
|
"NetworkHandler",
|
|
3754
|
-
`Network error tracked: ${e} ${t} (status: ${s}, statusText: ${
|
|
3755
|
-
{ method: e, url: t, status: s, statusText:
|
|
3825
|
+
`Network error tracked: ${e} ${t} (status: ${s}, statusText: ${n}, duration: ${a}ms)`,
|
|
3826
|
+
{ method: e, url: t, status: s, statusText: n, duration: a }
|
|
3756
3827
|
), this.eventManager.track({
|
|
3757
|
-
type:
|
|
3828
|
+
type: g.ERROR,
|
|
3758
3829
|
error_data: {
|
|
3759
|
-
type:
|
|
3760
|
-
message:
|
|
3830
|
+
type: O.NETWORK_ERROR,
|
|
3831
|
+
message: n,
|
|
3761
3832
|
method: e,
|
|
3762
3833
|
url: t,
|
|
3763
3834
|
status: s,
|
|
3764
|
-
statusText:
|
|
3835
|
+
statusText: n,
|
|
3765
3836
|
duration: a
|
|
3766
3837
|
}
|
|
3767
3838
|
});
|
|
@@ -3769,7 +3840,7 @@ class jt extends p {
|
|
|
3769
3840
|
normalizeUrlForTracking(e) {
|
|
3770
3841
|
try {
|
|
3771
3842
|
const t = this.get("config");
|
|
3772
|
-
return
|
|
3843
|
+
return ie(e, t?.sensitiveQueryParams);
|
|
3773
3844
|
} catch {
|
|
3774
3845
|
return e;
|
|
3775
3846
|
}
|
|
@@ -3778,7 +3849,7 @@ class jt extends p {
|
|
|
3778
3849
|
return Math.random() < e;
|
|
3779
3850
|
}
|
|
3780
3851
|
}
|
|
3781
|
-
class
|
|
3852
|
+
class Wt extends p {
|
|
3782
3853
|
isInitialized = !1;
|
|
3783
3854
|
googleAnalytics = null;
|
|
3784
3855
|
storageManager;
|
|
@@ -3800,16 +3871,16 @@ class Gt extends p {
|
|
|
3800
3871
|
}
|
|
3801
3872
|
async init(e) {
|
|
3802
3873
|
if (this.isInitialized) {
|
|
3803
|
-
|
|
3874
|
+
i.debug("App", "App already initialized, skipping re-initialization", { projectId: e.id });
|
|
3804
3875
|
return;
|
|
3805
3876
|
}
|
|
3806
|
-
|
|
3877
|
+
i.info("App", "App initialization started", { projectId: e.id }), this.validateAppReadiness(e);
|
|
3807
3878
|
try {
|
|
3808
|
-
this.initStorage(), await this.setState(e), await this.setIntegrations(), this.setEventManager(), await this.initHandlers(), this.isInitialized = !0,
|
|
3879
|
+
this.initStorage(), await this.setState(e), await this.setIntegrations(), this.setEventManager(), await this.initHandlers(), this.isInitialized = !0, i.info("App", "App initialization completed successfully", {
|
|
3809
3880
|
projectId: e.id
|
|
3810
3881
|
});
|
|
3811
3882
|
} catch (t) {
|
|
3812
|
-
throw this.isInitialized = !1,
|
|
3883
|
+
throw this.isInitialized = !1, i.error("App", "App initialization failed", { projectId: e.id, error: t }), t;
|
|
3813
3884
|
}
|
|
3814
3885
|
}
|
|
3815
3886
|
/**
|
|
@@ -3820,20 +3891,20 @@ class Gt extends p {
|
|
|
3820
3891
|
*/
|
|
3821
3892
|
validateAppReadiness(e) {
|
|
3822
3893
|
if (!e?.id)
|
|
3823
|
-
throw
|
|
3894
|
+
throw i.clientError("App", "Configuration integrity check failed - missing project ID", {
|
|
3824
3895
|
hasConfig: !!e,
|
|
3825
3896
|
hasId: !!e?.id
|
|
3826
3897
|
}), new Q("Configuration integrity check failed", "app");
|
|
3827
3898
|
}
|
|
3828
3899
|
sendCustomEvent(e, t) {
|
|
3829
3900
|
if (!this.eventManager) {
|
|
3830
|
-
|
|
3901
|
+
i.warn("App", "Custom event attempted before eventManager initialization", { eventName: e });
|
|
3831
3902
|
return;
|
|
3832
3903
|
}
|
|
3833
|
-
const { valid: s, error:
|
|
3904
|
+
const { valid: s, error: n, sanitizedMetadata: a } = bt(e, t);
|
|
3834
3905
|
if (s)
|
|
3835
|
-
|
|
3836
|
-
type:
|
|
3906
|
+
i.debug("App", "Custom event validated and queued", { eventName: e, hasMetadata: !!a }), this.eventManager.track({
|
|
3907
|
+
type: g.CUSTOM,
|
|
3837
3908
|
custom_event: {
|
|
3838
3909
|
name: e,
|
|
3839
3910
|
...a && { metadata: a }
|
|
@@ -3841,50 +3912,50 @@ class Gt extends p {
|
|
|
3841
3912
|
});
|
|
3842
3913
|
else {
|
|
3843
3914
|
const o = this.get("config")?.mode;
|
|
3844
|
-
if (
|
|
3915
|
+
if (i.clientError("App", `Custom event validation failed: ${n ?? "unknown error"}`, {
|
|
3845
3916
|
eventName: e,
|
|
3846
|
-
validationError:
|
|
3917
|
+
validationError: n,
|
|
3847
3918
|
hasMetadata: !!t,
|
|
3848
3919
|
mode: o
|
|
3849
3920
|
}), o === "qa" || o === "debug")
|
|
3850
3921
|
throw new Error(
|
|
3851
|
-
`custom event "${e}" validation failed (${
|
|
3922
|
+
`custom event "${e}" validation failed (${n ?? "unknown error"}). Please, review your event data and try again.`
|
|
3852
3923
|
);
|
|
3853
3924
|
}
|
|
3854
3925
|
}
|
|
3855
3926
|
destroy() {
|
|
3856
3927
|
if (!this.isInitialized) {
|
|
3857
|
-
|
|
3928
|
+
i.warn("App", "Destroy called but app was not initialized");
|
|
3858
3929
|
return;
|
|
3859
3930
|
}
|
|
3860
|
-
|
|
3931
|
+
i.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, i.info("App", "App cleanup completed successfully");
|
|
3861
3932
|
}
|
|
3862
3933
|
async setState(e) {
|
|
3863
3934
|
this.setApiUrl(e.id, e.allowHttp), await this.setConfig(e), this.setUserId(), this.setDevice(), this.setPageUrl();
|
|
3864
3935
|
}
|
|
3865
3936
|
setApiUrl(e, t = !1) {
|
|
3866
|
-
const s = new
|
|
3937
|
+
const s = new wt();
|
|
3867
3938
|
this.set("apiUrl", s.getUrl(e, t));
|
|
3868
3939
|
}
|
|
3869
3940
|
async setConfig(e) {
|
|
3870
|
-
const s = await new
|
|
3941
|
+
const s = await new It().get(this.get("apiUrl"), e);
|
|
3871
3942
|
this.set("config", s);
|
|
3872
3943
|
}
|
|
3873
3944
|
setUserId() {
|
|
3874
|
-
const t = new
|
|
3945
|
+
const t = new _t(this.storageManager).getId();
|
|
3875
3946
|
this.set("userId", t);
|
|
3876
3947
|
}
|
|
3877
3948
|
setDevice() {
|
|
3878
|
-
const e =
|
|
3949
|
+
const e = Ie();
|
|
3879
3950
|
this.set("device", e);
|
|
3880
3951
|
}
|
|
3881
3952
|
setPageUrl() {
|
|
3882
|
-
const e =
|
|
3953
|
+
const e = ie(window.location.href, this.get("config").sensitiveQueryParams);
|
|
3883
3954
|
this.set("pageUrl", e);
|
|
3884
3955
|
}
|
|
3885
3956
|
async setIntegrations() {
|
|
3886
3957
|
const e = this.get("config").ipExcluded, t = this.get("config").integrations?.googleAnalytics?.measurementId;
|
|
3887
|
-
!e && t?.trim() && (this.googleAnalytics = new
|
|
3958
|
+
!e && t?.trim() && (this.googleAnalytics = new Vt(), await this.googleAnalytics.initialize());
|
|
3888
3959
|
}
|
|
3889
3960
|
async initHandlers() {
|
|
3890
3961
|
if (!this.eventManager)
|
|
@@ -3894,74 +3965,74 @@ class Gt extends p {
|
|
|
3894
3965
|
this.initSessionHandler(), this.initPageViewHandler(), this.initClickHandler(), this.initScrollHandler(), await this.initPerformanceHandler(), this.initErrorHandler(), this.initNetworkHandler();
|
|
3895
3966
|
}
|
|
3896
3967
|
initStorage() {
|
|
3897
|
-
this.storageManager = new
|
|
3968
|
+
this.storageManager = new $t();
|
|
3898
3969
|
}
|
|
3899
3970
|
setEventManager() {
|
|
3900
3971
|
if (!this.storageManager)
|
|
3901
3972
|
throw new Error("StorageManager must be initialized before EventManager");
|
|
3902
|
-
this.eventManager = new
|
|
3973
|
+
this.eventManager = new Ct(this.storageManager, this.googleAnalytics);
|
|
3903
3974
|
}
|
|
3904
3975
|
initSessionHandler() {
|
|
3905
3976
|
if (!this.storageManager || !this.eventManager)
|
|
3906
3977
|
throw new Error("StorageManager and EventManager must be initialized before SessionHandler");
|
|
3907
|
-
this.sessionHandler = new
|
|
3978
|
+
this.sessionHandler = new Dt(this.storageManager, this.eventManager), this.sessionHandler.startTracking();
|
|
3908
3979
|
}
|
|
3909
3980
|
initPageViewHandler() {
|
|
3910
3981
|
if (!this.eventManager)
|
|
3911
3982
|
throw new Error("EventManager must be initialized before PageViewHandler");
|
|
3912
3983
|
const e = () => this.onPageViewTrack();
|
|
3913
|
-
this.pageViewHandler = new
|
|
3984
|
+
this.pageViewHandler = new xt(this.eventManager, e), this.pageViewHandler.startTracking();
|
|
3914
3985
|
}
|
|
3915
3986
|
onPageViewTrack() {
|
|
3916
3987
|
this.set("suppressNextScroll", !0), this.suppressNextScrollTimer && (clearTimeout(this.suppressNextScrollTimer), this.suppressNextScrollTimer = null), this.suppressNextScrollTimer = window.setTimeout(() => {
|
|
3917
3988
|
this.set("suppressNextScroll", !1);
|
|
3918
|
-
},
|
|
3989
|
+
}, Ae * tt.SUPPRESS_MULTIPLIER);
|
|
3919
3990
|
}
|
|
3920
3991
|
initClickHandler() {
|
|
3921
3992
|
if (!this.eventManager)
|
|
3922
3993
|
throw new Error("EventManager must be initialized before ClickHandler");
|
|
3923
|
-
this.clickHandler = new
|
|
3994
|
+
this.clickHandler = new Ft(this.eventManager), this.clickHandler.startTracking();
|
|
3924
3995
|
}
|
|
3925
3996
|
initScrollHandler() {
|
|
3926
3997
|
if (!this.eventManager)
|
|
3927
3998
|
throw new Error("EventManager must be initialized before ScrollHandler");
|
|
3928
|
-
this.scrollHandler = new
|
|
3999
|
+
this.scrollHandler = new zt(this.eventManager), this.scrollHandler.startTracking();
|
|
3929
4000
|
}
|
|
3930
4001
|
async initPerformanceHandler() {
|
|
3931
4002
|
if (!this.eventManager)
|
|
3932
4003
|
throw new Error("EventManager must be initialized before PerformanceHandler");
|
|
3933
|
-
this.performanceHandler = new
|
|
4004
|
+
this.performanceHandler = new jt(this.eventManager), await this.performanceHandler.startTracking();
|
|
3934
4005
|
}
|
|
3935
4006
|
initErrorHandler() {
|
|
3936
4007
|
if (!this.eventManager)
|
|
3937
4008
|
throw new Error("EventManager must be initialized before ErrorHandler");
|
|
3938
|
-
this.errorHandler = new
|
|
4009
|
+
this.errorHandler = new Gt(this.eventManager), this.errorHandler.startTracking();
|
|
3939
4010
|
}
|
|
3940
4011
|
initNetworkHandler() {
|
|
3941
4012
|
if (!this.eventManager)
|
|
3942
4013
|
throw new Error("EventManager must be initialized before NetworkHandler");
|
|
3943
|
-
this.networkHandler = new
|
|
4014
|
+
this.networkHandler = new Qt(this.eventManager), this.networkHandler.startTracking();
|
|
3944
4015
|
}
|
|
3945
4016
|
}
|
|
3946
|
-
const
|
|
4017
|
+
const Bt = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
|
|
3947
4018
|
__proto__: null,
|
|
3948
|
-
DeviceType:
|
|
3949
|
-
ErrorType:
|
|
3950
|
-
EventType:
|
|
4019
|
+
DeviceType: w,
|
|
4020
|
+
ErrorType: O,
|
|
4021
|
+
EventType: g,
|
|
3951
4022
|
Mode: L,
|
|
3952
4023
|
ScrollDirection: j,
|
|
3953
4024
|
TagConditionOperator: f,
|
|
3954
4025
|
TagConditionType: m,
|
|
3955
4026
|
TagLogicalOperator: G
|
|
3956
|
-
}, Symbol.toStringTag, { value: "Module" })),
|
|
4027
|
+
}, Symbol.toStringTag, { value: "Module" })), qt = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
|
|
3957
4028
|
__proto__: null,
|
|
3958
4029
|
DEFAULT_SESSION_TIMEOUT_MS: R
|
|
3959
4030
|
}, Symbol.toStringTag, { value: "Module" }));
|
|
3960
|
-
let
|
|
3961
|
-
const
|
|
4031
|
+
let S = null, T = !1;
|
|
4032
|
+
const Xt = async (r) => {
|
|
3962
4033
|
try {
|
|
3963
|
-
if (
|
|
3964
|
-
throw
|
|
4034
|
+
if (i.info("API", "Library initialization started", { id: r.id }), typeof window > "u" || typeof document > "u")
|
|
4035
|
+
throw i.clientError(
|
|
3965
4036
|
"API",
|
|
3966
4037
|
"Browser environment required - this library can only be used in a browser environment",
|
|
3967
4038
|
{
|
|
@@ -3969,88 +4040,88 @@ const qt = async (r) => {
|
|
|
3969
4040
|
hasDocument: typeof document < "u"
|
|
3970
4041
|
}
|
|
3971
4042
|
), new Error("This library can only be used in a browser environment");
|
|
3972
|
-
if (
|
|
3973
|
-
|
|
4043
|
+
if (S) {
|
|
4044
|
+
i.debug("API", "Library already initialized, skipping duplicate initialization", {
|
|
3974
4045
|
projectId: r.id
|
|
3975
4046
|
});
|
|
3976
4047
|
return;
|
|
3977
4048
|
}
|
|
3978
4049
|
if (T) {
|
|
3979
|
-
|
|
4050
|
+
i.debug("API", "Concurrent initialization detected, waiting for completion", { projectId: r.id });
|
|
3980
4051
|
let s = 0;
|
|
3981
|
-
const
|
|
3982
|
-
for (; T && s <
|
|
4052
|
+
const n = pe.MAX_CONCURRENT_RETRIES, a = pe.CONCURRENT_RETRY_DELAY_MS;
|
|
4053
|
+
for (; T && s < n; )
|
|
3983
4054
|
await new Promise((o) => setTimeout(o, a)), s++;
|
|
3984
|
-
if (
|
|
3985
|
-
|
|
4055
|
+
if (S) {
|
|
4056
|
+
i.debug("API", "Concurrent initialization completed successfully", {
|
|
3986
4057
|
projectId: r.id,
|
|
3987
4058
|
retriesUsed: s
|
|
3988
4059
|
});
|
|
3989
4060
|
return;
|
|
3990
4061
|
}
|
|
3991
4062
|
if (T)
|
|
3992
|
-
throw
|
|
4063
|
+
throw i.error("API", "Initialization timeout - concurrent initialization took too long", {
|
|
3993
4064
|
projectId: r.id,
|
|
3994
4065
|
retriesUsed: s,
|
|
3995
|
-
maxRetries:
|
|
4066
|
+
maxRetries: n
|
|
3996
4067
|
}), new Error("App initialization timeout - concurrent initialization took too long");
|
|
3997
4068
|
}
|
|
3998
|
-
T = !0,
|
|
3999
|
-
const e =
|
|
4000
|
-
|
|
4001
|
-
const t = new
|
|
4002
|
-
await t.init(e),
|
|
4069
|
+
T = !0, i.debug("API", "Validating and normalizing configuration", { projectId: r.id });
|
|
4070
|
+
const e = ut(r);
|
|
4071
|
+
i.debug("API", "Creating App instance", { projectId: e.id });
|
|
4072
|
+
const t = new Wt();
|
|
4073
|
+
await t.init(e), S = t, i.info("API", "Library initialization completed successfully", {
|
|
4003
4074
|
projectId: e.id
|
|
4004
4075
|
});
|
|
4005
4076
|
} catch (e) {
|
|
4006
|
-
if (
|
|
4077
|
+
if (S && !S.initialized)
|
|
4007
4078
|
try {
|
|
4008
|
-
|
|
4079
|
+
S.destroy();
|
|
4009
4080
|
} catch (t) {
|
|
4010
|
-
|
|
4081
|
+
i.warn("API", "Failed to cleanup partially initialized app", { cleanupError: t });
|
|
4011
4082
|
}
|
|
4012
|
-
throw
|
|
4083
|
+
throw S = null, i.error("API", "Initialization failed", { error: e }), e;
|
|
4013
4084
|
} finally {
|
|
4014
4085
|
T = !1;
|
|
4015
4086
|
}
|
|
4016
|
-
},
|
|
4087
|
+
}, Kt = (r, e) => {
|
|
4017
4088
|
try {
|
|
4018
|
-
if (!
|
|
4019
|
-
throw
|
|
4089
|
+
if (!S)
|
|
4090
|
+
throw i.clientError("API", "Custom event failed - Library not initialized. Please call TraceLog.init() first", {
|
|
4020
4091
|
eventName: r,
|
|
4021
4092
|
hasMetadata: !!e
|
|
4022
4093
|
}), new Error("App not initialized");
|
|
4023
|
-
|
|
4094
|
+
i.debug("API", "Sending custom event", {
|
|
4024
4095
|
eventName: r,
|
|
4025
4096
|
hasMetadata: !!e,
|
|
4026
4097
|
metadataKeys: e ? Object.keys(e) : []
|
|
4027
|
-
}),
|
|
4098
|
+
}), S.sendCustomEvent(r, e);
|
|
4028
4099
|
} catch (t) {
|
|
4029
|
-
if (
|
|
4100
|
+
if (i.error("API", "Event tracking failed", { eventName: r, error: t, hasMetadata: !!e }), t instanceof Error && (t.message === "App not initialized" || t.message.includes("validation failed")))
|
|
4030
4101
|
throw t;
|
|
4031
4102
|
}
|
|
4032
|
-
},
|
|
4033
|
-
isInitialized:
|
|
4103
|
+
}, Yt = () => S !== null, Jt = () => ({
|
|
4104
|
+
isInitialized: S !== null,
|
|
4034
4105
|
isInitializing: T,
|
|
4035
|
-
hasInstance:
|
|
4036
|
-
}),
|
|
4106
|
+
hasInstance: S !== null
|
|
4107
|
+
}), Zt = () => {
|
|
4037
4108
|
try {
|
|
4038
|
-
if (
|
|
4039
|
-
throw
|
|
4040
|
-
|
|
4109
|
+
if (i.info("API", "Library cleanup initiated"), !S)
|
|
4110
|
+
throw i.warn("API", "Cleanup called but Library was not initialized"), new Error("App not initialized");
|
|
4111
|
+
S.destroy(), S = null, T = !1, i.info("API", "Library cleanup completed successfully");
|
|
4041
4112
|
} catch (r) {
|
|
4042
|
-
|
|
4113
|
+
i.error("API", "Cleanup failed", { error: r, hadApp: !!S, wasInitializing: T });
|
|
4043
4114
|
}
|
|
4044
|
-
},
|
|
4115
|
+
}, es = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
|
|
4045
4116
|
__proto__: null,
|
|
4046
|
-
Constants:
|
|
4047
|
-
Types:
|
|
4048
|
-
destroy:
|
|
4049
|
-
event:
|
|
4050
|
-
getInitializationStatus:
|
|
4051
|
-
init:
|
|
4052
|
-
isInitialized:
|
|
4117
|
+
Constants: qt,
|
|
4118
|
+
Types: Bt,
|
|
4119
|
+
destroy: Zt,
|
|
4120
|
+
event: Kt,
|
|
4121
|
+
getInitializationStatus: Jt,
|
|
4122
|
+
init: Xt,
|
|
4123
|
+
isInitialized: Yt
|
|
4053
4124
|
}, Symbol.toStringTag, { value: "Module" }));
|
|
4054
4125
|
export {
|
|
4055
|
-
|
|
4126
|
+
es as TraceLog
|
|
4056
4127
|
};
|