@tracelog/lib 0.5.5 → 0.6.1
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/README.md +157 -180
- package/dist/browser/tracelog.esm.js +1124 -1377
- package/dist/browser/tracelog.esm.js.map +1 -0
- package/dist/browser/tracelog.js +2 -2
- package/dist/browser/tracelog.js.map +1 -0
- package/dist/cjs/api.d.ts +12 -2
- package/dist/cjs/api.js +74 -29
- package/dist/cjs/app.d.ts +2 -2
- package/dist/cjs/app.js +26 -32
- package/dist/cjs/constants/config.constants.d.ts +7 -2
- package/dist/cjs/constants/config.constants.js +9 -18
- package/dist/cjs/constants/index.d.ts +0 -1
- package/dist/cjs/constants/index.js +0 -1
- package/dist/cjs/constants/storage.constants.d.ts +3 -2
- package/dist/cjs/constants/storage.constants.js +4 -4
- package/dist/cjs/handlers/click.handler.js +3 -6
- package/dist/cjs/handlers/error.handler.js +1 -11
- package/dist/cjs/handlers/page-view.handler.js +0 -4
- package/dist/cjs/handlers/performance.handler.js +14 -29
- package/dist/cjs/handlers/scroll.handler.js +7 -6
- package/dist/cjs/handlers/session.handler.js +7 -6
- package/dist/cjs/integrations/google-analytics.integration.js +2 -6
- package/dist/cjs/listeners/activity-listener-manager.js +3 -3
- package/dist/cjs/listeners/input-listener-managers.js +3 -3
- package/dist/cjs/listeners/touch-listener-manager.js +3 -3
- package/dist/cjs/listeners/unload-listener-manager.js +3 -3
- package/dist/cjs/listeners/visibility-listener-manager.js +3 -3
- package/dist/cjs/managers/event.manager.d.ts +5 -1
- package/dist/cjs/managers/event.manager.js +103 -40
- package/dist/cjs/managers/sender.manager.js +29 -36
- package/dist/cjs/managers/session.manager.js +5 -13
- package/dist/cjs/managers/state.manager.d.ts +0 -3
- package/dist/cjs/managers/state.manager.js +1 -43
- package/dist/cjs/managers/storage.manager.d.ts +21 -2
- package/dist/cjs/managers/storage.manager.js +164 -21
- package/dist/cjs/managers/user.manager.d.ts +1 -1
- package/dist/cjs/managers/user.manager.js +2 -2
- package/dist/cjs/public-api.d.ts +3 -3
- package/dist/cjs/public-api.js +1 -1
- package/dist/cjs/test-bridge.d.ts +1 -0
- package/dist/cjs/test-bridge.js +37 -2
- package/dist/cjs/types/config.types.d.ts +17 -20
- package/dist/cjs/types/config.types.js +6 -0
- package/dist/cjs/types/event.types.d.ts +1 -13
- package/dist/cjs/types/index.d.ts +0 -2
- package/dist/cjs/types/index.js +0 -2
- package/dist/cjs/types/mode.types.d.ts +1 -2
- package/dist/cjs/types/mode.types.js +0 -1
- package/dist/cjs/types/queue.types.d.ts +0 -6
- package/dist/cjs/types/state.types.d.ts +2 -0
- package/dist/cjs/types/test-bridge.types.d.ts +2 -2
- package/dist/cjs/types/validation-error.types.d.ts +0 -6
- package/dist/cjs/types/validation-error.types.js +1 -10
- package/dist/cjs/utils/browser/device-detector.utils.js +2 -24
- package/dist/cjs/utils/browser/index.d.ts +1 -0
- package/dist/cjs/utils/browser/index.js +1 -0
- package/dist/cjs/utils/browser/qa-mode.utils.d.ts +13 -0
- package/dist/cjs/utils/browser/qa-mode.utils.js +43 -0
- package/dist/cjs/utils/browser/utm-params.utils.js +0 -15
- package/dist/cjs/utils/data/uuid.utils.d.ts +13 -0
- package/dist/cjs/utils/data/uuid.utils.js +37 -1
- package/dist/cjs/utils/index.d.ts +1 -1
- package/dist/cjs/utils/index.js +1 -1
- package/dist/cjs/utils/logging.utils.d.ts +21 -0
- package/dist/cjs/utils/logging.utils.js +86 -0
- package/dist/cjs/utils/network/index.d.ts +0 -1
- package/dist/cjs/utils/network/index.js +0 -1
- package/dist/cjs/utils/network/url.utils.d.ts +2 -8
- package/dist/cjs/utils/network/url.utils.js +45 -90
- package/dist/cjs/utils/security/sanitize.utils.d.ts +1 -13
- package/dist/cjs/utils/security/sanitize.utils.js +15 -178
- package/dist/cjs/utils/validations/config-validations.utils.d.ts +3 -9
- package/dist/cjs/utils/validations/config-validations.utils.js +56 -93
- package/dist/cjs/utils/validations/event-validations.utils.js +11 -5
- package/dist/cjs/utils/validations/index.d.ts +0 -1
- package/dist/cjs/utils/validations/index.js +0 -1
- package/dist/cjs/utils/validations/metadata-validations.utils.js +0 -1
- package/dist/cjs/utils/validations/type-guards.utils.d.ts +2 -2
- package/dist/cjs/utils/validations/type-guards.utils.js +50 -4
- package/dist/esm/api.d.ts +12 -2
- package/dist/esm/api.js +73 -29
- package/dist/esm/app.d.ts +2 -2
- package/dist/esm/app.js +28 -34
- package/dist/esm/constants/config.constants.d.ts +7 -2
- package/dist/esm/constants/config.constants.js +7 -16
- package/dist/esm/constants/index.d.ts +0 -1
- package/dist/esm/constants/index.js +0 -1
- package/dist/esm/constants/storage.constants.d.ts +3 -2
- package/dist/esm/constants/storage.constants.js +3 -2
- package/dist/esm/handlers/click.handler.js +3 -6
- package/dist/esm/handlers/error.handler.js +1 -11
- package/dist/esm/handlers/page-view.handler.js +0 -4
- package/dist/esm/handlers/performance.handler.js +14 -29
- package/dist/esm/handlers/scroll.handler.js +7 -6
- package/dist/esm/handlers/session.handler.js +7 -6
- package/dist/esm/integrations/google-analytics.integration.js +3 -7
- package/dist/esm/listeners/activity-listener-manager.js +3 -3
- package/dist/esm/listeners/input-listener-managers.js +3 -3
- package/dist/esm/listeners/touch-listener-manager.js +3 -3
- package/dist/esm/listeners/unload-listener-manager.js +3 -3
- package/dist/esm/listeners/visibility-listener-manager.js +3 -3
- package/dist/esm/managers/event.manager.d.ts +5 -1
- package/dist/esm/managers/event.manager.js +106 -43
- package/dist/esm/managers/sender.manager.js +31 -38
- package/dist/esm/managers/session.manager.js +5 -13
- package/dist/esm/managers/state.manager.d.ts +0 -3
- package/dist/esm/managers/state.manager.js +1 -43
- package/dist/esm/managers/storage.manager.d.ts +21 -2
- package/dist/esm/managers/storage.manager.js +164 -21
- package/dist/esm/managers/user.manager.d.ts +1 -1
- package/dist/esm/managers/user.manager.js +2 -2
- package/dist/esm/public-api.d.ts +3 -3
- package/dist/esm/public-api.js +1 -1
- package/dist/esm/test-bridge.d.ts +1 -0
- package/dist/esm/test-bridge.js +37 -2
- package/dist/esm/types/config.types.d.ts +17 -20
- package/dist/esm/types/config.types.js +5 -1
- package/dist/esm/types/event.types.d.ts +1 -13
- package/dist/esm/types/index.d.ts +0 -2
- package/dist/esm/types/index.js +0 -2
- package/dist/esm/types/mode.types.d.ts +1 -2
- package/dist/esm/types/mode.types.js +0 -1
- package/dist/esm/types/queue.types.d.ts +0 -6
- package/dist/esm/types/state.types.d.ts +2 -0
- package/dist/esm/types/test-bridge.types.d.ts +2 -2
- package/dist/esm/types/validation-error.types.d.ts +0 -6
- package/dist/esm/types/validation-error.types.js +0 -8
- package/dist/esm/utils/browser/device-detector.utils.js +2 -24
- package/dist/esm/utils/browser/index.d.ts +1 -0
- package/dist/esm/utils/browser/index.js +1 -0
- package/dist/esm/utils/browser/qa-mode.utils.d.ts +13 -0
- package/dist/esm/utils/browser/qa-mode.utils.js +39 -0
- package/dist/esm/utils/browser/utm-params.utils.js +0 -15
- package/dist/esm/utils/data/uuid.utils.d.ts +13 -0
- package/dist/esm/utils/data/uuid.utils.js +35 -0
- package/dist/esm/utils/index.d.ts +1 -1
- package/dist/esm/utils/index.js +1 -1
- package/dist/esm/utils/logging.utils.d.ts +21 -0
- package/dist/esm/utils/logging.utils.js +81 -0
- package/dist/esm/utils/network/index.d.ts +0 -1
- package/dist/esm/utils/network/index.js +0 -1
- package/dist/esm/utils/network/url.utils.d.ts +2 -8
- package/dist/esm/utils/network/url.utils.js +44 -88
- package/dist/esm/utils/security/sanitize.utils.d.ts +1 -13
- package/dist/esm/utils/security/sanitize.utils.js +15 -176
- package/dist/esm/utils/validations/config-validations.utils.d.ts +3 -9
- package/dist/esm/utils/validations/config-validations.utils.js +57 -93
- package/dist/esm/utils/validations/event-validations.utils.js +11 -5
- package/dist/esm/utils/validations/index.d.ts +0 -1
- package/dist/esm/utils/validations/index.js +0 -1
- package/dist/esm/utils/validations/metadata-validations.utils.js +0 -1
- package/dist/esm/utils/validations/type-guards.utils.d.ts +2 -2
- package/dist/esm/utils/validations/type-guards.utils.js +50 -4
- package/package.json +3 -2
- package/dist/cjs/app.types.d.ts +0 -2
- package/dist/cjs/app.types.js +0 -12
- package/dist/cjs/constants/api.constants.d.ts +0 -6
- package/dist/cjs/constants/api.constants.js +0 -14
- package/dist/cjs/managers/api.manager.d.ts +0 -13
- package/dist/cjs/managers/api.manager.js +0 -44
- package/dist/cjs/managers/config.builder.d.ts +0 -33
- package/dist/cjs/managers/config.builder.js +0 -116
- package/dist/cjs/managers/config.manager.d.ts +0 -56
- package/dist/cjs/managers/config.manager.js +0 -157
- package/dist/cjs/managers/tags.manager.d.ts +0 -36
- package/dist/cjs/managers/tags.manager.js +0 -171
- package/dist/cjs/types/api.types.d.ts +0 -52
- package/dist/cjs/types/api.types.js +0 -56
- package/dist/cjs/types/tag.types.d.ts +0 -43
- package/dist/cjs/types/tag.types.js +0 -31
- package/dist/cjs/utils/logging/debug-logger.utils.d.ts +0 -14
- package/dist/cjs/utils/logging/debug-logger.utils.js +0 -47
- package/dist/cjs/utils/logging/index.d.ts +0 -1
- package/dist/cjs/utils/logging/index.js +0 -5
- package/dist/cjs/utils/network/fetch-with-timeout.utils.d.ts +0 -4
- package/dist/cjs/utils/network/fetch-with-timeout.utils.js +0 -25
- package/dist/cjs/utils/validations/url-validations.utils.d.ts +0 -15
- package/dist/cjs/utils/validations/url-validations.utils.js +0 -47
- package/dist/esm/app.types.d.ts +0 -2
- package/dist/esm/app.types.js +0 -1
- package/dist/esm/constants/api.constants.d.ts +0 -6
- package/dist/esm/constants/api.constants.js +0 -11
- package/dist/esm/managers/api.manager.d.ts +0 -13
- package/dist/esm/managers/api.manager.js +0 -41
- package/dist/esm/managers/config.builder.d.ts +0 -33
- package/dist/esm/managers/config.builder.js +0 -112
- package/dist/esm/managers/config.manager.d.ts +0 -56
- package/dist/esm/managers/config.manager.js +0 -153
- package/dist/esm/managers/tags.manager.d.ts +0 -36
- package/dist/esm/managers/tags.manager.js +0 -167
- package/dist/esm/types/api.types.d.ts +0 -52
- package/dist/esm/types/api.types.js +0 -53
- package/dist/esm/types/tag.types.d.ts +0 -43
- package/dist/esm/types/tag.types.js +0 -28
- package/dist/esm/utils/logging/debug-logger.utils.d.ts +0 -14
- package/dist/esm/utils/logging/debug-logger.utils.js +0 -44
- package/dist/esm/utils/logging/index.d.ts +0 -1
- package/dist/esm/utils/logging/index.js +0 -1
- package/dist/esm/utils/network/fetch-with-timeout.utils.d.ts +0 -4
- package/dist/esm/utils/network/fetch-with-timeout.utils.js +0 -22
- package/dist/esm/utils/validations/url-validations.utils.d.ts +0 -15
- package/dist/esm/utils/validations/url-validations.utils.js +0 -42
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
const P = 15 * 60 * 1e3, Je = 500, Ze = 1e4, xe = 250, et = 24, pe = 100, Se = 3, tt = 5e3, Ue = 1e4, rt = 10, Ee = 5, ve = 500, ye = 120, M = 1, nt = 0, st = 1, k = 3e4, x = 864e5, Ie = 120, Te = 8 * 1024, _e = 10, we = 10, X = 255, T = 1e3, q = 100, Ae = 3, w = 2, F = "data-tl", it = [
|
|
1
|
+
const O = "data-tlog", Ce = [
|
|
3
2
|
"button",
|
|
4
3
|
"a",
|
|
5
4
|
'input[type="button"]',
|
|
@@ -31,47 +30,102 @@ const P = 15 * 60 * 1e3, Je = 500, Ze = 1e4, xe = 250, et = 24, pe = 100, Se = 3
|
|
|
31
30
|
".menu-item",
|
|
32
31
|
"[data-testid]",
|
|
33
32
|
'[tabindex="0"]'
|
|
34
|
-
],
|
|
35
|
-
|
|
36
|
-
"
|
|
37
|
-
"
|
|
38
|
-
"excludedUrlPaths",
|
|
39
|
-
"ipExcluded"
|
|
40
|
-
]), y = {
|
|
41
|
-
// Project ID validation - consistent message across all layers
|
|
42
|
-
MISSING_PROJECT_ID: "Project ID is required",
|
|
43
|
-
PROJECT_ID_EMPTY_AFTER_TRIM: "Project ID is required",
|
|
44
|
-
// Session timeout validation
|
|
45
|
-
INVALID_SESSION_TIMEOUT: `Session timeout must be between ${k}ms (30 seconds) and ${x}ms (24 hours)`,
|
|
33
|
+
], be = ["utm_source", "utm_medium", "utm_campaign", "utm_term", "utm_content"];
|
|
34
|
+
const m = {
|
|
35
|
+
INVALID_SESSION_TIMEOUT: "Session timeout must be between 30000ms (30 seconds) and 86400000ms (24 hours)",
|
|
36
|
+
INVALID_SAMPLING_RATE: "Sampling rate must be between 0 and 1",
|
|
46
37
|
INVALID_ERROR_SAMPLING_RATE: "Error sampling must be between 0 and 1",
|
|
47
|
-
|
|
38
|
+
INVALID_TRACELOG_PROJECT_ID: "TraceLog project ID is required when integration is enabled",
|
|
39
|
+
INVALID_CUSTOM_API_URL: "Custom API URL is required when integration is enabled",
|
|
48
40
|
INVALID_GOOGLE_ANALYTICS_ID: "Google Analytics measurement ID is required when integration is enabled",
|
|
49
|
-
// UI validation
|
|
50
41
|
INVALID_SCROLL_CONTAINER_SELECTORS: "Scroll container selectors must be valid CSS selectors",
|
|
51
|
-
// Global metadata validation
|
|
52
42
|
INVALID_GLOBAL_METADATA: "Global metadata must be an object",
|
|
53
|
-
// Array validation
|
|
54
43
|
INVALID_SENSITIVE_QUERY_PARAMS: "Sensitive query params must be an array of strings"
|
|
55
|
-
},
|
|
44
|
+
}, Oe = [
|
|
56
45
|
/<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi,
|
|
57
46
|
/javascript:/gi,
|
|
58
47
|
/on\w+\s*=/gi,
|
|
59
48
|
/<iframe\b[^<]*(?:(?!<\/iframe>)<[^<]*)*<\/iframe>/gi,
|
|
60
49
|
/<embed\b[^>]*>/gi,
|
|
61
50
|
/<object\b[^<]*(?:(?!<\/object>)<[^<]*)*<\/object>/gi
|
|
62
|
-
]
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
}
|
|
51
|
+
];
|
|
52
|
+
var j = /* @__PURE__ */ ((s) => (s.Localhost = "localhost:8080", s.Fail = "localhost:9999", s))(j || {}), _ = /* @__PURE__ */ ((s) => (s.Mobile = "mobile", s.Tablet = "tablet", s.Desktop = "desktop", s.Unknown = "unknown", s))(_ || {}), X = /* @__PURE__ */ ((s) => (s.EVENT = "event", s.QUEUE = "queue", s))(X || {}), d = /* @__PURE__ */ ((s) => (s.PAGE_VIEW = "page_view", s.CLICK = "click", s.SCROLL = "scroll", s.SESSION_START = "session_start", s.SESSION_END = "session_end", s.CUSTOM = "custom", s.WEB_VITALS = "web_vitals", s.ERROR = "error", s))(d || {}), D = /* @__PURE__ */ ((s) => (s.UP = "up", s.DOWN = "down", s))(D || {}), L = /* @__PURE__ */ ((s) => (s.JS_ERROR = "js_error", s.PROMISE_REJECTION = "promise_rejection", s))(L || {}), R = /* @__PURE__ */ ((s) => (s.QA = "qa", s))(R || {});
|
|
53
|
+
class C extends Error {
|
|
54
|
+
constructor(e, t, r) {
|
|
55
|
+
super(e), this.errorCode = t, this.layer = r, this.name = this.constructor.name, Error.captureStackTrace && Error.captureStackTrace(this, this.constructor);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
class y extends C {
|
|
59
|
+
constructor(e, t = "config") {
|
|
60
|
+
super(e, "APP_CONFIG_INVALID", t);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
class Pe extends C {
|
|
64
|
+
constructor(e, t = "config") {
|
|
65
|
+
super(e, "SESSION_TIMEOUT_INVALID", t);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
class oe extends C {
|
|
69
|
+
constructor(e, t = "config") {
|
|
70
|
+
super(e, "SAMPLING_RATE_INVALID", t);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
class v extends C {
|
|
74
|
+
constructor(e, t = "config") {
|
|
75
|
+
super(e, "INTEGRATION_INVALID", t);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
class xt extends C {
|
|
79
|
+
constructor(e, t, r = "runtime") {
|
|
80
|
+
super(e, "INITIALIZATION_TIMEOUT", r), this.timeoutMs = t;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
const De = (s, e) => {
|
|
84
|
+
if (e) {
|
|
85
|
+
if (e instanceof Error) {
|
|
86
|
+
const t = e.message.replace(/\s+at\s+.*$/gm, "").replace(/\(.*?:\d+:\d+\)/g, "");
|
|
87
|
+
return `[TraceLog] ${s}: ${t}`;
|
|
88
|
+
}
|
|
89
|
+
return `[TraceLog] ${s}: ${e instanceof Error ? e.message : "Unknown error"}`;
|
|
90
|
+
}
|
|
91
|
+
return `[TraceLog] ${s}`;
|
|
92
|
+
}, o = (s, e, t) => {
|
|
93
|
+
const { error: r, data: n, showToClient: i = !1 } = t ?? {}, a = r ? De(e, r) : `[TraceLog] ${e}`, c = s === "error" ? "error" : s === "warn" ? "warn" : "log";
|
|
94
|
+
if (!(s === "debug" || s === "info" && !i))
|
|
95
|
+
if (n !== void 0) {
|
|
96
|
+
const l = ke(n);
|
|
97
|
+
console[c](a, l);
|
|
98
|
+
} else n !== void 0 ? console[c](a, n) : console[c](a);
|
|
99
|
+
}, ke = (s) => {
|
|
100
|
+
const e = {}, t = ["token", "password", "secret", "key", "apikey", "api_key", "sessionid", "session_id"];
|
|
101
|
+
for (const [r, n] of Object.entries(s)) {
|
|
102
|
+
const i = r.toLowerCase();
|
|
103
|
+
t.some((a) => i.includes(a)) ? e[r] = "[REDACTED]" : e[r] = n;
|
|
104
|
+
}
|
|
105
|
+
return e;
|
|
106
|
+
};
|
|
107
|
+
let W, pe;
|
|
108
|
+
const Ue = () => {
|
|
109
|
+
typeof window < "u" && !W && (W = window.matchMedia("(pointer: coarse)"), pe = window.matchMedia("(hover: none)"));
|
|
110
|
+
}, He = () => {
|
|
111
|
+
try {
|
|
112
|
+
const s = navigator;
|
|
113
|
+
if (s.userAgentData && typeof s.userAgentData.mobile == "boolean")
|
|
114
|
+
return s.userAgentData.platform && /ipad|tablet/i.test(s.userAgentData.platform) ? _.Tablet : s.userAgentData.mobile ? _.Mobile : _.Desktop;
|
|
115
|
+
Ue();
|
|
116
|
+
const e = window.innerWidth, t = W?.matches ?? !1, r = pe?.matches ?? !1, n = "ontouchstart" in window || navigator.maxTouchPoints > 0, i = navigator.userAgent.toLowerCase(), a = /mobile|android|iphone|ipod|blackberry|iemobile|opera mini/.test(i), c = /tablet|ipad|android(?!.*mobile)/.test(i);
|
|
117
|
+
return e <= 767 || a && n ? _.Mobile : e >= 768 && e <= 1024 || c || t && r && n ? _.Tablet : _.Desktop;
|
|
118
|
+
} catch (s) {
|
|
119
|
+
return o("warn", "Device detection failed, defaulting to desktop", { error: s }), _.Desktop;
|
|
120
|
+
}
|
|
121
|
+
}, T = "tlog", ce = `${T}:qa_mode`, xe = `${T}:uid`, Ve = (s) => s ? `${T}:${s}:queue` : `${T}:queue`, Fe = (s) => s ? `${T}:${s}:session` : `${T}:session`, Ge = (s) => s ? `${T}:${s}:broadcast` : `${T}:broadcast`, _e = {
|
|
68
122
|
LCP: 4e3,
|
|
69
123
|
FCP: 1800,
|
|
70
124
|
CLS: 0.25,
|
|
71
125
|
INP: 200,
|
|
72
126
|
TTFB: 800,
|
|
73
127
|
LONG_TASK: 50
|
|
74
|
-
},
|
|
128
|
+
}, ze = 1e3, Te = [
|
|
75
129
|
// Email addresses
|
|
76
130
|
/\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Z|a-z]{2,}\b/gi,
|
|
77
131
|
// US Phone numbers (various formats)
|
|
@@ -86,400 +140,252 @@ const P = 15 * 60 * 1e3, Je = 500, Ze = 1e4, xe = 250, et = 24, pe = 100, Se = 3
|
|
|
86
140
|
/Bearer\s+[A-Za-z0-9_-]+(?:\.[A-Za-z0-9_-]+)?(?:\.[A-Za-z0-9_-]+)?/gi,
|
|
87
141
|
// Passwords in connection strings (protocol://user:password@host)
|
|
88
142
|
/:\/\/[^:/]+:([^@]+)@/gi
|
|
89
|
-
],
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
p[e] = l;
|
|
106
|
-
} else
|
|
107
|
-
p[e] = s;
|
|
108
|
-
} else
|
|
109
|
-
p[e] = t;
|
|
110
|
-
} else
|
|
111
|
-
p[e] = t;
|
|
112
|
-
this.isCriticalStateKey(e) && this.shouldLog(n, p[e]) && a.debug("StateManager", "State updated", {
|
|
113
|
-
key: e,
|
|
114
|
-
oldValue: this.formatLogValue(e, n),
|
|
115
|
-
newValue: this.formatLogValue(e, p[e])
|
|
116
|
-
});
|
|
117
|
-
}
|
|
118
|
-
getState() {
|
|
119
|
-
return { ...p };
|
|
120
|
-
}
|
|
121
|
-
isCriticalStateKey(e) {
|
|
122
|
-
return e === "sessionId" || e === "config" || e === "hasStartSession";
|
|
123
|
-
}
|
|
124
|
-
shouldLog(e, t) {
|
|
125
|
-
return e !== t;
|
|
126
|
-
}
|
|
127
|
-
formatLogValue(e, t) {
|
|
128
|
-
return e === "config" ? t ? "(configured)" : "(not configured)" : t;
|
|
129
|
-
}
|
|
130
|
-
}
|
|
131
|
-
class mt {
|
|
132
|
-
clientError = (e, t, n) => this.log("CLIENT_ERROR", e, t, n);
|
|
133
|
-
clientWarn = (e, t, n) => this.log("CLIENT_WARN", e, t, n);
|
|
134
|
-
info = (e, t, n) => this.log("INFO", e, t, n);
|
|
135
|
-
error = (e, t, n) => this.log("ERROR", e, t, n);
|
|
136
|
-
warn = (e, t, n) => this.log("WARN", e, t, n);
|
|
137
|
-
debug = (e, t, n) => this.log("DEBUG", e, t, n);
|
|
138
|
-
verbose = (e, t, n) => this.log("VERBOSE", e, t, n);
|
|
139
|
-
log(e, t, n, s) {
|
|
140
|
-
const i = ft()?.config?.mode;
|
|
141
|
-
if (!this.shouldShow(e, i)) return;
|
|
142
|
-
const o = `[TraceLog:${t}] ${n}`, c = this.getMethod(e);
|
|
143
|
-
s !== void 0 ? console[c](o, s) : console[c](o);
|
|
144
|
-
}
|
|
145
|
-
shouldShow(e, t) {
|
|
146
|
-
return ["CLIENT_ERROR", "ERROR"].includes(e) ? !0 : t ? t === "qa" ? ["INFO", "CLIENT_ERROR", "CLIENT_WARN"].includes(e) : t === "debug" : e === "CLIENT_WARN";
|
|
147
|
-
}
|
|
148
|
-
getMethod(e) {
|
|
149
|
-
return ["CLIENT_ERROR", "ERROR"].includes(e) ? "error" : ["CLIENT_WARN", "WARN"].includes(e) ? "warn" : "log";
|
|
143
|
+
], le = 500, ue = 5e3, k = 50, $e = k * 2, de = "tlog_mode", Qe = "qa", Be = () => {
|
|
144
|
+
if (sessionStorage.getItem(ce) === "true")
|
|
145
|
+
return !0;
|
|
146
|
+
const e = new URLSearchParams(window.location.search), r = e.get(de) === Qe;
|
|
147
|
+
if (r) {
|
|
148
|
+
sessionStorage.setItem(ce, "true"), e.delete(de);
|
|
149
|
+
const n = e.toString(), i = `${window.location.pathname}${n ? "?" + n : ""}${window.location.hash}`;
|
|
150
|
+
try {
|
|
151
|
+
window.history.replaceState({}, "", i);
|
|
152
|
+
} catch (a) {
|
|
153
|
+
o("warn", "History API not available, cannot replace URL", { error: a });
|
|
154
|
+
}
|
|
155
|
+
console.log(
|
|
156
|
+
"%c[TraceLog] QA Mode ACTIVE",
|
|
157
|
+
"background: #ff9800; color: white; font-weight: bold; padding: 2px 8px; border-radius: 3px;"
|
|
158
|
+
);
|
|
150
159
|
}
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
const r = navigator;
|
|
160
|
-
if (r.userAgentData && typeof r.userAgentData.mobile == "boolean") {
|
|
161
|
-
if (a.debug("DeviceDetector", "Using modern User-Agent Client Hints API", {
|
|
162
|
-
mobile: r.userAgentData.mobile,
|
|
163
|
-
platform: r.userAgentData.platform
|
|
164
|
-
}), r.userAgentData.platform && /ipad|tablet/i.test(r.userAgentData.platform))
|
|
165
|
-
return a.debug("DeviceDetector", "Device detected as tablet via platform hint"), I.Tablet;
|
|
166
|
-
const u = r.userAgentData.mobile ? I.Mobile : I.Desktop;
|
|
167
|
-
return a.debug("DeviceDetector", "Device detected via User-Agent hints", { result: u }), u;
|
|
168
|
-
}
|
|
169
|
-
a.debug("DeviceDetector", "Using fallback detection methods"), pt();
|
|
170
|
-
const e = window.innerWidth, t = te?.matches ?? !1, n = ze?.matches ?? !1, s = "ontouchstart" in window || navigator.maxTouchPoints > 0, i = navigator.userAgent.toLowerCase(), o = /mobile|android|iphone|ipod|blackberry|iemobile|opera mini/.test(i), c = /tablet|ipad|android(?!.*mobile)/.test(i), l = {
|
|
171
|
-
width: e,
|
|
172
|
-
hasCoarsePointer: t,
|
|
173
|
-
hasNoHover: n,
|
|
174
|
-
hasTouchSupport: s,
|
|
175
|
-
isMobileUA: o,
|
|
176
|
-
isTabletUA: c,
|
|
177
|
-
maxTouchPoints: navigator.maxTouchPoints
|
|
178
|
-
};
|
|
179
|
-
return e <= 767 || o && s ? (a.debug("DeviceDetector", "Device detected as mobile", l), I.Mobile) : e >= 768 && e <= 1024 || c || t && n && s ? (a.debug("DeviceDetector", "Device detected as tablet", l), I.Tablet) : (a.debug("DeviceDetector", "Device detected as desktop", l), I.Desktop);
|
|
180
|
-
} catch (r) {
|
|
181
|
-
return a.warn("DeviceDetector", "Device detection failed, defaulting to desktop", {
|
|
182
|
-
error: r instanceof Error ? r.message : r
|
|
183
|
-
}), I.Desktop;
|
|
184
|
-
}
|
|
185
|
-
}, Le = () => {
|
|
186
|
-
a.debug("UTMParams", "Extracting UTM parameters from URL", {
|
|
187
|
-
url: window.location.href,
|
|
188
|
-
search: window.location.search
|
|
189
|
-
});
|
|
190
|
-
const r = new URLSearchParams(window.location.search), e = {};
|
|
191
|
-
at.forEach((n) => {
|
|
192
|
-
const s = r.get(n);
|
|
193
|
-
if (s) {
|
|
194
|
-
const i = n.split("utm_")[1];
|
|
195
|
-
e[i] = s, a.debug("UTMParams", "Found UTM parameter", { param: n, key: i, value: s });
|
|
160
|
+
return r;
|
|
161
|
+
}, he = () => {
|
|
162
|
+
const s = new URLSearchParams(window.location.search), e = {};
|
|
163
|
+
return be.forEach((r) => {
|
|
164
|
+
const n = s.get(r);
|
|
165
|
+
if (n) {
|
|
166
|
+
const i = r.split("utm_")[1];
|
|
167
|
+
e[i] = n;
|
|
196
168
|
}
|
|
197
|
-
});
|
|
198
|
-
|
|
199
|
-
return t ? a.debug("UTMParams", "UTM parameters extracted successfully", {
|
|
200
|
-
parameterCount: Object.keys(t).length,
|
|
201
|
-
parameters: Object.keys(t)
|
|
202
|
-
}) : a.debug("UTMParams", "No UTM parameters found in URL"), t;
|
|
203
|
-
}, Et = () => typeof crypto < "u" && crypto.randomUUID ? crypto.randomUUID() : "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, (r) => {
|
|
169
|
+
}), Object.keys(e).length ? e : void 0;
|
|
170
|
+
}, je = () => typeof crypto < "u" && crypto.randomUUID ? crypto.randomUUID() : "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, (s) => {
|
|
204
171
|
const e = Math.random() * 16 | 0;
|
|
205
|
-
return (
|
|
206
|
-
})
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
super(e, "PROJECT_ID_INVALID", t);
|
|
172
|
+
return (s === "x" ? e : e & 3 | 8).toString(16);
|
|
173
|
+
}), Xe = () => {
|
|
174
|
+
const s = Date.now();
|
|
175
|
+
let e = "";
|
|
176
|
+
try {
|
|
177
|
+
if (typeof crypto < "u" && crypto.getRandomValues) {
|
|
178
|
+
const t = crypto.getRandomValues(new Uint8Array(4));
|
|
179
|
+
t && (e = Array.from(t, (r) => r.toString(16).padStart(2, "0")).join(""));
|
|
180
|
+
}
|
|
181
|
+
} catch {
|
|
216
182
|
}
|
|
217
|
-
}
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
183
|
+
return e || (e = Math.floor(Math.random() * 4294967295).toString(16).padStart(8, "0")), `${s}-${e}`;
|
|
184
|
+
}, fe = (s, e = !1) => {
|
|
185
|
+
try {
|
|
186
|
+
const t = new URL(s), r = t.protocol === "https:", n = t.protocol === "http:";
|
|
187
|
+
return r || e && n;
|
|
188
|
+
} catch {
|
|
189
|
+
return !1;
|
|
221
190
|
}
|
|
222
|
-
}
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
191
|
+
}, We = (s) => {
|
|
192
|
+
if (s.integrations?.tracelog?.projectId) {
|
|
193
|
+
const r = new URL(window.location.href).hostname.split(".");
|
|
194
|
+
if (r.length === 0)
|
|
195
|
+
throw new Error("Invalid URL");
|
|
196
|
+
const n = s.integrations.tracelog.projectId, i = r.slice(-2).join("."), a = `https://${n}.${i}`;
|
|
197
|
+
if (!fe(a))
|
|
198
|
+
throw new Error("Invalid URL");
|
|
199
|
+
return a;
|
|
200
|
+
}
|
|
201
|
+
if (s.integrations?.custom?.apiUrl) {
|
|
202
|
+
const e = s.integrations.custom.apiUrl, t = s.integrations?.custom?.allowHttp ?? !1;
|
|
203
|
+
if (!fe(e, t))
|
|
204
|
+
throw new Error("Invalid URL");
|
|
205
|
+
return e;
|
|
226
206
|
}
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
207
|
+
return "";
|
|
208
|
+
}, Y = (s, e = []) => {
|
|
209
|
+
try {
|
|
210
|
+
const t = new URL(s), r = t.searchParams;
|
|
211
|
+
let n = !1;
|
|
212
|
+
const i = [];
|
|
213
|
+
return e.forEach((c) => {
|
|
214
|
+
r.has(c) && (r.delete(c), n = !0, i.push(c));
|
|
215
|
+
}), !n && s.includes("?") ? s : (t.search = r.toString(), t.toString());
|
|
216
|
+
} catch (t) {
|
|
217
|
+
return o("warn", "URL normalization failed, returning original", { error: t, data: { url: s.slice(0, 100) } }), s;
|
|
231
218
|
}
|
|
232
|
-
}
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
219
|
+
}, ge = (s) => {
|
|
220
|
+
if (!s || typeof s != "string" || s.trim().length === 0)
|
|
221
|
+
return "";
|
|
222
|
+
let e = s;
|
|
223
|
+
s.length > 1e3 && (e = s.slice(0, Math.max(0, 1e3)));
|
|
224
|
+
let t = 0;
|
|
225
|
+
for (const n of Oe) {
|
|
226
|
+
const i = e;
|
|
227
|
+
e = e.replace(n, ""), i !== e && t++;
|
|
228
|
+
}
|
|
229
|
+
return t > 0 && o("warn", "XSS patterns detected and removed", {
|
|
230
|
+
data: {
|
|
231
|
+
patternMatches: t,
|
|
232
|
+
originalValue: s.slice(0, 100)
|
|
233
|
+
}
|
|
234
|
+
}), e = e.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'").replaceAll("/", "/"), e.trim();
|
|
235
|
+
}, K = (s, e = 0) => {
|
|
236
|
+
if (e > 3 || s == null)
|
|
237
|
+
return null;
|
|
238
|
+
if (typeof s == "string")
|
|
239
|
+
return ge(s);
|
|
240
|
+
if (typeof s == "number")
|
|
241
|
+
return !Number.isFinite(s) || s < -Number.MAX_SAFE_INTEGER || s > Number.MAX_SAFE_INTEGER ? 0 : s;
|
|
242
|
+
if (typeof s == "boolean")
|
|
243
|
+
return s;
|
|
244
|
+
if (Array.isArray(s))
|
|
245
|
+
return s.slice(0, 100).map((n) => K(n, e + 1)).filter((n) => n !== null);
|
|
246
|
+
if (typeof s == "object") {
|
|
247
|
+
const t = {}, n = Object.entries(s).slice(0, 20);
|
|
248
|
+
for (const [i, a] of n) {
|
|
249
|
+
const c = ge(i);
|
|
250
|
+
if (c) {
|
|
251
|
+
const l = K(a, e + 1);
|
|
252
|
+
l !== null && (t[c] = l);
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
return t;
|
|
236
256
|
}
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
if (
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
if (r.scrollContainerSelectors !== void 0 && bt(r.scrollContainerSelectors), r.integrations && Mt(r.integrations), r.sensitiveQueryParams !== void 0) {
|
|
260
|
-
if (!Array.isArray(r.sensitiveQueryParams))
|
|
261
|
-
throw a.clientError("ConfigValidation", "Sensitive query params must be an array", {
|
|
262
|
-
provided: r.sensitiveQueryParams,
|
|
263
|
-
type: typeof r.sensitiveQueryParams
|
|
264
|
-
}), new A(y.INVALID_SENSITIVE_QUERY_PARAMS, "config");
|
|
265
|
-
for (const e of r.sensitiveQueryParams)
|
|
257
|
+
return null;
|
|
258
|
+
}, Ye = (s) => {
|
|
259
|
+
if (typeof s != "object" || s === null)
|
|
260
|
+
return {};
|
|
261
|
+
try {
|
|
262
|
+
const e = K(s);
|
|
263
|
+
return typeof e == "object" && e !== null ? e : {};
|
|
264
|
+
} catch (e) {
|
|
265
|
+
const t = e instanceof Error ? e.message : String(e);
|
|
266
|
+
throw new Error(`[TraceLog] Metadata sanitization failed: ${t}`);
|
|
267
|
+
}
|
|
268
|
+
}, Ke = (s) => {
|
|
269
|
+
if (!s || typeof s != "object")
|
|
270
|
+
throw new y("Configuration must be an object", "config");
|
|
271
|
+
if (s.sessionTimeout !== void 0 && (typeof s.sessionTimeout != "number" || s.sessionTimeout < 3e4 || s.sessionTimeout > 864e5))
|
|
272
|
+
throw new Pe(m.INVALID_SESSION_TIMEOUT, "config");
|
|
273
|
+
if (s.globalMetadata !== void 0 && (typeof s.globalMetadata != "object" || s.globalMetadata === null))
|
|
274
|
+
throw new y(m.INVALID_GLOBAL_METADATA, "config");
|
|
275
|
+
if (s.scrollContainerSelectors !== void 0 && Ze(s.scrollContainerSelectors), s.integrations && Je(s.integrations), s.sensitiveQueryParams !== void 0) {
|
|
276
|
+
if (!Array.isArray(s.sensitiveQueryParams))
|
|
277
|
+
throw new y(m.INVALID_SENSITIVE_QUERY_PARAMS, "config");
|
|
278
|
+
for (const e of s.sensitiveQueryParams)
|
|
266
279
|
if (typeof e != "string")
|
|
267
|
-
throw
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
expected: "0-1"
|
|
276
|
-
}), new _t(y.INVALID_ERROR_SAMPLING_RATE, "config");
|
|
277
|
-
}, At = (r) => {
|
|
278
|
-
if (r.includes("<") || r.includes(">") || /on\w+\s*=/i.test(r) || !/^[a-zA-Z0-9\-_#.[\]="':, >+~*()]+$/.test(r))
|
|
280
|
+
throw new y("All sensitive query params must be strings", "config");
|
|
281
|
+
}
|
|
282
|
+
if (s.errorSampling !== void 0 && (typeof s.errorSampling != "number" || s.errorSampling < 0 || s.errorSampling > 1))
|
|
283
|
+
throw new oe(m.INVALID_ERROR_SAMPLING_RATE, "config");
|
|
284
|
+
if (s.samplingRate !== void 0 && (typeof s.samplingRate != "number" || s.samplingRate < 0 || s.samplingRate > 1))
|
|
285
|
+
throw new oe(m.INVALID_SAMPLING_RATE, "config");
|
|
286
|
+
}, qe = (s) => {
|
|
287
|
+
if (s.includes("<") || s.includes(">") || /on\w+\s*=/i.test(s) || !/^[a-zA-Z0-9\-_#.[\]="':, >+~*()]+$/.test(s))
|
|
279
288
|
return !1;
|
|
280
289
|
let t = 0;
|
|
281
|
-
for (const
|
|
282
|
-
if (
|
|
290
|
+
for (const n of s)
|
|
291
|
+
if (n === "(" && t++, n === ")" && t--, t < 0) return !1;
|
|
283
292
|
if (t !== 0) return !1;
|
|
284
|
-
let
|
|
285
|
-
for (const
|
|
286
|
-
if (
|
|
287
|
-
return
|
|
288
|
-
},
|
|
289
|
-
const e = Array.isArray(
|
|
293
|
+
let r = 0;
|
|
294
|
+
for (const n of s)
|
|
295
|
+
if (n === "[" && r++, n === "]" && r--, r < 0) return !1;
|
|
296
|
+
return r === 0;
|
|
297
|
+
}, Ze = (s) => {
|
|
298
|
+
const e = Array.isArray(s) ? s : [s];
|
|
290
299
|
for (const t of e) {
|
|
291
300
|
if (typeof t != "string" || t.trim() === "")
|
|
292
|
-
throw
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
throw a.clientError("ConfigValidation", "Invalid or potentially unsafe CSS selector", {
|
|
299
|
-
selector: t,
|
|
300
|
-
reason: "Failed security validation"
|
|
301
|
-
}), new A("Invalid or potentially unsafe CSS selector", "config");
|
|
302
|
-
}
|
|
303
|
-
}, Mt = (r) => {
|
|
304
|
-
if (r && r.googleAnalytics) {
|
|
305
|
-
if (!r.googleAnalytics.measurementId || typeof r.googleAnalytics.measurementId != "string" || r.googleAnalytics.measurementId.trim() === "")
|
|
306
|
-
throw a.clientError("ConfigValidation", "Invalid Google Analytics measurement ID", {
|
|
307
|
-
provided: r.googleAnalytics.measurementId,
|
|
308
|
-
type: typeof r.googleAnalytics.measurementId
|
|
309
|
-
}), new Ne(y.INVALID_GOOGLE_ANALYTICS_ID, "config");
|
|
310
|
-
const e = r.googleAnalytics.measurementId.trim();
|
|
311
|
-
if (!e.match(/^(G-|UA-)/))
|
|
312
|
-
throw a.clientError("ConfigValidation", 'Google Analytics measurement ID must start with "G-" or "UA-"', {
|
|
313
|
-
provided: e
|
|
314
|
-
}), new Ne('Google Analytics measurement ID must start with "G-" or "UA-"', "config");
|
|
315
|
-
}
|
|
316
|
-
}, Rt = (r) => {
|
|
317
|
-
wt(r);
|
|
318
|
-
const e = {
|
|
319
|
-
...r,
|
|
320
|
-
id: r.id.trim(),
|
|
321
|
-
globalMetadata: r.globalMetadata ?? {},
|
|
322
|
-
sensitiveQueryParams: r.sensitiveQueryParams ?? []
|
|
323
|
-
};
|
|
324
|
-
if (!e.id)
|
|
325
|
-
throw a.clientError("ConfigValidation", "Project ID is empty after trimming whitespace", {
|
|
326
|
-
originalId: r.id,
|
|
327
|
-
normalizedId: e.id
|
|
328
|
-
}), new ne(y.PROJECT_ID_EMPTY_AFTER_TRIM, "config");
|
|
329
|
-
return e;
|
|
330
|
-
}, Ce = (r) => {
|
|
331
|
-
if (!r || typeof r != "string" || r.trim().length === 0)
|
|
332
|
-
return a.debug("Sanitize", "String sanitization skipped - empty or invalid input", { value: r, type: typeof r }), "";
|
|
333
|
-
const e = r.length;
|
|
334
|
-
let t = r;
|
|
335
|
-
r.length > T && (t = r.slice(0, Math.max(0, T)), a.warn("Sanitize", "String truncated due to length limit", {
|
|
336
|
-
originalLength: e,
|
|
337
|
-
maxLength: T,
|
|
338
|
-
truncatedLength: t.length
|
|
339
|
-
}));
|
|
340
|
-
let n = 0;
|
|
341
|
-
for (const i of He) {
|
|
342
|
-
const o = t;
|
|
343
|
-
t = t.replace(i, ""), o !== t && n++;
|
|
344
|
-
}
|
|
345
|
-
n > 0 && a.warn("Sanitize", "XSS patterns detected and removed", {
|
|
346
|
-
patternMatches: n,
|
|
347
|
-
originalValue: r.slice(0, 100)
|
|
348
|
-
// Log first 100 chars for debugging
|
|
349
|
-
}), t = t.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'").replaceAll("/", "/");
|
|
350
|
-
const s = t.trim();
|
|
351
|
-
return (e > 50 || n > 0) && a.debug("Sanitize", "String sanitization completed", {
|
|
352
|
-
originalLength: e,
|
|
353
|
-
sanitizedLength: s.length,
|
|
354
|
-
xssPatternMatches: n,
|
|
355
|
-
wasTruncated: e > T
|
|
356
|
-
}), s;
|
|
357
|
-
}, Lt = (r) => {
|
|
358
|
-
if (typeof r != "string")
|
|
359
|
-
return "";
|
|
360
|
-
r.length > T && (r = r.slice(0, Math.max(0, T)));
|
|
361
|
-
let e = r;
|
|
362
|
-
for (const t of He)
|
|
363
|
-
e = e.replace(t, "");
|
|
364
|
-
return e = e.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'"), e.trim();
|
|
365
|
-
}, U = (r, e = 0) => {
|
|
366
|
-
if (e > Ae)
|
|
367
|
-
return a.warn("Sanitize", "Maximum object depth exceeded during sanitization", {
|
|
368
|
-
depth: e,
|
|
369
|
-
maxDepth: Ae
|
|
370
|
-
}), null;
|
|
371
|
-
if (r == null)
|
|
372
|
-
return null;
|
|
373
|
-
if (typeof r == "string")
|
|
374
|
-
return Ce(r);
|
|
375
|
-
if (typeof r == "number")
|
|
376
|
-
return !Number.isFinite(r) || r < -Number.MAX_SAFE_INTEGER || r > Number.MAX_SAFE_INTEGER ? (a.warn("Sanitize", "Invalid number sanitized to 0", { value: r, isFinite: Number.isFinite(r) }), 0) : r;
|
|
377
|
-
if (typeof r == "boolean")
|
|
378
|
-
return r;
|
|
379
|
-
if (Array.isArray(r)) {
|
|
380
|
-
const t = r.length, n = r.slice(0, q);
|
|
381
|
-
t > q && a.warn("Sanitize", "Array truncated due to length limit", {
|
|
382
|
-
originalLength: t,
|
|
383
|
-
maxLength: q,
|
|
384
|
-
depth: e
|
|
385
|
-
});
|
|
386
|
-
const s = n.map((i) => U(i, e + 1)).filter((i) => i !== null);
|
|
387
|
-
return t > 0 && s.length === 0 && a.warn("Sanitize", "All array items were filtered out during sanitization", { originalLength: t, depth: e }), s;
|
|
388
|
-
}
|
|
389
|
-
if (typeof r == "object") {
|
|
390
|
-
const t = {}, n = Object.entries(r), s = n.length, i = n.slice(0, 20);
|
|
391
|
-
s > 20 && a.warn("Sanitize", "Object keys truncated due to limit", {
|
|
392
|
-
originalKeys: s,
|
|
393
|
-
maxKeys: 20,
|
|
394
|
-
depth: e
|
|
395
|
-
});
|
|
396
|
-
let o = 0;
|
|
397
|
-
for (const [c, l] of i) {
|
|
398
|
-
const u = Ce(c);
|
|
399
|
-
if (u) {
|
|
400
|
-
const h = U(l, e + 1);
|
|
401
|
-
h !== null ? t[u] = h : o++;
|
|
402
|
-
} else
|
|
403
|
-
o++;
|
|
404
|
-
}
|
|
405
|
-
return o > 0 && a.debug("Sanitize", "Object properties filtered during sanitization", {
|
|
406
|
-
filteredKeysCount: o,
|
|
407
|
-
remainingKeys: Object.keys(t).length,
|
|
408
|
-
depth: e
|
|
409
|
-
}), t;
|
|
410
|
-
}
|
|
411
|
-
return a.debug("Sanitize", "Unknown value type sanitized to null", { type: typeof r, depth: e }), null;
|
|
412
|
-
}, Nt = (r) => {
|
|
413
|
-
a.debug("Sanitize", "Starting API config sanitization");
|
|
414
|
-
const e = {};
|
|
415
|
-
if (typeof r != "object" || r === null)
|
|
416
|
-
return a.warn("Sanitize", "API config data is not an object", { data: r, type: typeof r }), e;
|
|
417
|
-
try {
|
|
418
|
-
const t = Object.keys(r);
|
|
419
|
-
let n = 0, s = 0;
|
|
420
|
-
for (const i of t)
|
|
421
|
-
if (lt.has(i)) {
|
|
422
|
-
const o = r[i];
|
|
423
|
-
if (i === "excludedUrlPaths") {
|
|
424
|
-
const c = Array.isArray(o) ? o : typeof o == "string" ? [o] : [], l = c.length;
|
|
425
|
-
e.excludedUrlPaths = c.map((h) => Lt(String(h))).filter(Boolean);
|
|
426
|
-
const u = l - e.excludedUrlPaths.length;
|
|
427
|
-
u > 0 && a.warn("Sanitize", "Some excluded URL paths were filtered during sanitization", {
|
|
428
|
-
originalCount: l,
|
|
429
|
-
filteredCount: u
|
|
430
|
-
});
|
|
431
|
-
} else if (i === "tags")
|
|
432
|
-
Array.isArray(o) ? (e.tags = o, a.debug("Sanitize", "Tags processed", { count: o.length })) : a.warn("Sanitize", "Tags value is not an array", { value: o, type: typeof o });
|
|
433
|
-
else if (i === "samplingRate") {
|
|
434
|
-
const c = U(o);
|
|
435
|
-
typeof c == "number" && (e.samplingRate = c);
|
|
436
|
-
} else {
|
|
437
|
-
const c = U(o);
|
|
438
|
-
c !== null ? e[i] = c : a.warn("Sanitize", "API config value sanitized to null", { key: i, originalValue: o });
|
|
301
|
+
throw o("error", "Invalid scroll container selector", {
|
|
302
|
+
showToClient: !0,
|
|
303
|
+
data: {
|
|
304
|
+
selector: t,
|
|
305
|
+
type: typeof t,
|
|
306
|
+
isEmpty: t === "" || typeof t == "string" && t.trim() === ""
|
|
439
307
|
}
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
}
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
308
|
+
}), new y(m.INVALID_SCROLL_CONTAINER_SELECTORS, "config");
|
|
309
|
+
if (!qe(t))
|
|
310
|
+
throw o("error", "Invalid or potentially unsafe CSS selector", {
|
|
311
|
+
showToClient: !0,
|
|
312
|
+
data: {
|
|
313
|
+
selector: t,
|
|
314
|
+
reason: "Failed security validation"
|
|
315
|
+
}
|
|
316
|
+
}), new y("Invalid or potentially unsafe CSS selector", "config");
|
|
317
|
+
}
|
|
318
|
+
}, Je = (s) => {
|
|
319
|
+
if (s) {
|
|
320
|
+
if (s.tracelog && (!s.tracelog.projectId || typeof s.tracelog.projectId != "string" || s.tracelog.projectId.trim() === ""))
|
|
321
|
+
throw new v(m.INVALID_TRACELOG_PROJECT_ID, "config");
|
|
322
|
+
if (s.custom) {
|
|
323
|
+
if (!s.custom.apiUrl || typeof s.custom.apiUrl != "string" || s.custom.apiUrl.trim() === "")
|
|
324
|
+
throw new v(m.INVALID_CUSTOM_API_URL, "config");
|
|
325
|
+
if (s.custom.allowHttp !== void 0 && typeof s.custom.allowHttp != "boolean")
|
|
326
|
+
throw new v("allowHttp must be a boolean", "config");
|
|
327
|
+
const e = s.custom.apiUrl.trim();
|
|
328
|
+
if (!e.startsWith("http://") && !e.startsWith("https://"))
|
|
329
|
+
throw new v('Custom API URL must start with "http://" or "https://"', "config");
|
|
330
|
+
if (!(s.custom.allowHttp ?? !1) && e.startsWith("http://"))
|
|
331
|
+
throw new v(
|
|
332
|
+
"Custom API URL must use HTTPS in production. Set allowHttp: true in integration config to allow HTTP (not recommended)",
|
|
333
|
+
"config"
|
|
334
|
+
);
|
|
335
|
+
}
|
|
336
|
+
if (s.googleAnalytics) {
|
|
337
|
+
if (!s.googleAnalytics.measurementId || typeof s.googleAnalytics.measurementId != "string" || s.googleAnalytics.measurementId.trim() === "")
|
|
338
|
+
throw new v(m.INVALID_GOOGLE_ANALYTICS_ID, "config");
|
|
339
|
+
if (!s.googleAnalytics.measurementId.trim().match(/^(G-|UA-)/))
|
|
340
|
+
throw new v('Google Analytics measurement ID must start with "G-" or "UA-"', "config");
|
|
341
|
+
}
|
|
453
342
|
}
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
343
|
+
}, et = (s) => {
|
|
344
|
+
Ke(s);
|
|
345
|
+
const e = {
|
|
346
|
+
...s,
|
|
347
|
+
sessionTimeout: s.sessionTimeout ?? 9e5,
|
|
348
|
+
globalMetadata: s.globalMetadata ?? {},
|
|
349
|
+
sensitiveQueryParams: s.sensitiveQueryParams ?? [],
|
|
350
|
+
errorSampling: s.errorSampling ?? 1,
|
|
351
|
+
samplingRate: s.samplingRate ?? 1
|
|
352
|
+
};
|
|
353
|
+
return e.integrations?.custom && (e.integrations.custom = {
|
|
354
|
+
...e.integrations.custom,
|
|
355
|
+
allowHttp: e.integrations.custom.allowHttp ?? !1
|
|
356
|
+
}), e;
|
|
357
|
+
}, tt = (s) => {
|
|
358
|
+
if (typeof s == "string")
|
|
359
|
+
return !0;
|
|
360
|
+
if (typeof s == "object" && s !== null && !Array.isArray(s)) {
|
|
361
|
+
const e = Object.entries(s);
|
|
362
|
+
if (e.length > 20)
|
|
363
|
+
return !1;
|
|
364
|
+
for (const [, t] of e) {
|
|
365
|
+
if (t == null)
|
|
366
|
+
continue;
|
|
367
|
+
const r = typeof t;
|
|
368
|
+
if (r !== "string" && r !== "number" && r !== "boolean")
|
|
369
|
+
return !1;
|
|
370
|
+
}
|
|
371
|
+
return !0;
|
|
472
372
|
}
|
|
473
|
-
|
|
474
|
-
|
|
373
|
+
return !1;
|
|
374
|
+
}, rt = (s) => {
|
|
375
|
+
if (typeof s != "object" || s === null)
|
|
475
376
|
return !1;
|
|
476
|
-
for (const e of Object.values(
|
|
377
|
+
for (const e of Object.values(s)) {
|
|
477
378
|
if (e == null)
|
|
478
379
|
continue;
|
|
479
380
|
const t = typeof e;
|
|
480
381
|
if (!(t === "string" || t === "number" || t === "boolean")) {
|
|
481
382
|
if (Array.isArray(e)) {
|
|
482
|
-
if (
|
|
383
|
+
if (e.length === 0)
|
|
384
|
+
continue;
|
|
385
|
+
if (typeof e[0] == "string") {
|
|
386
|
+
if (!e.every((i) => typeof i == "string"))
|
|
387
|
+
return !1;
|
|
388
|
+
} else if (!e.every((i) => tt(i)))
|
|
483
389
|
return !1;
|
|
484
390
|
continue;
|
|
485
391
|
}
|
|
@@ -487,407 +393,146 @@ const wt = (r) => {
|
|
|
487
393
|
}
|
|
488
394
|
}
|
|
489
395
|
return !0;
|
|
490
|
-
},
|
|
396
|
+
}, st = (s) => typeof s != "string" ? {
|
|
491
397
|
valid: !1,
|
|
492
398
|
error: "Event name must be a string"
|
|
493
|
-
} :
|
|
399
|
+
} : s.length === 0 ? {
|
|
494
400
|
valid: !1,
|
|
495
401
|
error: "Event name cannot be empty"
|
|
496
|
-
} :
|
|
402
|
+
} : s.length > 120 ? {
|
|
497
403
|
valid: !1,
|
|
498
|
-
error:
|
|
499
|
-
} :
|
|
404
|
+
error: "Event name is too long (max 120 characters)"
|
|
405
|
+
} : s.includes("<") || s.includes(">") || s.includes("&") ? {
|
|
500
406
|
valid: !1,
|
|
501
407
|
error: "Event name contains invalid characters"
|
|
502
|
-
} : ["constructor", "prototype", "__proto__", "eval", "function", "var", "let", "const"].includes(
|
|
408
|
+
} : ["constructor", "prototype", "__proto__", "eval", "function", "var", "let", "const"].includes(s.toLowerCase()) ? {
|
|
503
409
|
valid: !1,
|
|
504
410
|
error: "Event name cannot be a reserved word"
|
|
505
|
-
} : { valid: !0 },
|
|
506
|
-
const
|
|
507
|
-
if (!
|
|
411
|
+
} : { valid: !0 }, Se = (s, e, t) => {
|
|
412
|
+
const r = Ye(e), n = `${t} "${s}" metadata error`;
|
|
413
|
+
if (!rt(r))
|
|
508
414
|
return {
|
|
509
415
|
valid: !1,
|
|
510
|
-
error: `${
|
|
416
|
+
error: `${n}: object has invalid types. Valid types are string, number, boolean or string arrays.`
|
|
511
417
|
};
|
|
512
418
|
let i;
|
|
513
419
|
try {
|
|
514
|
-
i = JSON.stringify(
|
|
420
|
+
i = JSON.stringify(r);
|
|
515
421
|
} catch {
|
|
516
422
|
return {
|
|
517
423
|
valid: !1,
|
|
518
|
-
error: `${
|
|
424
|
+
error: `${n}: object contains circular references or cannot be serialized.`
|
|
519
425
|
};
|
|
520
426
|
}
|
|
521
|
-
if (i.length >
|
|
427
|
+
if (i.length > 8192)
|
|
522
428
|
return {
|
|
523
429
|
valid: !1,
|
|
524
|
-
error: `${
|
|
430
|
+
error: `${n}: object is too large (max ${8192 / 1024} KB).`
|
|
525
431
|
};
|
|
526
|
-
if (Object.keys(
|
|
432
|
+
if (Object.keys(r).length > 10)
|
|
527
433
|
return {
|
|
528
434
|
valid: !1,
|
|
529
|
-
error: `${
|
|
435
|
+
error: `${n}: object has too many keys (max 10 keys).`
|
|
530
436
|
};
|
|
531
|
-
for (const [c, l] of Object.entries(
|
|
437
|
+
for (const [c, l] of Object.entries(r)) {
|
|
532
438
|
if (Array.isArray(l)) {
|
|
533
|
-
if (l.length >
|
|
439
|
+
if (l.length > 10)
|
|
534
440
|
return {
|
|
535
441
|
valid: !1,
|
|
536
|
-
error: `${
|
|
442
|
+
error: `${n}: array property "${c}" is too large (max 10 items).`
|
|
537
443
|
};
|
|
538
444
|
for (const u of l)
|
|
539
445
|
if (typeof u == "string" && u.length > 500)
|
|
540
446
|
return {
|
|
541
447
|
valid: !1,
|
|
542
|
-
error: `${
|
|
448
|
+
error: `${n}: array property "${c}" contains strings that are too long (max 500 characters).`
|
|
543
449
|
};
|
|
544
450
|
}
|
|
545
|
-
if (typeof l == "string" && l.length >
|
|
451
|
+
if (typeof l == "string" && l.length > 1e3)
|
|
546
452
|
return {
|
|
547
453
|
valid: !1,
|
|
548
|
-
error: `${
|
|
454
|
+
error: `${n}: property "${c}" is too long (max 1000 characters).`
|
|
549
455
|
};
|
|
550
456
|
}
|
|
551
457
|
return {
|
|
552
458
|
valid: !0,
|
|
553
|
-
sanitizedMetadata:
|
|
459
|
+
sanitizedMetadata: r
|
|
554
460
|
};
|
|
555
|
-
},
|
|
461
|
+
}, nt = (s, e, t) => {
|
|
556
462
|
if (Array.isArray(e)) {
|
|
557
|
-
const
|
|
463
|
+
const r = [], n = `${t} "${s}" metadata error`;
|
|
558
464
|
for (let i = 0; i < e.length; i++) {
|
|
559
|
-
const
|
|
560
|
-
if (typeof
|
|
465
|
+
const a = e[i];
|
|
466
|
+
if (typeof a != "object" || a === null || Array.isArray(a))
|
|
561
467
|
return {
|
|
562
468
|
valid: !1,
|
|
563
|
-
error: `${
|
|
469
|
+
error: `${n}: array item at index ${i} must be an object.`
|
|
564
470
|
};
|
|
565
|
-
const c =
|
|
471
|
+
const c = Se(s, a, t);
|
|
566
472
|
if (!c.valid)
|
|
567
473
|
return {
|
|
568
474
|
valid: !1,
|
|
569
|
-
error: `${
|
|
475
|
+
error: `${n}: array item at index ${i} is invalid: ${c.error}`
|
|
570
476
|
};
|
|
571
|
-
c.sanitizedMetadata &&
|
|
477
|
+
c.sanitizedMetadata && r.push(c.sanitizedMetadata);
|
|
572
478
|
}
|
|
573
479
|
return {
|
|
574
480
|
valid: !0,
|
|
575
|
-
sanitizedMetadata:
|
|
481
|
+
sanitizedMetadata: r
|
|
576
482
|
};
|
|
577
483
|
}
|
|
578
|
-
return
|
|
579
|
-
},
|
|
580
|
-
const t =
|
|
484
|
+
return Se(s, e, t);
|
|
485
|
+
}, it = (s, e) => {
|
|
486
|
+
const t = st(s);
|
|
581
487
|
if (!t.valid)
|
|
582
|
-
return
|
|
488
|
+
return o("error", "Event name validation failed", {
|
|
489
|
+
showToClient: !0,
|
|
490
|
+
data: { eventName: s, error: t.error }
|
|
491
|
+
}), t;
|
|
583
492
|
if (!e)
|
|
584
493
|
return { valid: !0 };
|
|
585
|
-
const
|
|
586
|
-
return
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
try {
|
|
592
|
-
const t = new URL(r), n = t.protocol === "https:", s = t.protocol === "http:";
|
|
593
|
-
return n || e && s;
|
|
594
|
-
} catch {
|
|
595
|
-
return !1;
|
|
596
|
-
}
|
|
597
|
-
}, xt = (r, e = !1) => {
|
|
598
|
-
const t = new URL(window.location.href), n = t.hostname, s = n.split(".");
|
|
599
|
-
if (s.length === 0)
|
|
600
|
-
throw a.clientError("URLUtils", "Invalid hostname - no domain parts found", { hostname: n }), new Error("Invalid URL");
|
|
601
|
-
const i = s.slice(-2).join("."), c = `${e && t.protocol === "http:" ? "http" : "https"}://${r}.${i}`;
|
|
602
|
-
if (!se(c, e))
|
|
603
|
-
throw a.clientError("URLUtils", "Generated API URL failed validation", {
|
|
604
|
-
apiUrl: c,
|
|
605
|
-
allowHttp: e
|
|
606
|
-
}), new Error("Invalid URL");
|
|
607
|
-
return c;
|
|
608
|
-
}, ie = (r, e = []) => {
|
|
609
|
-
try {
|
|
610
|
-
const t = new URL(r), n = t.searchParams, s = Array.from(n.keys()).length;
|
|
611
|
-
let i = !1;
|
|
612
|
-
const o = [];
|
|
613
|
-
return e.forEach((l) => {
|
|
614
|
-
n.has(l) && (n.delete(l), i = !0, o.push(l));
|
|
615
|
-
}), i && a.debug("URLUtils", "Sensitive parameters removed from URL", {
|
|
616
|
-
removedParams: o,
|
|
617
|
-
originalParamCount: s,
|
|
618
|
-
finalParamCount: Array.from(n.keys()).length
|
|
619
|
-
}), !i && r.includes("?") ? r : (t.search = n.toString(), t.toString());
|
|
620
|
-
} catch (t) {
|
|
621
|
-
return a.warn("URLUtils", "URL normalization failed, returning original", {
|
|
622
|
-
url: r.slice(0, 100),
|
|
623
|
-
error: t instanceof Error ? t.message : t
|
|
624
|
-
}), r;
|
|
625
|
-
}
|
|
626
|
-
}, Ut = (r, e = []) => {
|
|
627
|
-
if (e.length === 0)
|
|
628
|
-
return !1;
|
|
629
|
-
let t;
|
|
630
|
-
try {
|
|
631
|
-
const l = new URL(r, window.location.origin);
|
|
632
|
-
t = l.pathname + (l.hash ?? "");
|
|
633
|
-
} catch (l) {
|
|
634
|
-
return a.warn("URLUtils", "Failed to parse URL for path exclusion check", {
|
|
635
|
-
url: r.slice(0, 100),
|
|
636
|
-
error: l instanceof Error ? l.message : l
|
|
637
|
-
}), !1;
|
|
638
|
-
}
|
|
639
|
-
const n = (l) => typeof l == "object" && l !== void 0 && typeof l.test == "function", s = (l) => l.replaceAll(/[$()*+.?[\\\]^{|}]/g, "\\$&"), i = (l) => new RegExp(
|
|
640
|
-
"^" + l.split("*").map((u) => s(u)).join(".+") + "$"
|
|
641
|
-
);
|
|
642
|
-
return !!e.find((l) => {
|
|
643
|
-
try {
|
|
644
|
-
return n(l) ? l.test(t) : l.includes("*") ? i(l).test(t) : l === t;
|
|
645
|
-
} catch (u) {
|
|
646
|
-
return a.warn("URLUtils", "Error testing exclusion pattern", {
|
|
647
|
-
pattern: l,
|
|
648
|
-
path: t,
|
|
649
|
-
error: u instanceof Error ? u.message : u
|
|
650
|
-
}), !1;
|
|
494
|
+
const r = nt(s, e, "customEvent");
|
|
495
|
+
return r.valid || o("error", "Event metadata validation failed", {
|
|
496
|
+
showToClient: !0,
|
|
497
|
+
data: {
|
|
498
|
+
eventName: s,
|
|
499
|
+
error: r.error
|
|
651
500
|
}
|
|
652
|
-
});
|
|
501
|
+
}), r;
|
|
653
502
|
};
|
|
654
|
-
|
|
655
|
-
const { timeout: t = 1e4, ...n } = e, s = new AbortController(), i = setTimeout(() => {
|
|
656
|
-
s.abort();
|
|
657
|
-
}, t);
|
|
658
|
-
try {
|
|
659
|
-
const o = await fetch(r, {
|
|
660
|
-
...n,
|
|
661
|
-
signal: s.signal
|
|
662
|
-
});
|
|
663
|
-
return clearTimeout(i), o;
|
|
664
|
-
} catch (o) {
|
|
665
|
-
throw clearTimeout(i), o instanceof Error && o.name === "AbortError" ? new Error(`Request timeout after ${t}ms`) : o;
|
|
666
|
-
}
|
|
667
|
-
}
|
|
668
|
-
class Vt {
|
|
503
|
+
class at {
|
|
669
504
|
listeners = /* @__PURE__ */ new Map();
|
|
670
505
|
on(e, t) {
|
|
671
506
|
this.listeners.has(e) || this.listeners.set(e, []), this.listeners.get(e).push(t);
|
|
672
507
|
}
|
|
673
508
|
off(e, t) {
|
|
674
|
-
const
|
|
675
|
-
if (
|
|
676
|
-
const
|
|
677
|
-
|
|
509
|
+
const r = this.listeners.get(e);
|
|
510
|
+
if (r) {
|
|
511
|
+
const n = r.indexOf(t);
|
|
512
|
+
n > -1 && r.splice(n, 1);
|
|
678
513
|
}
|
|
679
514
|
}
|
|
680
515
|
emit(e, t) {
|
|
681
|
-
const
|
|
682
|
-
|
|
516
|
+
const r = this.listeners.get(e);
|
|
517
|
+
r && r.forEach((n) => n(t));
|
|
683
518
|
}
|
|
684
519
|
removeAllListeners() {
|
|
685
520
|
this.listeners.clear();
|
|
686
521
|
}
|
|
687
522
|
}
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
if (!se(n, !0))
|
|
693
|
-
throw new Error(`Invalid localhost URL format: ${r}`);
|
|
694
|
-
return n;
|
|
695
|
-
}
|
|
696
|
-
const t = xt(r, e);
|
|
697
|
-
if (!se(t, e))
|
|
698
|
-
throw new Error(`Generated API URL failed validation: ${t}`);
|
|
699
|
-
return t;
|
|
700
|
-
} catch (t) {
|
|
701
|
-
throw a.error("ApiManager", "API URL generation failed", {
|
|
702
|
-
projectId: r,
|
|
703
|
-
allowHttp: e,
|
|
704
|
-
error: t instanceof Error ? t.message : t
|
|
705
|
-
}), t;
|
|
706
|
-
}
|
|
707
|
-
}
|
|
708
|
-
class Oe {
|
|
709
|
-
/**
|
|
710
|
-
* Builds final configuration from app config and API config
|
|
711
|
-
* Applies clear precedence: API overrides client, with defaults as fallback
|
|
712
|
-
*/
|
|
713
|
-
static build(e, t = {}) {
|
|
714
|
-
const n = this.resolveMode(e, t.mode), s = {
|
|
715
|
-
// Core identifiers
|
|
716
|
-
id: e.id,
|
|
717
|
-
// Session configuration
|
|
718
|
-
sessionTimeout: this.resolveSessionTimeout(e.sessionTimeout),
|
|
719
|
-
// Mode configuration (resolved first)
|
|
720
|
-
mode: n,
|
|
721
|
-
// Sampling configuration (depends on mode)
|
|
722
|
-
samplingRate: this.resolveSamplingRate(t.samplingRate, e.samplingRate),
|
|
723
|
-
errorSampling: this.resolveErrorSampling(e.errorSampling, n),
|
|
724
|
-
// Filtering configuration
|
|
725
|
-
excludedUrlPaths: t.excludedUrlPaths ?? e.excludedUrlPaths ?? [],
|
|
726
|
-
tags: t.tags ?? [],
|
|
727
|
-
ipExcluded: t.ipExcluded ?? !1,
|
|
728
|
-
// Client-only configuration
|
|
729
|
-
globalMetadata: e.globalMetadata ?? {},
|
|
730
|
-
scrollContainerSelectors: e.scrollContainerSelectors,
|
|
731
|
-
sensitiveQueryParams: e.sensitiveQueryParams ?? [],
|
|
732
|
-
integrations: e.integrations,
|
|
733
|
-
// Security configuration
|
|
734
|
-
allowHttp: e.allowHttp ?? !1
|
|
735
|
-
};
|
|
736
|
-
return a.debug("ConfigBuilder", "Configuration built", {
|
|
737
|
-
projectId: s.id,
|
|
738
|
-
mode: s.mode,
|
|
739
|
-
samplingRate: s.samplingRate,
|
|
740
|
-
errorSampling: s.errorSampling,
|
|
741
|
-
hasTags: !!s.tags?.length,
|
|
742
|
-
hasExclusions: !!s.excludedUrlPaths?.length
|
|
743
|
-
}), s;
|
|
744
|
-
}
|
|
745
|
-
/**
|
|
746
|
-
* Resolves session timeout with validation
|
|
747
|
-
* Returns default if undefined or out of valid range
|
|
748
|
-
*/
|
|
749
|
-
static resolveSessionTimeout(e) {
|
|
750
|
-
return e === void 0 ? P : e < k || e > x ? (a.warn("ConfigBuilder", "Invalid session timeout, using default", {
|
|
751
|
-
provided: e,
|
|
752
|
-
min: k,
|
|
753
|
-
max: x,
|
|
754
|
-
default: P
|
|
755
|
-
}), P) : e;
|
|
756
|
-
}
|
|
757
|
-
/**
|
|
758
|
-
* Resolves sampling rate with validation
|
|
759
|
-
* Priority: API config > app config > default
|
|
760
|
-
*/
|
|
761
|
-
static resolveSamplingRate(e, t) {
|
|
762
|
-
const n = e ?? t;
|
|
763
|
-
return n === void 0 ? M : n < nt || n > st ? (a.warn("ConfigBuilder", "Invalid sampling rate, using default", {
|
|
764
|
-
provided: n,
|
|
765
|
-
default: M
|
|
766
|
-
}), M) : n;
|
|
767
|
-
}
|
|
768
|
-
/**
|
|
769
|
-
* Resolves error sampling rate based on mode
|
|
770
|
-
* In debug/qa modes: uses provided value or defaults to full sampling (1.0)
|
|
771
|
-
* In production: uses provided value or defaults to 10% sampling (0.1)
|
|
772
|
-
*/
|
|
773
|
-
static resolveErrorSampling(e, t) {
|
|
774
|
-
return t === O.DEBUG || t === O.QA ? e ?? 1 : e ?? 0.1;
|
|
775
|
-
}
|
|
776
|
-
/**
|
|
777
|
-
* Resolves mode with special project ID handling
|
|
778
|
-
* Priority: Special project ID > API mode > app mode
|
|
779
|
-
*/
|
|
780
|
-
static resolveMode(e, t) {
|
|
781
|
-
return e.id === f.Skip || e.id === f.Fail || e.id.toLowerCase().startsWith("skip-") ? O.DEBUG : t ?? e.mode;
|
|
782
|
-
}
|
|
783
|
-
}
|
|
784
|
-
class zt {
|
|
785
|
-
static PRODUCTION_DOMAINS = [/^https:\/\/.*\.tracelog\.app$/, /^https:\/\/.*\.tracelog\.dev$/];
|
|
786
|
-
/**
|
|
787
|
-
* Gets complete configuration by loading API config and building final config.
|
|
788
|
-
*
|
|
789
|
-
* @param apiUrl - Base URL for the configuration API
|
|
790
|
-
* @param appConfig - Client-side configuration from init()
|
|
791
|
-
* @returns Promise<Config> - Merged configuration object
|
|
792
|
-
*/
|
|
793
|
-
async get(e, t) {
|
|
794
|
-
if (t.id === f.Skip || t.id === f.Fail || t.id.toLowerCase().startsWith("skip-"))
|
|
795
|
-
return this.createDefaultConfig(t);
|
|
796
|
-
const n = await this.loadFromApi(e, t), s = this.applyQaModeIfEnabled(n), i = Oe.build(t, s);
|
|
797
|
-
return a.info("ConfigManager", "Configuration loaded", {
|
|
798
|
-
projectId: i.id,
|
|
799
|
-
mode: i.mode,
|
|
800
|
-
hasTags: !!i.tags?.length,
|
|
801
|
-
hasExclusions: !!i.excludedUrlPaths?.length
|
|
802
|
-
}), i;
|
|
803
|
-
}
|
|
804
|
-
/**
|
|
805
|
-
* Loads configuration from API and returns sanitized API config.
|
|
806
|
-
* Only returns values explicitly provided by the API.
|
|
807
|
-
*/
|
|
808
|
-
async loadFromApi(e, t) {
|
|
809
|
-
try {
|
|
810
|
-
const n = this.buildConfigUrl(e, t), s = this.buildHeaders(t), i = await Ht(n, {
|
|
811
|
-
method: "GET",
|
|
812
|
-
headers: s,
|
|
813
|
-
timeout: Ue
|
|
814
|
-
});
|
|
815
|
-
if (!i.ok)
|
|
816
|
-
throw new Error(`HTTP ${i.status}: ${i.statusText}`);
|
|
817
|
-
const o = await this.parseJsonResponse(i), c = Nt(o);
|
|
818
|
-
return {
|
|
819
|
-
...c,
|
|
820
|
-
excludedUrlPaths: c.excludedUrlPaths ?? N.excludedUrlPaths,
|
|
821
|
-
tags: c.tags ?? N.tags
|
|
822
|
-
};
|
|
823
|
-
} catch (n) {
|
|
824
|
-
const s = n instanceof Error ? n.message : "Unknown error";
|
|
825
|
-
throw a.error("ConfigManager", "Failed to load configuration", {
|
|
826
|
-
error: s,
|
|
827
|
-
apiUrl: e,
|
|
828
|
-
projectId: t.id
|
|
829
|
-
}), new Error(`Configuration load failed: ${s}`);
|
|
830
|
-
}
|
|
831
|
-
}
|
|
832
|
-
/**
|
|
833
|
-
* Builds the configuration URL based on project type and QA mode.
|
|
834
|
-
*/
|
|
835
|
-
buildConfigUrl(e, t) {
|
|
836
|
-
if (t.id === f.Localhost || t.id === f.Fail)
|
|
837
|
-
return `http://${t.id}/config`;
|
|
838
|
-
const s = `${e}/config`;
|
|
839
|
-
return this.isQaModeEnabled() ? `${s}?qaMode=true` : s;
|
|
840
|
-
}
|
|
841
|
-
/**
|
|
842
|
-
* Builds request headers based on project configuration.
|
|
843
|
-
* Always includes X-TraceLog-Project header for consistent identification.
|
|
844
|
-
*/
|
|
845
|
-
buildHeaders(e) {
|
|
846
|
-
return {
|
|
847
|
-
"Content-Type": "application/json",
|
|
848
|
-
"X-TraceLog-Project": e.id
|
|
849
|
-
};
|
|
850
|
-
}
|
|
851
|
-
/**
|
|
852
|
-
* Parses and validates JSON response from config API.
|
|
853
|
-
*/
|
|
854
|
-
async parseJsonResponse(e) {
|
|
855
|
-
if (!e.headers.get("content-type")?.includes("application/json"))
|
|
856
|
-
throw new Error("Invalid response content-type, expected JSON");
|
|
857
|
-
const n = await e.json();
|
|
858
|
-
if (!n || typeof n != "object" || Array.isArray(n))
|
|
859
|
-
throw new Error("Invalid response format, expected object");
|
|
860
|
-
return n;
|
|
861
|
-
}
|
|
862
|
-
/**
|
|
863
|
-
* Checks if QA mode is enabled via URL parameter.
|
|
864
|
-
*/
|
|
865
|
-
isQaModeEnabled() {
|
|
866
|
-
return new URLSearchParams(window.location.search).get("qaMode") === "true";
|
|
523
|
+
const $ = {};
|
|
524
|
+
class f {
|
|
525
|
+
get(e) {
|
|
526
|
+
return $[e];
|
|
867
527
|
}
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
*/
|
|
871
|
-
applyQaModeIfEnabled(e) {
|
|
872
|
-
return this.isQaModeEnabled() && !e.mode ? (a.info("ConfigManager", "QA mode enabled via URL parameter"), { ...e, mode: O.QA }) : e;
|
|
528
|
+
set(e, t) {
|
|
529
|
+
$[e] = t;
|
|
873
530
|
}
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
* Only uses API defaults for fields not provided by the app config.
|
|
877
|
-
*/
|
|
878
|
-
createDefaultConfig(e) {
|
|
879
|
-
const t = {
|
|
880
|
-
// Only use defaults if app config doesn't provide these values
|
|
881
|
-
tags: N.tags,
|
|
882
|
-
ipExcluded: N.ipExcluded,
|
|
883
|
-
...e.samplingRate === void 0 && { samplingRate: N.samplingRate }
|
|
884
|
-
// Don't override excludedUrlPaths if provided by app config
|
|
885
|
-
// ConfigBuilder will handle the fallback to [] if both are undefined
|
|
886
|
-
};
|
|
887
|
-
return Oe.build(e, t);
|
|
531
|
+
getState() {
|
|
532
|
+
return { ...$ };
|
|
888
533
|
}
|
|
889
534
|
}
|
|
890
|
-
class
|
|
535
|
+
class ot extends f {
|
|
891
536
|
storeManager;
|
|
892
537
|
retryTimeoutId = null;
|
|
893
538
|
retryCount = 0;
|
|
@@ -896,23 +541,23 @@ class Gt extends m {
|
|
|
896
541
|
super(), this.storeManager = e;
|
|
897
542
|
}
|
|
898
543
|
getQueueStorageKey() {
|
|
899
|
-
const e = this.get("
|
|
900
|
-
return
|
|
544
|
+
const e = this.get("userId") || "anonymous";
|
|
545
|
+
return Ve(e);
|
|
901
546
|
}
|
|
902
547
|
sendEventsQueueSync(e) {
|
|
903
548
|
if (this.shouldSkipSend())
|
|
904
549
|
return this.resetRetryState(), !0;
|
|
905
|
-
if (this.get("config")?.
|
|
906
|
-
return
|
|
907
|
-
events: e.events.length
|
|
550
|
+
if (this.get("config")?.integrations?.custom?.apiUrl === j.Fail)
|
|
551
|
+
return o("warn", "Fail mode: simulating network failure (sync)", {
|
|
552
|
+
data: { events: e.events.length }
|
|
908
553
|
}), !1;
|
|
909
|
-
const
|
|
910
|
-
return
|
|
554
|
+
const r = this.sendQueueSyncInternal(e);
|
|
555
|
+
return r && this.resetRetryState(), r;
|
|
911
556
|
}
|
|
912
557
|
async sendEventsQueue(e, t) {
|
|
913
|
-
|
|
914
|
-
const
|
|
915
|
-
return
|
|
558
|
+
this.shouldSkipSend() || this.persistEvents(e) || o("warn", "Failed to persist events, attempting immediate send");
|
|
559
|
+
const r = await this.send(e);
|
|
560
|
+
return r ? (this.clearPersistedEvents(), this.resetRetryState(), t?.onSuccess?.(e.events.length, e.events, e)) : (this.scheduleRetry(e, t), t?.onFailure?.()), r;
|
|
916
561
|
}
|
|
917
562
|
async recoverPersistedEvents(e) {
|
|
918
563
|
try {
|
|
@@ -921,10 +566,10 @@ class Gt extends m {
|
|
|
921
566
|
this.clearPersistedEvents();
|
|
922
567
|
return;
|
|
923
568
|
}
|
|
924
|
-
const
|
|
925
|
-
await this.send(
|
|
569
|
+
const r = this.createRecoveryBody(t);
|
|
570
|
+
await this.send(r) ? (this.clearPersistedEvents(), this.resetRetryState(), e?.onSuccess?.(t.events.length, t.events, r)) : (this.scheduleRetry(r, e), e?.onFailure?.());
|
|
926
571
|
} catch (t) {
|
|
927
|
-
|
|
572
|
+
o("error", "Failed to recover persisted events", { error: t }), this.clearPersistedEvents();
|
|
928
573
|
}
|
|
929
574
|
}
|
|
930
575
|
persistEventsForRecovery(e) {
|
|
@@ -939,55 +584,55 @@ class Gt extends m {
|
|
|
939
584
|
async send(e) {
|
|
940
585
|
if (this.shouldSkipSend())
|
|
941
586
|
return this.simulateSuccessfulSend();
|
|
942
|
-
if (this.get("config")?.
|
|
943
|
-
return
|
|
944
|
-
events: e.events.length
|
|
587
|
+
if (this.get("config")?.integrations?.custom?.apiUrl === j.Fail)
|
|
588
|
+
return o("warn", "Fail mode: simulating network failure", {
|
|
589
|
+
data: { events: e.events.length }
|
|
945
590
|
}), !1;
|
|
946
|
-
const { url:
|
|
591
|
+
const { url: r, payload: n } = this.prepareRequest(e);
|
|
947
592
|
try {
|
|
948
|
-
return (await this.sendWithTimeout(
|
|
593
|
+
return (await this.sendWithTimeout(r, n)).ok;
|
|
949
594
|
} catch (i) {
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
595
|
+
return o("error", "Send request failed", {
|
|
596
|
+
error: i,
|
|
597
|
+
data: {
|
|
598
|
+
events: e.events.length,
|
|
599
|
+
url: r.replace(/\/\/[^/]+/, "//[DOMAIN]")
|
|
600
|
+
}
|
|
955
601
|
}), !1;
|
|
956
602
|
}
|
|
957
603
|
}
|
|
958
604
|
async sendWithTimeout(e, t) {
|
|
959
|
-
const
|
|
605
|
+
const r = new AbortController(), n = setTimeout(() => r.abort(), 1e4);
|
|
960
606
|
try {
|
|
961
|
-
const
|
|
607
|
+
const i = await fetch(e, {
|
|
962
608
|
method: "POST",
|
|
963
|
-
headers: {
|
|
964
|
-
"Content-Type": "application/json",
|
|
965
|
-
"X-TraceLog-Project": i?.id || "unknown"
|
|
966
|
-
},
|
|
967
609
|
body: t,
|
|
968
610
|
keepalive: !0,
|
|
969
611
|
credentials: "include",
|
|
970
|
-
signal:
|
|
612
|
+
signal: r.signal,
|
|
613
|
+
headers: {
|
|
614
|
+
"Content-Type": "application/json"
|
|
615
|
+
}
|
|
971
616
|
});
|
|
972
|
-
if (!
|
|
973
|
-
throw new Error(`HTTP ${
|
|
974
|
-
return
|
|
617
|
+
if (!i.ok)
|
|
618
|
+
throw new Error(`HTTP ${i.status}: ${i.statusText}`);
|
|
619
|
+
return i;
|
|
975
620
|
} finally {
|
|
976
|
-
clearTimeout(
|
|
621
|
+
clearTimeout(n);
|
|
977
622
|
}
|
|
978
623
|
}
|
|
979
624
|
sendQueueSyncInternal(e) {
|
|
980
|
-
const { url: t, payload:
|
|
625
|
+
const { url: t, payload: r } = this.prepareRequest(e), n = new Blob([r], { type: "application/json" });
|
|
981
626
|
if (this.isSendBeaconAvailable()) {
|
|
982
|
-
if (navigator.sendBeacon(t,
|
|
627
|
+
if (navigator.sendBeacon(t, n))
|
|
983
628
|
return !0;
|
|
984
|
-
|
|
629
|
+
o("warn", "sendBeacon failed, persisting events for recovery");
|
|
985
630
|
} else
|
|
986
|
-
|
|
631
|
+
o("warn", "sendBeacon not available, persisting events for recovery");
|
|
987
632
|
return this.persistEventsForRecovery(e), !1;
|
|
988
633
|
}
|
|
989
634
|
prepareRequest(e) {
|
|
990
|
-
const t = `${this.get("apiUrl")}/collect`,
|
|
635
|
+
const t = `${this.get("apiUrl")}/collect`, r = {
|
|
991
636
|
...e,
|
|
992
637
|
_metadata: {
|
|
993
638
|
referer: typeof window < "u" ? window.location.href : void 0,
|
|
@@ -996,7 +641,7 @@ class Gt extends m {
|
|
|
996
641
|
};
|
|
997
642
|
return {
|
|
998
643
|
url: t,
|
|
999
|
-
payload: JSON.stringify(
|
|
644
|
+
payload: JSON.stringify(r)
|
|
1000
645
|
};
|
|
1001
646
|
}
|
|
1002
647
|
getPersistedData() {
|
|
@@ -1005,12 +650,12 @@ class Gt extends m {
|
|
|
1005
650
|
if (t)
|
|
1006
651
|
return JSON.parse(t);
|
|
1007
652
|
} catch (e) {
|
|
1008
|
-
|
|
653
|
+
o("warn", "Failed to parse persisted data", { error: e }), this.clearPersistedEvents();
|
|
1009
654
|
}
|
|
1010
655
|
return null;
|
|
1011
656
|
}
|
|
1012
657
|
isDataRecent(e) {
|
|
1013
|
-
return !e.timestamp || typeof e.timestamp != "number" ? !1 : (Date.now() - e.timestamp) / (1e3 * 60 * 60) <
|
|
658
|
+
return !e.timestamp || typeof e.timestamp != "number" ? !1 : (Date.now() - e.timestamp) / (1e3 * 60 * 60) < 24;
|
|
1014
659
|
}
|
|
1015
660
|
createRecoveryBody(e) {
|
|
1016
661
|
return {
|
|
@@ -1030,10 +675,10 @@ class Gt extends m {
|
|
|
1030
675
|
events: e.events,
|
|
1031
676
|
timestamp: Date.now(),
|
|
1032
677
|
...e.global_metadata && { global_metadata: e.global_metadata }
|
|
1033
|
-
},
|
|
1034
|
-
return this.storeManager.setItem(
|
|
678
|
+
}, r = this.getQueueStorageKey();
|
|
679
|
+
return this.storeManager.setItem(r, JSON.stringify(t)), !!this.storeManager.getItem(r);
|
|
1035
680
|
} catch (t) {
|
|
1036
|
-
return
|
|
681
|
+
return o("warn", "Failed to persist events", { error: t }), !1;
|
|
1037
682
|
}
|
|
1038
683
|
}
|
|
1039
684
|
clearPersistedEvents() {
|
|
@@ -1041,7 +686,7 @@ class Gt extends m {
|
|
|
1041
686
|
const e = this.getQueueStorageKey();
|
|
1042
687
|
this.storeManager.removeItem(e);
|
|
1043
688
|
} catch (e) {
|
|
1044
|
-
|
|
689
|
+
o("warn", "Failed to clear persisted events", { error: e });
|
|
1045
690
|
}
|
|
1046
691
|
}
|
|
1047
692
|
resetRetryState() {
|
|
@@ -1050,27 +695,22 @@ class Gt extends m {
|
|
|
1050
695
|
scheduleRetry(e, t) {
|
|
1051
696
|
if (this.retryTimeoutId !== null || this.isRetrying)
|
|
1052
697
|
return;
|
|
1053
|
-
if (this.retryCount >=
|
|
1054
|
-
|
|
698
|
+
if (this.retryCount >= 3) {
|
|
699
|
+
o("warn", "Max retries reached, giving up", { data: { retryCount: this.retryCount } }), this.clearPersistedEvents(), this.resetRetryState(), t?.onFailure?.();
|
|
1055
700
|
return;
|
|
1056
701
|
}
|
|
1057
|
-
const
|
|
702
|
+
const r = 5e3 * Math.pow(2, this.retryCount);
|
|
1058
703
|
this.isRetrying = !0, this.retryTimeoutId = window.setTimeout(async () => {
|
|
1059
704
|
this.retryTimeoutId = null, this.retryCount++;
|
|
1060
705
|
try {
|
|
1061
|
-
await this.send(e) ? (this.clearPersistedEvents(), this.resetRetryState(), t?.onSuccess?.(e.events.length)) : this.retryCount >=
|
|
706
|
+
await this.send(e) ? (this.clearPersistedEvents(), this.resetRetryState(), t?.onSuccess?.(e.events.length)) : this.retryCount >= 3 ? (this.clearPersistedEvents(), this.resetRetryState(), t?.onFailure?.()) : this.scheduleRetry(e, t);
|
|
1062
707
|
} finally {
|
|
1063
708
|
this.isRetrying = !1;
|
|
1064
709
|
}
|
|
1065
|
-
},
|
|
1066
|
-
attempt: this.retryCount + 1,
|
|
1067
|
-
delay: n,
|
|
1068
|
-
events: e.events.length
|
|
1069
|
-
});
|
|
710
|
+
}, r);
|
|
1070
711
|
}
|
|
1071
712
|
shouldSkipSend() {
|
|
1072
|
-
|
|
1073
|
-
return t === f.Skip;
|
|
713
|
+
return !this.get("apiUrl");
|
|
1074
714
|
}
|
|
1075
715
|
async simulateSuccessfulSend() {
|
|
1076
716
|
const e = Math.random() * 400 + 100;
|
|
@@ -1083,76 +723,107 @@ class Gt extends m {
|
|
|
1083
723
|
this.retryTimeoutId !== null && (clearTimeout(this.retryTimeoutId), this.retryTimeoutId = null);
|
|
1084
724
|
}
|
|
1085
725
|
}
|
|
1086
|
-
class
|
|
726
|
+
class ct extends f {
|
|
1087
727
|
googleAnalytics;
|
|
1088
728
|
dataSender;
|
|
1089
729
|
emitter;
|
|
1090
730
|
eventsQueue = [];
|
|
731
|
+
pendingEventsBuffer = [];
|
|
1091
732
|
lastEventFingerprint = null;
|
|
1092
733
|
lastEventTime = 0;
|
|
1093
734
|
sendIntervalId = null;
|
|
1094
|
-
|
|
1095
|
-
|
|
735
|
+
rateLimitCounter = 0;
|
|
736
|
+
rateLimitWindowStart = 0;
|
|
737
|
+
constructor(e, t = null, r = null) {
|
|
738
|
+
super(), this.googleAnalytics = t, this.dataSender = new ot(e), this.emitter = r;
|
|
1096
739
|
}
|
|
1097
740
|
async recoverPersistedEvents() {
|
|
1098
741
|
await this.dataSender.recoverPersistedEvents({
|
|
1099
|
-
onSuccess: (e, t,
|
|
742
|
+
onSuccess: (e, t, r) => {
|
|
1100
743
|
if (t && t.length > 0) {
|
|
1101
|
-
const
|
|
1102
|
-
this.removeProcessedEvents(
|
|
744
|
+
const n = t.map((i) => i.id);
|
|
745
|
+
this.removeProcessedEvents(n), r && this.emitEventsQueue(r);
|
|
1103
746
|
}
|
|
1104
747
|
},
|
|
1105
748
|
onFailure: async () => {
|
|
1106
|
-
|
|
749
|
+
o("warn", "Failed to recover persisted events");
|
|
1107
750
|
}
|
|
1108
751
|
});
|
|
1109
752
|
}
|
|
1110
753
|
track({
|
|
1111
754
|
type: e,
|
|
1112
755
|
page_url: t,
|
|
1113
|
-
from_page_url:
|
|
1114
|
-
scroll_data:
|
|
756
|
+
from_page_url: r,
|
|
757
|
+
scroll_data: n,
|
|
1115
758
|
click_data: i,
|
|
1116
|
-
custom_event:
|
|
759
|
+
custom_event: a,
|
|
1117
760
|
web_vitals: c,
|
|
1118
761
|
error_data: l,
|
|
1119
762
|
session_end_reason: u
|
|
1120
763
|
}) {
|
|
1121
764
|
if (!e) {
|
|
1122
|
-
|
|
765
|
+
o("error", "Event type is required - event will be ignored");
|
|
1123
766
|
return;
|
|
1124
767
|
}
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
768
|
+
if (!this.get("sessionId")) {
|
|
769
|
+
this.pendingEventsBuffer.length >= 100 && (this.pendingEventsBuffer.shift(), o("warn", "Pending events buffer full - dropping oldest event", {
|
|
770
|
+
data: { maxBufferSize: 100 }
|
|
771
|
+
})), this.pendingEventsBuffer.push({
|
|
772
|
+
type: e,
|
|
773
|
+
page_url: t,
|
|
774
|
+
from_page_url: r,
|
|
775
|
+
scroll_data: n,
|
|
776
|
+
click_data: i,
|
|
777
|
+
custom_event: a,
|
|
778
|
+
web_vitals: c,
|
|
779
|
+
error_data: l,
|
|
780
|
+
session_end_reason: u
|
|
781
|
+
});
|
|
782
|
+
return;
|
|
783
|
+
}
|
|
784
|
+
const p = e === d.SESSION_START || e === d.SESSION_END;
|
|
785
|
+
if (!p && !this.checkRateLimit())
|
|
786
|
+
return;
|
|
787
|
+
const N = e, Le = N === d.SESSION_START, Re = t || this.get("pageUrl"), z = this.buildEventPayload({
|
|
788
|
+
type: N,
|
|
789
|
+
page_url: Re,
|
|
790
|
+
from_page_url: r,
|
|
791
|
+
scroll_data: n,
|
|
1130
792
|
click_data: i,
|
|
1131
|
-
custom_event:
|
|
793
|
+
custom_event: a,
|
|
1132
794
|
web_vitals: c,
|
|
1133
795
|
error_data: l,
|
|
1134
796
|
session_end_reason: u
|
|
1135
797
|
});
|
|
1136
|
-
if (!
|
|
1137
|
-
if (
|
|
1138
|
-
const
|
|
1139
|
-
if (!
|
|
1140
|
-
|
|
798
|
+
if (!(!p && !this.shouldSample())) {
|
|
799
|
+
if (Le) {
|
|
800
|
+
const ae = this.get("sessionId");
|
|
801
|
+
if (!ae) {
|
|
802
|
+
o("error", "Session start event requires sessionId - event will be ignored");
|
|
1141
803
|
return;
|
|
1142
804
|
}
|
|
1143
805
|
if (this.get("hasStartSession")) {
|
|
1144
|
-
|
|
1145
|
-
sessionId:
|
|
806
|
+
o("warn", "Duplicate session_start detected", {
|
|
807
|
+
data: { sessionId: ae }
|
|
1146
808
|
});
|
|
1147
809
|
return;
|
|
1148
810
|
}
|
|
1149
811
|
this.set("hasStartSession", !0);
|
|
1150
812
|
}
|
|
1151
|
-
this.isDuplicateEvent(
|
|
813
|
+
if (!this.isDuplicateEvent(z)) {
|
|
814
|
+
if (this.get("mode") === R.QA && N === d.CUSTOM && a) {
|
|
815
|
+
console.log("[TraceLog] Event", {
|
|
816
|
+
name: a.name,
|
|
817
|
+
...a.metadata && { metadata: a.metadata }
|
|
818
|
+
}), this.emitEvent(z);
|
|
819
|
+
return;
|
|
820
|
+
}
|
|
821
|
+
this.addToQueue(z);
|
|
822
|
+
}
|
|
1152
823
|
}
|
|
1153
824
|
}
|
|
1154
825
|
stop() {
|
|
1155
|
-
this.sendIntervalId && (clearInterval(this.sendIntervalId), this.sendIntervalId = null), this.eventsQueue = [], this.lastEventFingerprint = null, this.lastEventTime = 0, this.dataSender.stop();
|
|
826
|
+
this.sendIntervalId && (clearInterval(this.sendIntervalId), this.sendIntervalId = null), this.eventsQueue = [], this.pendingEventsBuffer = [], this.lastEventFingerprint = null, this.lastEventTime = 0, this.rateLimitCounter = 0, this.rateLimitWindowStart = 0, this.dataSender.stop();
|
|
1156
827
|
}
|
|
1157
828
|
async flushImmediately() {
|
|
1158
829
|
return this.flushEvents(!1);
|
|
@@ -1163,24 +834,38 @@ class jt extends m {
|
|
|
1163
834
|
getQueueLength() {
|
|
1164
835
|
return this.eventsQueue.length;
|
|
1165
836
|
}
|
|
837
|
+
flushPendingEvents() {
|
|
838
|
+
if (this.pendingEventsBuffer.length === 0)
|
|
839
|
+
return;
|
|
840
|
+
if (!this.get("sessionId")) {
|
|
841
|
+
o("warn", "Cannot flush pending events: session not initialized - keeping in buffer", {
|
|
842
|
+
data: { bufferedEventCount: this.pendingEventsBuffer.length }
|
|
843
|
+
});
|
|
844
|
+
return;
|
|
845
|
+
}
|
|
846
|
+
const t = [...this.pendingEventsBuffer];
|
|
847
|
+
this.pendingEventsBuffer = [], t.forEach((r) => {
|
|
848
|
+
this.track(r);
|
|
849
|
+
});
|
|
850
|
+
}
|
|
1166
851
|
clearSendInterval() {
|
|
1167
852
|
this.sendIntervalId && (clearInterval(this.sendIntervalId), this.sendIntervalId = null);
|
|
1168
853
|
}
|
|
1169
854
|
flushEvents(e) {
|
|
1170
855
|
if (this.eventsQueue.length === 0)
|
|
1171
856
|
return e ? !0 : Promise.resolve(!0);
|
|
1172
|
-
const t = this.buildEventsPayload(),
|
|
857
|
+
const t = this.buildEventsPayload(), r = [...this.eventsQueue], n = r.map((i) => i.id);
|
|
1173
858
|
if (e) {
|
|
1174
859
|
const i = this.dataSender.sendEventsQueueSync(t);
|
|
1175
|
-
return i && (this.removeProcessedEvents(
|
|
860
|
+
return i && (this.removeProcessedEvents(n), this.clearSendInterval(), this.emitEventsQueue(t)), i;
|
|
1176
861
|
} else
|
|
1177
862
|
return this.dataSender.sendEventsQueue(t, {
|
|
1178
863
|
onSuccess: () => {
|
|
1179
|
-
this.removeProcessedEvents(
|
|
864
|
+
this.removeProcessedEvents(n), this.clearSendInterval(), this.emitEventsQueue(t);
|
|
1180
865
|
},
|
|
1181
866
|
onFailure: () => {
|
|
1182
|
-
|
|
1183
|
-
eventCount:
|
|
867
|
+
o("warn", "Async flush failed", {
|
|
868
|
+
data: { eventCount: r.length }
|
|
1184
869
|
});
|
|
1185
870
|
}
|
|
1186
871
|
});
|
|
@@ -1188,37 +873,39 @@ class jt extends m {
|
|
|
1188
873
|
async sendEventsQueue() {
|
|
1189
874
|
if (!this.get("sessionId") || this.eventsQueue.length === 0)
|
|
1190
875
|
return;
|
|
1191
|
-
const e = this.buildEventsPayload(), t = [...this.eventsQueue],
|
|
876
|
+
const e = this.buildEventsPayload(), t = [...this.eventsQueue], r = t.map((n) => n.id);
|
|
1192
877
|
await this.dataSender.sendEventsQueue(e, {
|
|
1193
878
|
onSuccess: () => {
|
|
1194
|
-
this.removeProcessedEvents(
|
|
879
|
+
this.removeProcessedEvents(r), this.emitEventsQueue(e);
|
|
1195
880
|
},
|
|
1196
881
|
onFailure: async () => {
|
|
1197
|
-
|
|
1198
|
-
eventCount: t.length
|
|
882
|
+
o("warn", "Events send failed, keeping in queue", {
|
|
883
|
+
data: { eventCount: t.length }
|
|
1199
884
|
});
|
|
1200
885
|
}
|
|
1201
886
|
});
|
|
1202
887
|
}
|
|
1203
888
|
buildEventsPayload() {
|
|
1204
889
|
const e = /* @__PURE__ */ new Map(), t = [];
|
|
1205
|
-
for (const
|
|
1206
|
-
const i = this.createEventSignature(
|
|
1207
|
-
e.has(i) || t.push(i), e.set(i,
|
|
890
|
+
for (const n of this.eventsQueue) {
|
|
891
|
+
const i = this.createEventSignature(n);
|
|
892
|
+
e.has(i) || t.push(i), e.set(i, n);
|
|
1208
893
|
}
|
|
1209
|
-
const
|
|
894
|
+
const r = t.map((n) => e.get(n)).filter((n) => !!n).sort((n, i) => n.timestamp - i.timestamp);
|
|
1210
895
|
return {
|
|
1211
896
|
user_id: this.get("userId"),
|
|
1212
897
|
session_id: this.get("sessionId"),
|
|
1213
898
|
device: this.get("device"),
|
|
1214
|
-
events:
|
|
899
|
+
events: r,
|
|
1215
900
|
...this.get("config")?.globalMetadata && { global_metadata: this.get("config")?.globalMetadata }
|
|
1216
901
|
};
|
|
1217
902
|
}
|
|
1218
903
|
buildEventPayload(e) {
|
|
1219
|
-
const t = e.type === d.SESSION_START,
|
|
904
|
+
const t = e.type === d.SESSION_START, r = e.page_url ?? this.get("pageUrl");
|
|
905
|
+
return {
|
|
906
|
+
id: Xe(),
|
|
1220
907
|
type: e.type,
|
|
1221
|
-
page_url:
|
|
908
|
+
page_url: r,
|
|
1222
909
|
timestamp: Date.now(),
|
|
1223
910
|
...t && { referrer: document.referrer || "Direct" },
|
|
1224
911
|
...e.from_page_url && { from_page_url: e.from_page_url },
|
|
@@ -1228,23 +915,18 @@ class jt extends m {
|
|
|
1228
915
|
...e.web_vitals && { web_vitals: e.web_vitals },
|
|
1229
916
|
...e.error_data && { error_data: e.error_data },
|
|
1230
917
|
...e.session_end_reason && { session_end_reason: e.session_end_reason },
|
|
1231
|
-
...t &&
|
|
1232
|
-
}
|
|
1233
|
-
return i?.length && (s.tags = i), s;
|
|
1234
|
-
}
|
|
1235
|
-
isEventExcluded(e) {
|
|
1236
|
-
const t = this.get("config"), n = Ut(e.page_url, t?.excludedUrlPaths ?? []), s = this.get("hasStartSession"), i = e.type === d.SESSION_END, o = e.type === d.SESSION_START;
|
|
1237
|
-
return n && !o && !(i && s) ? !0 : t?.ipExcluded === !0;
|
|
918
|
+
...t && he() && { utm: he() }
|
|
919
|
+
};
|
|
1238
920
|
}
|
|
1239
921
|
isDuplicateEvent(e) {
|
|
1240
|
-
const t = Date.now(),
|
|
1241
|
-
return this.lastEventFingerprint ===
|
|
922
|
+
const t = Date.now(), r = this.createEventFingerprint(e);
|
|
923
|
+
return this.lastEventFingerprint === r && t - this.lastEventTime < 500 ? !0 : (this.lastEventFingerprint = r, this.lastEventTime = t, !1);
|
|
1242
924
|
}
|
|
1243
925
|
createEventFingerprint(e) {
|
|
1244
926
|
let t = `${e.type}_${e.page_url}`;
|
|
1245
927
|
if (e.click_data) {
|
|
1246
|
-
const
|
|
1247
|
-
t += `_click_${
|
|
928
|
+
const r = Math.round((e.click_data.x || 0) / 10) * 10, n = Math.round((e.click_data.y || 0) / 10) * 10;
|
|
929
|
+
t += `_click_${r}_${n}`;
|
|
1248
930
|
}
|
|
1249
931
|
return e.scroll_data && (t += `_scroll_${e.scroll_data.depth}_${e.scroll_data.direction}`), e.custom_event && (t += `_custom_${e.custom_event.name}`), e.web_vitals && (t += `_vitals_${e.web_vitals.type}`), e.error_data && (t += `_error_${e.error_data.type}_${e.error_data.message}`), t;
|
|
1250
932
|
}
|
|
@@ -1252,15 +934,17 @@ class jt extends m {
|
|
|
1252
934
|
return this.createEventFingerprint(e);
|
|
1253
935
|
}
|
|
1254
936
|
addToQueue(e) {
|
|
1255
|
-
if (this.eventsQueue.push(e), this.emitEvent(e), this.eventsQueue.length >
|
|
937
|
+
if (this.eventsQueue.push(e), this.emitEvent(e), this.eventsQueue.length > 100) {
|
|
1256
938
|
const t = this.eventsQueue.findIndex(
|
|
1257
|
-
(
|
|
1258
|
-
),
|
|
1259
|
-
|
|
1260
|
-
|
|
1261
|
-
|
|
1262
|
-
|
|
1263
|
-
|
|
939
|
+
(n) => n.type !== d.SESSION_START && n.type !== d.SESSION_END
|
|
940
|
+
), r = t >= 0 ? this.eventsQueue.splice(t, 1)[0] : this.eventsQueue.shift();
|
|
941
|
+
o("warn", "Event queue overflow, oldest non-critical event removed", {
|
|
942
|
+
data: {
|
|
943
|
+
maxLength: 100,
|
|
944
|
+
currentLength: this.eventsQueue.length,
|
|
945
|
+
removedEventType: r?.type,
|
|
946
|
+
wasCritical: r?.type === d.SESSION_START || r?.type === d.SESSION_END
|
|
947
|
+
}
|
|
1264
948
|
});
|
|
1265
949
|
}
|
|
1266
950
|
this.sendIntervalId || this.startSendInterval(), this.handleGoogleAnalyticsIntegration(e);
|
|
@@ -1268,11 +952,11 @@ class jt extends m {
|
|
|
1268
952
|
startSendInterval() {
|
|
1269
953
|
this.sendIntervalId = window.setInterval(() => {
|
|
1270
954
|
this.eventsQueue.length > 0 && this.sendEventsQueue();
|
|
1271
|
-
},
|
|
955
|
+
}, 1e4);
|
|
1272
956
|
}
|
|
1273
957
|
handleGoogleAnalyticsIntegration(e) {
|
|
1274
958
|
if (this.googleAnalytics && e.type === d.CUSTOM && e.custom_event) {
|
|
1275
|
-
if (this.get("
|
|
959
|
+
if (this.get("mode") === R.QA)
|
|
1276
960
|
return;
|
|
1277
961
|
this.googleAnalytics.trackEvent(e.custom_event.name, e.custom_event.metadata ?? {});
|
|
1278
962
|
}
|
|
@@ -1281,21 +965,22 @@ class jt extends m {
|
|
|
1281
965
|
const e = this.get("config")?.samplingRate ?? 1;
|
|
1282
966
|
return Math.random() < e;
|
|
1283
967
|
}
|
|
968
|
+
checkRateLimit() {
|
|
969
|
+
const e = Date.now();
|
|
970
|
+
return e - this.rateLimitWindowStart > 1e3 && (this.rateLimitCounter = 0, this.rateLimitWindowStart = e), this.rateLimitCounter >= 200 ? !1 : (this.rateLimitCounter++, !0);
|
|
971
|
+
}
|
|
1284
972
|
removeProcessedEvents(e) {
|
|
1285
973
|
const t = new Set(e);
|
|
1286
|
-
this.eventsQueue = this.eventsQueue.filter((
|
|
1287
|
-
const s = `${n.timestamp}_${n.type}`;
|
|
1288
|
-
return !t.has(s);
|
|
1289
|
-
});
|
|
974
|
+
this.eventsQueue = this.eventsQueue.filter((r) => !t.has(r.id));
|
|
1290
975
|
}
|
|
1291
976
|
emitEvent(e) {
|
|
1292
|
-
this.emitter && this.emitter.emit(
|
|
977
|
+
this.emitter && this.emitter.emit(X.EVENT, e);
|
|
1293
978
|
}
|
|
1294
979
|
emitEventsQueue(e) {
|
|
1295
|
-
this.emitter && this.emitter.emit(
|
|
980
|
+
this.emitter && this.emitter.emit(X.QUEUE, e);
|
|
1296
981
|
}
|
|
1297
982
|
}
|
|
1298
|
-
class
|
|
983
|
+
class lt {
|
|
1299
984
|
/**
|
|
1300
985
|
* Gets or creates a unique user ID for the given project.
|
|
1301
986
|
* The user ID is persisted in localStorage and reused across sessions.
|
|
@@ -1304,15 +989,15 @@ class $t {
|
|
|
1304
989
|
* @param projectId - Project identifier for namespacing
|
|
1305
990
|
* @returns Persistent unique user ID
|
|
1306
991
|
*/
|
|
1307
|
-
static getId(e
|
|
1308
|
-
const
|
|
1309
|
-
if (
|
|
1310
|
-
return
|
|
1311
|
-
const
|
|
1312
|
-
return e.setItem(
|
|
992
|
+
static getId(e) {
|
|
993
|
+
const t = xe, r = e.getItem(t);
|
|
994
|
+
if (r)
|
|
995
|
+
return r;
|
|
996
|
+
const n = je();
|
|
997
|
+
return e.setItem(t, n), n;
|
|
1313
998
|
}
|
|
1314
999
|
}
|
|
1315
|
-
class
|
|
1000
|
+
class ut extends f {
|
|
1316
1001
|
storageManager;
|
|
1317
1002
|
eventManager;
|
|
1318
1003
|
projectId;
|
|
@@ -1322,23 +1007,23 @@ class Qt extends m {
|
|
|
1322
1007
|
visibilityChangeHandler = null;
|
|
1323
1008
|
beforeUnloadHandler = null;
|
|
1324
1009
|
isTracking = !1;
|
|
1325
|
-
constructor(e, t,
|
|
1326
|
-
super(), this.storageManager = e, this.eventManager = t, this.projectId =
|
|
1010
|
+
constructor(e, t, r) {
|
|
1011
|
+
super(), this.storageManager = e, this.eventManager = t, this.projectId = r;
|
|
1327
1012
|
}
|
|
1328
1013
|
initCrossTabSync() {
|
|
1329
1014
|
if (typeof BroadcastChannel > "u") {
|
|
1330
|
-
|
|
1015
|
+
o("warn", "BroadcastChannel not supported");
|
|
1331
1016
|
return;
|
|
1332
1017
|
}
|
|
1333
1018
|
const e = this.getProjectId();
|
|
1334
|
-
this.broadcastChannel = new BroadcastChannel(
|
|
1335
|
-
const { action:
|
|
1336
|
-
if (
|
|
1337
|
-
if (
|
|
1338
|
-
|
|
1019
|
+
this.broadcastChannel = new BroadcastChannel(Ge(e)), this.broadcastChannel.onmessage = (t) => {
|
|
1020
|
+
const { action: r, sessionId: n, timestamp: i, projectId: a } = t.data ?? {};
|
|
1021
|
+
if (a === e) {
|
|
1022
|
+
if (r === "session_end") {
|
|
1023
|
+
this.resetSessionState();
|
|
1339
1024
|
return;
|
|
1340
1025
|
}
|
|
1341
|
-
|
|
1026
|
+
n && typeof i == "number" && i > Date.now() - 5e3 && (this.set("sessionId", n), this.set("hasStartSession", !0), this.persistSession(n, i), this.isTracking && this.setupSessionTimeout());
|
|
1342
1027
|
}
|
|
1343
1028
|
};
|
|
1344
1029
|
}
|
|
@@ -1366,8 +1051,8 @@ class Qt extends m {
|
|
|
1366
1051
|
const e = this.loadStoredSession();
|
|
1367
1052
|
if (!e)
|
|
1368
1053
|
return null;
|
|
1369
|
-
const t = this.get("config")?.sessionTimeout ??
|
|
1370
|
-
return Date.now() - e.lastActivity > t ? (
|
|
1054
|
+
const t = this.get("config")?.sessionTimeout ?? 9e5;
|
|
1055
|
+
return Date.now() - e.lastActivity > t ? (this.clearStoredSession(), null) : e.id;
|
|
1371
1056
|
}
|
|
1372
1057
|
persistSession(e, t = Date.now()) {
|
|
1373
1058
|
this.saveStoredSession({
|
|
@@ -1384,8 +1069,8 @@ class Qt extends m {
|
|
|
1384
1069
|
if (!t)
|
|
1385
1070
|
return null;
|
|
1386
1071
|
try {
|
|
1387
|
-
const
|
|
1388
|
-
return !
|
|
1072
|
+
const r = JSON.parse(t);
|
|
1073
|
+
return !r.id || typeof r.lastActivity != "number" ? null : r;
|
|
1389
1074
|
} catch {
|
|
1390
1075
|
return this.storageManager.removeItem(e), null;
|
|
1391
1076
|
}
|
|
@@ -1395,24 +1080,24 @@ class Qt extends m {
|
|
|
1395
1080
|
this.storageManager.setItem(t, JSON.stringify(e));
|
|
1396
1081
|
}
|
|
1397
1082
|
getSessionStorageKey() {
|
|
1398
|
-
return
|
|
1083
|
+
return Fe(this.getProjectId());
|
|
1399
1084
|
}
|
|
1400
1085
|
getProjectId() {
|
|
1401
1086
|
return this.projectId;
|
|
1402
1087
|
}
|
|
1403
1088
|
async startTracking() {
|
|
1404
1089
|
if (this.isTracking) {
|
|
1405
|
-
|
|
1090
|
+
o("warn", "Session tracking already active");
|
|
1406
1091
|
return;
|
|
1407
1092
|
}
|
|
1408
|
-
const e = this.recoverSession(), t = e ?? this.generateSessionId(),
|
|
1093
|
+
const e = this.recoverSession(), t = e ?? this.generateSessionId(), r = !!e;
|
|
1409
1094
|
this.isTracking = !0;
|
|
1410
1095
|
try {
|
|
1411
|
-
this.set("sessionId", t), this.persistSession(t),
|
|
1096
|
+
this.set("sessionId", t), this.persistSession(t), r || this.eventManager.track({
|
|
1412
1097
|
type: d.SESSION_START
|
|
1413
|
-
}), this.initCrossTabSync(), this.shareSession(t), this.setupSessionTimeout(), this.setupActivityListeners(), this.setupLifecycleListeners()
|
|
1414
|
-
} catch (
|
|
1415
|
-
throw this.isTracking = !1, this.clearSessionTimeout(), this.cleanupActivityListeners(), this.cleanupLifecycleListeners(), this.cleanupCrossTabSync(), this.set("sessionId", null),
|
|
1098
|
+
}), this.initCrossTabSync(), this.shareSession(t), this.setupSessionTimeout(), this.setupActivityListeners(), this.setupLifecycleListeners();
|
|
1099
|
+
} catch (n) {
|
|
1100
|
+
throw this.isTracking = !1, this.clearSessionTimeout(), this.cleanupActivityListeners(), this.cleanupLifecycleListeners(), this.cleanupCrossTabSync(), this.set("sessionId", null), n;
|
|
1416
1101
|
}
|
|
1417
1102
|
}
|
|
1418
1103
|
generateSessionId() {
|
|
@@ -1420,7 +1105,7 @@ class Qt extends m {
|
|
|
1420
1105
|
}
|
|
1421
1106
|
setupSessionTimeout() {
|
|
1422
1107
|
this.clearSessionTimeout();
|
|
1423
|
-
const e = this.get("config")?.sessionTimeout ??
|
|
1108
|
+
const e = this.get("config")?.sessionTimeout ?? 9e5;
|
|
1424
1109
|
this.sessionTimeoutId = setTimeout(() => {
|
|
1425
1110
|
this.endSession("inactivity");
|
|
1426
1111
|
}, e);
|
|
@@ -1452,26 +1137,24 @@ class Qt extends m {
|
|
|
1452
1137
|
async endSession(e) {
|
|
1453
1138
|
const t = this.get("sessionId");
|
|
1454
1139
|
if (!t) {
|
|
1455
|
-
|
|
1140
|
+
o("warn", "endSession called without active session", { data: { reason: e } }), this.resetSessionState(e);
|
|
1456
1141
|
return;
|
|
1457
1142
|
}
|
|
1458
|
-
|
|
1143
|
+
this.eventManager.track({
|
|
1459
1144
|
type: d.SESSION_END,
|
|
1460
1145
|
session_end_reason: e
|
|
1461
1146
|
});
|
|
1462
|
-
const
|
|
1147
|
+
const r = () => {
|
|
1463
1148
|
this.broadcastSessionEnd(t, e), this.resetSessionState(e);
|
|
1464
1149
|
};
|
|
1465
1150
|
if (this.eventManager.flushImmediatelySync()) {
|
|
1466
|
-
|
|
1151
|
+
r();
|
|
1467
1152
|
return;
|
|
1468
1153
|
}
|
|
1469
1154
|
try {
|
|
1470
|
-
await this.eventManager.flushImmediately(),
|
|
1155
|
+
await this.eventManager.flushImmediately(), r();
|
|
1471
1156
|
} catch (i) {
|
|
1472
|
-
|
|
1473
|
-
error: i instanceof Error ? i.message : "Unknown error"
|
|
1474
|
-
}), n();
|
|
1157
|
+
o("warn", "Async flush failed during session end", { error: i }), r();
|
|
1475
1158
|
}
|
|
1476
1159
|
}
|
|
1477
1160
|
resetSessionState(e) {
|
|
@@ -1484,7 +1167,7 @@ class Qt extends m {
|
|
|
1484
1167
|
this.clearSessionTimeout(), this.cleanupActivityListeners(), this.cleanupCrossTabSync(), this.cleanupLifecycleListeners(), this.isTracking = !1, this.set("hasStartSession", !1);
|
|
1485
1168
|
}
|
|
1486
1169
|
}
|
|
1487
|
-
class
|
|
1170
|
+
class dt extends f {
|
|
1488
1171
|
eventManager;
|
|
1489
1172
|
storageManager;
|
|
1490
1173
|
sessionManager = null;
|
|
@@ -1496,15 +1179,15 @@ class Bt extends m {
|
|
|
1496
1179
|
if (this.isActive())
|
|
1497
1180
|
return;
|
|
1498
1181
|
if (this.destroyed) {
|
|
1499
|
-
|
|
1182
|
+
o("warn", "Cannot start tracking on destroyed handler");
|
|
1500
1183
|
return;
|
|
1501
1184
|
}
|
|
1502
|
-
const e = this.get("config")?.
|
|
1503
|
-
if (!
|
|
1185
|
+
const e = this.get("config"), t = e?.integrations?.tracelog?.projectId ?? e?.integrations?.custom?.apiUrl ?? "default";
|
|
1186
|
+
if (!t)
|
|
1504
1187
|
throw new Error("Cannot start session tracking: config not available");
|
|
1505
1188
|
try {
|
|
1506
|
-
this.sessionManager = new
|
|
1507
|
-
} catch (
|
|
1189
|
+
this.sessionManager = new ut(this.storageManager, this.eventManager, t), await this.sessionManager.startTracking(), this.eventManager.flushPendingEvents();
|
|
1190
|
+
} catch (r) {
|
|
1508
1191
|
if (this.sessionManager) {
|
|
1509
1192
|
try {
|
|
1510
1193
|
this.sessionManager.destroy();
|
|
@@ -1512,9 +1195,7 @@ class Bt extends m {
|
|
|
1512
1195
|
}
|
|
1513
1196
|
this.sessionManager = null;
|
|
1514
1197
|
}
|
|
1515
|
-
throw
|
|
1516
|
-
error: t instanceof Error ? t.message : "Unknown error"
|
|
1517
|
-
}), t;
|
|
1198
|
+
throw o("error", "Failed to start session tracking", { error: r }), r;
|
|
1518
1199
|
}
|
|
1519
1200
|
}
|
|
1520
1201
|
isActive() {
|
|
@@ -1530,7 +1211,7 @@ class Bt extends m {
|
|
|
1530
1211
|
this.destroyed || (this.sessionManager && (this.sessionManager.destroy(), this.sessionManager = null), this.destroyed = !0, this.set("hasStartSession", !1));
|
|
1531
1212
|
}
|
|
1532
1213
|
}
|
|
1533
|
-
class
|
|
1214
|
+
class ht extends f {
|
|
1534
1215
|
eventManager;
|
|
1535
1216
|
onTrack;
|
|
1536
1217
|
originalPushState;
|
|
@@ -1539,34 +1220,34 @@ class Wt extends m {
|
|
|
1539
1220
|
super(), this.eventManager = e, this.onTrack = t;
|
|
1540
1221
|
}
|
|
1541
1222
|
startTracking() {
|
|
1542
|
-
|
|
1223
|
+
this.trackInitialPageView(), window.addEventListener("popstate", this.trackCurrentPage, !0), window.addEventListener("hashchange", this.trackCurrentPage, !0), this.patchHistory("pushState"), this.patchHistory("replaceState");
|
|
1543
1224
|
}
|
|
1544
1225
|
stopTracking() {
|
|
1545
|
-
|
|
1226
|
+
window.removeEventListener("popstate", this.trackCurrentPage, !0), window.removeEventListener("hashchange", this.trackCurrentPage, !0), this.originalPushState && (window.history.pushState = this.originalPushState), this.originalReplaceState && (window.history.replaceState = this.originalReplaceState);
|
|
1546
1227
|
}
|
|
1547
1228
|
patchHistory(e) {
|
|
1548
1229
|
const t = window.history[e];
|
|
1549
|
-
e === "pushState" && !this.originalPushState ? this.originalPushState = t : e === "replaceState" && !this.originalReplaceState && (this.originalReplaceState = t), window.history[e] = (...
|
|
1550
|
-
t.apply(window.history,
|
|
1230
|
+
e === "pushState" && !this.originalPushState ? this.originalPushState = t : e === "replaceState" && !this.originalReplaceState && (this.originalReplaceState = t), window.history[e] = (...r) => {
|
|
1231
|
+
t.apply(window.history, r), this.trackCurrentPage();
|
|
1551
1232
|
};
|
|
1552
1233
|
}
|
|
1553
1234
|
trackCurrentPage = async () => {
|
|
1554
|
-
const e = window.location.href, t =
|
|
1235
|
+
const e = window.location.href, t = Y(e, this.get("config").sensitiveQueryParams);
|
|
1555
1236
|
if (this.get("pageUrl") === t)
|
|
1556
1237
|
return;
|
|
1557
1238
|
this.onTrack();
|
|
1558
|
-
const
|
|
1559
|
-
|
|
1560
|
-
const
|
|
1239
|
+
const r = this.get("pageUrl");
|
|
1240
|
+
this.set("pageUrl", t);
|
|
1241
|
+
const n = this.extractPageViewData();
|
|
1561
1242
|
this.eventManager.track({
|
|
1562
1243
|
type: d.PAGE_VIEW,
|
|
1563
1244
|
page_url: this.get("pageUrl"),
|
|
1564
|
-
from_page_url:
|
|
1565
|
-
...
|
|
1245
|
+
from_page_url: r,
|
|
1246
|
+
...n && { page_view: n }
|
|
1566
1247
|
});
|
|
1567
1248
|
};
|
|
1568
1249
|
trackInitialPageView() {
|
|
1569
|
-
const e =
|
|
1250
|
+
const e = Y(window.location.href, this.get("config").sensitiveQueryParams), t = this.extractPageViewData();
|
|
1570
1251
|
this.eventManager.track({
|
|
1571
1252
|
type: d.PAGE_VIEW,
|
|
1572
1253
|
page_url: e,
|
|
@@ -1574,17 +1255,17 @@ class Wt extends m {
|
|
|
1574
1255
|
}), this.onTrack();
|
|
1575
1256
|
}
|
|
1576
1257
|
extractPageViewData() {
|
|
1577
|
-
const { pathname: e, search: t, hash:
|
|
1578
|
-
return !
|
|
1579
|
-
...
|
|
1258
|
+
const { pathname: e, search: t, hash: r } = window.location, { referrer: n } = document, { title: i } = document;
|
|
1259
|
+
return !n && !i && !e && !t && !r ? void 0 : {
|
|
1260
|
+
...n && { referrer: n },
|
|
1580
1261
|
...i && { title: i },
|
|
1581
1262
|
...e && { pathname: e },
|
|
1582
1263
|
...t && { search: t },
|
|
1583
|
-
...
|
|
1264
|
+
...r && { hash: r }
|
|
1584
1265
|
};
|
|
1585
1266
|
}
|
|
1586
1267
|
}
|
|
1587
|
-
class
|
|
1268
|
+
class ft extends f {
|
|
1588
1269
|
eventManager;
|
|
1589
1270
|
clickHandler;
|
|
1590
1271
|
constructor(e) {
|
|
@@ -1592,26 +1273,26 @@ class Yt extends m {
|
|
|
1592
1273
|
}
|
|
1593
1274
|
startTracking() {
|
|
1594
1275
|
this.clickHandler || (this.clickHandler = (e) => {
|
|
1595
|
-
const t = e,
|
|
1596
|
-
if (!
|
|
1597
|
-
|
|
1276
|
+
const t = e, r = t.target, n = r instanceof HTMLElement ? r : r instanceof Node && r.parentElement instanceof HTMLElement ? r.parentElement : null;
|
|
1277
|
+
if (!n) {
|
|
1278
|
+
o("warn", "Click target not found or not an element");
|
|
1598
1279
|
return;
|
|
1599
1280
|
}
|
|
1600
|
-
const i = this.findTrackingElement(
|
|
1281
|
+
const i = this.findTrackingElement(n), a = this.getRelevantClickElement(n), c = this.calculateClickCoordinates(t, n);
|
|
1601
1282
|
if (i) {
|
|
1602
1283
|
const u = this.extractTrackingData(i);
|
|
1603
1284
|
if (u) {
|
|
1604
|
-
const
|
|
1285
|
+
const p = this.createCustomEventData(u);
|
|
1605
1286
|
this.eventManager.track({
|
|
1606
1287
|
type: d.CUSTOM,
|
|
1607
1288
|
custom_event: {
|
|
1608
|
-
name:
|
|
1609
|
-
...
|
|
1289
|
+
name: p.name,
|
|
1290
|
+
...p.value && { metadata: { value: p.value } }
|
|
1610
1291
|
}
|
|
1611
1292
|
});
|
|
1612
1293
|
}
|
|
1613
1294
|
}
|
|
1614
|
-
const l = this.generateClickData(
|
|
1295
|
+
const l = this.generateClickData(n, a, c);
|
|
1615
1296
|
this.eventManager.track({
|
|
1616
1297
|
type: d.CLICK,
|
|
1617
1298
|
click_data: l
|
|
@@ -1622,21 +1303,18 @@ class Yt extends m {
|
|
|
1622
1303
|
this.clickHandler && (window.removeEventListener("click", this.clickHandler, !0), this.clickHandler = void 0);
|
|
1623
1304
|
}
|
|
1624
1305
|
findTrackingElement(e) {
|
|
1625
|
-
return e.hasAttribute(`${
|
|
1306
|
+
return e.hasAttribute(`${O}-name`) ? e : e.closest(`[${O}-name]`) || void 0;
|
|
1626
1307
|
}
|
|
1627
1308
|
getRelevantClickElement(e) {
|
|
1628
|
-
for (const t of
|
|
1309
|
+
for (const t of Ce)
|
|
1629
1310
|
try {
|
|
1630
1311
|
if (e.matches(t))
|
|
1631
1312
|
return e;
|
|
1632
|
-
const
|
|
1633
|
-
if (
|
|
1634
|
-
return
|
|
1635
|
-
} catch (
|
|
1636
|
-
|
|
1637
|
-
selector: t,
|
|
1638
|
-
error: n instanceof Error ? n.message : "Unknown error"
|
|
1639
|
-
});
|
|
1313
|
+
const r = e.closest(t);
|
|
1314
|
+
if (r)
|
|
1315
|
+
return r;
|
|
1316
|
+
} catch (r) {
|
|
1317
|
+
o("warn", "Invalid selector in element search", { error: r, data: { selector: t } });
|
|
1640
1318
|
continue;
|
|
1641
1319
|
}
|
|
1642
1320
|
return e;
|
|
@@ -1645,24 +1323,24 @@ class Yt extends m {
|
|
|
1645
1323
|
return Math.max(0, Math.min(1, Number(e.toFixed(3))));
|
|
1646
1324
|
}
|
|
1647
1325
|
calculateClickCoordinates(e, t) {
|
|
1648
|
-
const
|
|
1649
|
-
return { x:
|
|
1326
|
+
const r = t.getBoundingClientRect(), n = e.clientX, i = e.clientY, a = r.width > 0 ? this.clamp((n - r.left) / r.width) : 0, c = r.height > 0 ? this.clamp((i - r.top) / r.height) : 0;
|
|
1327
|
+
return { x: n, y: i, relativeX: a, relativeY: c };
|
|
1650
1328
|
}
|
|
1651
1329
|
extractTrackingData(e) {
|
|
1652
|
-
const t = e.getAttribute(`${
|
|
1330
|
+
const t = e.getAttribute(`${O}-name`), r = e.getAttribute(`${O}-value`);
|
|
1653
1331
|
if (t)
|
|
1654
1332
|
return {
|
|
1655
1333
|
element: e,
|
|
1656
1334
|
name: t,
|
|
1657
|
-
...
|
|
1335
|
+
...r && { value: r }
|
|
1658
1336
|
};
|
|
1659
1337
|
}
|
|
1660
|
-
generateClickData(e, t,
|
|
1661
|
-
const { x:
|
|
1338
|
+
generateClickData(e, t, r) {
|
|
1339
|
+
const { x: n, y: i, relativeX: a, relativeY: c } = r, l = this.getRelevantText(e, t), u = this.extractElementAttributes(t);
|
|
1662
1340
|
return {
|
|
1663
|
-
x:
|
|
1341
|
+
x: n,
|
|
1664
1342
|
y: i,
|
|
1665
|
-
relativeX:
|
|
1343
|
+
relativeX: a,
|
|
1666
1344
|
relativeY: c,
|
|
1667
1345
|
tag: t.tagName.toLowerCase(),
|
|
1668
1346
|
...t.id && { id: t.id },
|
|
@@ -1677,8 +1355,8 @@ class Yt extends m {
|
|
|
1677
1355
|
};
|
|
1678
1356
|
}
|
|
1679
1357
|
getRelevantText(e, t) {
|
|
1680
|
-
const
|
|
1681
|
-
return !
|
|
1358
|
+
const r = e.textContent?.trim() ?? "", n = t.textContent?.trim() ?? "";
|
|
1359
|
+
return !r && !n ? "" : r && r.length <= 255 ? r : n.length <= 255 ? n : n.slice(0, 252) + "...";
|
|
1682
1360
|
}
|
|
1683
1361
|
extractElementAttributes(e) {
|
|
1684
1362
|
const t = [
|
|
@@ -1692,12 +1370,12 @@ class Yt extends m {
|
|
|
1692
1370
|
"name",
|
|
1693
1371
|
"alt",
|
|
1694
1372
|
"role"
|
|
1695
|
-
],
|
|
1696
|
-
for (const
|
|
1697
|
-
const i = e.getAttribute(
|
|
1698
|
-
i && (n
|
|
1373
|
+
], r = {};
|
|
1374
|
+
for (const n of t) {
|
|
1375
|
+
const i = e.getAttribute(n);
|
|
1376
|
+
i && (r[n] = i);
|
|
1699
1377
|
}
|
|
1700
|
-
return
|
|
1378
|
+
return r;
|
|
1701
1379
|
}
|
|
1702
1380
|
createCustomEventData(e) {
|
|
1703
1381
|
return {
|
|
@@ -1706,13 +1384,13 @@ class Yt extends m {
|
|
|
1706
1384
|
};
|
|
1707
1385
|
}
|
|
1708
1386
|
}
|
|
1709
|
-
class
|
|
1387
|
+
class gt extends f {
|
|
1710
1388
|
eventManager;
|
|
1711
1389
|
containers = [];
|
|
1712
1390
|
limitWarningLogged = !1;
|
|
1713
|
-
minDepthChange =
|
|
1714
|
-
minIntervalMs =
|
|
1715
|
-
maxEventsPerSession =
|
|
1391
|
+
minDepthChange = 5;
|
|
1392
|
+
minIntervalMs = 500;
|
|
1393
|
+
maxEventsPerSession = 120;
|
|
1716
1394
|
constructor(e) {
|
|
1717
1395
|
super(), this.eventManager = e;
|
|
1718
1396
|
}
|
|
@@ -1727,10 +1405,10 @@ class Kt extends m {
|
|
|
1727
1405
|
this.containers.length = 0, this.set("scrollEventCount", 0), this.limitWarningLogged = !1;
|
|
1728
1406
|
}
|
|
1729
1407
|
trySetupContainers(e, t) {
|
|
1730
|
-
const
|
|
1731
|
-
if (
|
|
1732
|
-
for (const
|
|
1733
|
-
this.containers.some((
|
|
1408
|
+
const r = e.map((n) => this.safeQuerySelector(n)).filter((n) => n instanceof HTMLElement);
|
|
1409
|
+
if (r.length > 0) {
|
|
1410
|
+
for (const n of r)
|
|
1411
|
+
this.containers.some((a) => a.element === n) || this.setupScrollContainer(n);
|
|
1734
1412
|
return;
|
|
1735
1413
|
}
|
|
1736
1414
|
if (t < 5) {
|
|
@@ -1743,41 +1421,41 @@ class Kt extends m {
|
|
|
1743
1421
|
if (e !== window && !this.isElementScrollable(e))
|
|
1744
1422
|
return;
|
|
1745
1423
|
const t = () => {
|
|
1746
|
-
this.get("suppressNextScroll") || (this.clearContainerTimer(
|
|
1747
|
-
const i = this.calculateScrollData(
|
|
1424
|
+
this.get("suppressNextScroll") || (this.clearContainerTimer(n), n.debounceTimer = window.setTimeout(() => {
|
|
1425
|
+
const i = this.calculateScrollData(n);
|
|
1748
1426
|
if (i) {
|
|
1749
|
-
const
|
|
1750
|
-
this.processScrollEvent(
|
|
1427
|
+
const a = Date.now();
|
|
1428
|
+
this.processScrollEvent(n, i, a);
|
|
1751
1429
|
}
|
|
1752
|
-
|
|
1753
|
-
},
|
|
1754
|
-
},
|
|
1430
|
+
n.debounceTimer = null;
|
|
1431
|
+
}, 250));
|
|
1432
|
+
}, r = this.getScrollTop(e), n = {
|
|
1755
1433
|
element: e,
|
|
1756
|
-
lastScrollPos:
|
|
1434
|
+
lastScrollPos: r,
|
|
1757
1435
|
lastDepth: this.calculateScrollDepth(
|
|
1758
|
-
|
|
1436
|
+
r,
|
|
1759
1437
|
this.getScrollHeight(e),
|
|
1760
1438
|
this.getViewportHeight(e)
|
|
1761
1439
|
),
|
|
1762
|
-
lastDirection:
|
|
1440
|
+
lastDirection: D.DOWN,
|
|
1763
1441
|
lastEventTime: 0,
|
|
1764
1442
|
debounceTimer: null,
|
|
1765
1443
|
listener: t
|
|
1766
1444
|
};
|
|
1767
|
-
this.containers.push(
|
|
1445
|
+
this.containers.push(n), e instanceof Window ? window.addEventListener("scroll", t, { passive: !0 }) : e.addEventListener("scroll", t, { passive: !0 });
|
|
1768
1446
|
}
|
|
1769
|
-
processScrollEvent(e, t,
|
|
1770
|
-
if (!this.shouldEmitScrollEvent(e, t,
|
|
1447
|
+
processScrollEvent(e, t, r) {
|
|
1448
|
+
if (!this.shouldEmitScrollEvent(e, t, r))
|
|
1771
1449
|
return;
|
|
1772
|
-
e.lastEventTime =
|
|
1773
|
-
const
|
|
1774
|
-
this.set("scrollEventCount",
|
|
1450
|
+
e.lastEventTime = r, e.lastDepth = t.depth, e.lastDirection = t.direction;
|
|
1451
|
+
const n = this.get("scrollEventCount") ?? 0;
|
|
1452
|
+
this.set("scrollEventCount", n + 1), this.eventManager.track({
|
|
1775
1453
|
type: d.SCROLL,
|
|
1776
1454
|
scroll_data: t
|
|
1777
1455
|
});
|
|
1778
1456
|
}
|
|
1779
|
-
shouldEmitScrollEvent(e, t,
|
|
1780
|
-
return this.hasReachedSessionLimit() ? (this.logLimitOnce(), !1) : !(!this.hasElapsedMinimumInterval(e,
|
|
1457
|
+
shouldEmitScrollEvent(e, t, r) {
|
|
1458
|
+
return this.hasReachedSessionLimit() ? (this.logLimitOnce(), !1) : !(!this.hasElapsedMinimumInterval(e, r) || !this.hasSignificantDepthChange(e, t.depth));
|
|
1781
1459
|
}
|
|
1782
1460
|
hasReachedSessionLimit() {
|
|
1783
1461
|
return (this.get("scrollEventCount") ?? 0) >= this.maxEventsPerSession;
|
|
@@ -1789,12 +1467,12 @@ class Kt extends m {
|
|
|
1789
1467
|
return Math.abs(t - e.lastDepth) >= this.minDepthChange;
|
|
1790
1468
|
}
|
|
1791
1469
|
logLimitOnce() {
|
|
1792
|
-
this.limitWarningLogged || (this.limitWarningLogged = !0,
|
|
1793
|
-
limit: this.maxEventsPerSession
|
|
1470
|
+
this.limitWarningLogged || (this.limitWarningLogged = !0, o("warn", "Max scroll events per session reached", {
|
|
1471
|
+
data: { limit: this.maxEventsPerSession }
|
|
1794
1472
|
}));
|
|
1795
1473
|
}
|
|
1796
1474
|
applyConfigOverrides() {
|
|
1797
|
-
this.minDepthChange =
|
|
1475
|
+
this.minDepthChange = 5, this.minIntervalMs = 500, this.maxEventsPerSession = 120;
|
|
1798
1476
|
}
|
|
1799
1477
|
isWindowScrollable() {
|
|
1800
1478
|
return document.documentElement.scrollHeight > window.innerHeight;
|
|
@@ -1803,20 +1481,20 @@ class Kt extends m {
|
|
|
1803
1481
|
e.debounceTimer !== null && (clearTimeout(e.debounceTimer), e.debounceTimer = null);
|
|
1804
1482
|
}
|
|
1805
1483
|
getScrollDirection(e, t) {
|
|
1806
|
-
return e > t ?
|
|
1484
|
+
return e > t ? D.DOWN : D.UP;
|
|
1807
1485
|
}
|
|
1808
|
-
calculateScrollDepth(e, t,
|
|
1809
|
-
if (t <=
|
|
1486
|
+
calculateScrollDepth(e, t, r) {
|
|
1487
|
+
if (t <= r)
|
|
1810
1488
|
return 0;
|
|
1811
|
-
const
|
|
1812
|
-
return Math.min(100, Math.max(0, Math.floor(e /
|
|
1489
|
+
const n = t - r;
|
|
1490
|
+
return Math.min(100, Math.max(0, Math.floor(e / n * 100)));
|
|
1813
1491
|
}
|
|
1814
1492
|
calculateScrollData(e) {
|
|
1815
|
-
const { element: t, lastScrollPos:
|
|
1816
|
-
if (Math.abs(
|
|
1493
|
+
const { element: t, lastScrollPos: r } = e, n = this.getScrollTop(t);
|
|
1494
|
+
if (Math.abs(n - r) < 10 || t === window && !this.isWindowScrollable())
|
|
1817
1495
|
return null;
|
|
1818
|
-
const
|
|
1819
|
-
return e.lastScrollPos =
|
|
1496
|
+
const a = this.getViewportHeight(t), c = this.getScrollHeight(t), l = this.getScrollDirection(n, r), u = this.calculateScrollDepth(n, c, a);
|
|
1497
|
+
return e.lastScrollPos = n, { depth: u, direction: l };
|
|
1820
1498
|
}
|
|
1821
1499
|
getScrollTop(e) {
|
|
1822
1500
|
return e instanceof Window ? window.scrollY : e.scrollTop;
|
|
@@ -1828,21 +1506,22 @@ class Kt extends m {
|
|
|
1828
1506
|
return e instanceof Window ? document.documentElement.scrollHeight : e.scrollHeight;
|
|
1829
1507
|
}
|
|
1830
1508
|
isElementScrollable(e) {
|
|
1831
|
-
const t = getComputedStyle(e),
|
|
1832
|
-
return
|
|
1509
|
+
const t = getComputedStyle(e), r = t.overflowY === "auto" || t.overflowY === "scroll" || t.overflowX === "auto" || t.overflowX === "scroll" || t.overflow === "auto" || t.overflow === "scroll", n = e.scrollHeight > e.clientHeight || e.scrollWidth > e.clientWidth;
|
|
1510
|
+
return r && n;
|
|
1833
1511
|
}
|
|
1834
1512
|
safeQuerySelector(e) {
|
|
1835
1513
|
try {
|
|
1836
1514
|
return document.querySelector(e);
|
|
1837
1515
|
} catch (t) {
|
|
1838
|
-
return
|
|
1839
|
-
|
|
1840
|
-
|
|
1516
|
+
return o("warn", "Invalid CSS selector", {
|
|
1517
|
+
error: t,
|
|
1518
|
+
data: { selector: e },
|
|
1519
|
+
showToClient: !0
|
|
1841
1520
|
}), null;
|
|
1842
1521
|
}
|
|
1843
1522
|
}
|
|
1844
1523
|
}
|
|
1845
|
-
class
|
|
1524
|
+
class St extends f {
|
|
1846
1525
|
isInitialized = !1;
|
|
1847
1526
|
async initialize() {
|
|
1848
1527
|
if (this.isInitialized)
|
|
@@ -1855,21 +1534,17 @@ class Xt extends m {
|
|
|
1855
1534
|
return;
|
|
1856
1535
|
}
|
|
1857
1536
|
await this.loadScript(e), this.configureGtag(e, t), this.isInitialized = !0;
|
|
1858
|
-
} catch (
|
|
1859
|
-
|
|
1860
|
-
error: n instanceof Error ? n.message : "Unknown error"
|
|
1861
|
-
});
|
|
1537
|
+
} catch (r) {
|
|
1538
|
+
o("error", "Google Analytics initialization failed", { error: r });
|
|
1862
1539
|
}
|
|
1863
1540
|
}
|
|
1864
1541
|
trackEvent(e, t) {
|
|
1865
1542
|
if (!(!e?.trim() || !this.isInitialized || typeof window.gtag != "function"))
|
|
1866
1543
|
try {
|
|
1867
|
-
const
|
|
1868
|
-
window.gtag("event", e,
|
|
1869
|
-
} catch (
|
|
1870
|
-
|
|
1871
|
-
error: n instanceof Error ? n.message : "Unknown error"
|
|
1872
|
-
});
|
|
1544
|
+
const r = Array.isArray(t) ? { items: t } : t;
|
|
1545
|
+
window.gtag("event", e, r);
|
|
1546
|
+
} catch (r) {
|
|
1547
|
+
o("error", "Google Analytics event tracking failed", { error: r });
|
|
1873
1548
|
}
|
|
1874
1549
|
}
|
|
1875
1550
|
cleanup() {
|
|
@@ -1881,29 +1556,31 @@ class Xt extends m {
|
|
|
1881
1556
|
return document.getElementById("tracelog-ga-script") ? !0 : !!document.querySelector('script[src*="googletagmanager.com/gtag/js"]');
|
|
1882
1557
|
}
|
|
1883
1558
|
async loadScript(e) {
|
|
1884
|
-
return new Promise((t,
|
|
1885
|
-
const
|
|
1886
|
-
|
|
1559
|
+
return new Promise((t, r) => {
|
|
1560
|
+
const n = document.createElement("script");
|
|
1561
|
+
n.id = "tracelog-ga-script", n.async = !0, n.src = `https://www.googletagmanager.com/gtag/js?id=${e}`, n.onload = () => t(), n.onerror = () => r(new Error("Failed to load Google Analytics script")), document.head.appendChild(n);
|
|
1887
1562
|
});
|
|
1888
1563
|
}
|
|
1889
1564
|
configureGtag(e, t) {
|
|
1890
|
-
const
|
|
1891
|
-
|
|
1565
|
+
const r = document.createElement("script");
|
|
1566
|
+
r.innerHTML = `
|
|
1892
1567
|
window.dataLayer = window.dataLayer || [];
|
|
1893
1568
|
function gtag(){dataLayer.push(arguments);}
|
|
1894
1569
|
gtag('js', new Date());
|
|
1895
1570
|
gtag('config', '${e}', {
|
|
1896
1571
|
'user_id': '${t}'
|
|
1897
1572
|
});
|
|
1898
|
-
`, document.head.appendChild(
|
|
1573
|
+
`, document.head.appendChild(r);
|
|
1899
1574
|
}
|
|
1900
1575
|
}
|
|
1901
|
-
class
|
|
1576
|
+
class Et {
|
|
1902
1577
|
storage;
|
|
1578
|
+
sessionStorageRef;
|
|
1903
1579
|
fallbackStorage = /* @__PURE__ */ new Map();
|
|
1580
|
+
fallbackSessionStorage = /* @__PURE__ */ new Map();
|
|
1904
1581
|
hasQuotaExceededError = !1;
|
|
1905
1582
|
constructor() {
|
|
1906
|
-
this.storage = this.initializeStorage(), this.storage ||
|
|
1583
|
+
this.storage = this.initializeStorage("localStorage"), this.sessionStorageRef = this.initializeStorage("sessionStorage"), this.storage || o("warn", "localStorage not available, using memory fallback"), this.sessionStorageRef || o("warn", "sessionStorage not available, using memory fallback");
|
|
1907
1584
|
}
|
|
1908
1585
|
/**
|
|
1909
1586
|
* Retrieves an item from storage
|
|
@@ -1911,26 +1588,42 @@ class qt {
|
|
|
1911
1588
|
getItem(e) {
|
|
1912
1589
|
try {
|
|
1913
1590
|
return this.storage ? this.storage.getItem(e) : this.fallbackStorage.get(e) ?? null;
|
|
1914
|
-
} catch
|
|
1915
|
-
return
|
|
1591
|
+
} catch {
|
|
1592
|
+
return this.fallbackStorage.get(e) ?? null;
|
|
1916
1593
|
}
|
|
1917
1594
|
}
|
|
1918
1595
|
/**
|
|
1919
1596
|
* Stores an item in storage
|
|
1920
1597
|
*/
|
|
1921
1598
|
setItem(e, t) {
|
|
1599
|
+
this.fallbackStorage.set(e, t);
|
|
1922
1600
|
try {
|
|
1923
1601
|
if (this.storage) {
|
|
1924
1602
|
this.storage.setItem(e, t);
|
|
1925
1603
|
return;
|
|
1926
1604
|
}
|
|
1927
|
-
} catch (
|
|
1928
|
-
|
|
1929
|
-
|
|
1930
|
-
|
|
1931
|
-
|
|
1605
|
+
} catch (r) {
|
|
1606
|
+
if (r instanceof DOMException && r.name === "QuotaExceededError")
|
|
1607
|
+
if (this.hasQuotaExceededError = !0, o("warn", "localStorage quota exceeded, attempting cleanup", {
|
|
1608
|
+
data: { key: e, valueSize: t.length }
|
|
1609
|
+
}), this.cleanupOldData())
|
|
1610
|
+
try {
|
|
1611
|
+
if (this.storage) {
|
|
1612
|
+
this.storage.setItem(e, t);
|
|
1613
|
+
return;
|
|
1614
|
+
}
|
|
1615
|
+
} catch (i) {
|
|
1616
|
+
o("error", "localStorage quota exceeded even after cleanup - data will not persist", {
|
|
1617
|
+
error: i,
|
|
1618
|
+
data: { key: e, valueSize: t.length }
|
|
1619
|
+
});
|
|
1620
|
+
}
|
|
1621
|
+
else
|
|
1622
|
+
o("error", "localStorage quota exceeded and no data to cleanup - data will not persist", {
|
|
1623
|
+
error: r,
|
|
1624
|
+
data: { key: e, valueSize: t.length }
|
|
1625
|
+
});
|
|
1932
1626
|
}
|
|
1933
|
-
this.fallbackStorage.set(e, t);
|
|
1934
1627
|
}
|
|
1935
1628
|
/**
|
|
1936
1629
|
* Removes an item from storage
|
|
@@ -1938,8 +1631,7 @@ class qt {
|
|
|
1938
1631
|
removeItem(e) {
|
|
1939
1632
|
try {
|
|
1940
1633
|
this.storage && this.storage.removeItem(e);
|
|
1941
|
-
} catch
|
|
1942
|
-
a.warn("StorageManager", "Failed to remove item", { key: e, error: t });
|
|
1634
|
+
} catch {
|
|
1943
1635
|
}
|
|
1944
1636
|
this.fallbackStorage.delete(e);
|
|
1945
1637
|
}
|
|
@@ -1954,12 +1646,12 @@ class qt {
|
|
|
1954
1646
|
try {
|
|
1955
1647
|
const e = [];
|
|
1956
1648
|
for (let t = 0; t < this.storage.length; t++) {
|
|
1957
|
-
const
|
|
1958
|
-
|
|
1649
|
+
const r = this.storage.key(t);
|
|
1650
|
+
r?.startsWith("tracelog_") && e.push(r);
|
|
1959
1651
|
}
|
|
1960
|
-
e.forEach((t) => this.storage.removeItem(t)), this.fallbackStorage.clear()
|
|
1652
|
+
e.forEach((t) => this.storage.removeItem(t)), this.fallbackStorage.clear();
|
|
1961
1653
|
} catch (e) {
|
|
1962
|
-
|
|
1654
|
+
o("error", "Failed to clear storage", { error: e }), this.fallbackStorage.clear();
|
|
1963
1655
|
}
|
|
1964
1656
|
}
|
|
1965
1657
|
/**
|
|
@@ -1976,25 +1668,93 @@ class qt {
|
|
|
1976
1668
|
return this.hasQuotaExceededError;
|
|
1977
1669
|
}
|
|
1978
1670
|
/**
|
|
1979
|
-
*
|
|
1671
|
+
* Attempts to cleanup old TraceLog data from storage to free up space
|
|
1672
|
+
* Returns true if any data was removed, false otherwise
|
|
1980
1673
|
*/
|
|
1981
|
-
|
|
1674
|
+
cleanupOldData() {
|
|
1675
|
+
if (!this.storage)
|
|
1676
|
+
return !1;
|
|
1677
|
+
try {
|
|
1678
|
+
const e = [], t = [];
|
|
1679
|
+
for (let i = 0; i < this.storage.length; i++) {
|
|
1680
|
+
const a = this.storage.key(i);
|
|
1681
|
+
a?.startsWith("tracelog_") && (e.push(a), a.startsWith("tracelog_persisted_events_") && t.push(a));
|
|
1682
|
+
}
|
|
1683
|
+
if (t.length > 0)
|
|
1684
|
+
return t.forEach((i) => {
|
|
1685
|
+
try {
|
|
1686
|
+
this.storage.removeItem(i);
|
|
1687
|
+
} catch {
|
|
1688
|
+
}
|
|
1689
|
+
}), !0;
|
|
1690
|
+
const r = ["tracelog_session_", "tracelog_user_id", "tracelog_device_id", "tracelog_config"], n = e.filter((i) => !r.some((a) => i.startsWith(a)));
|
|
1691
|
+
return n.length > 0 ? (n.slice(0, 5).forEach((a) => {
|
|
1692
|
+
try {
|
|
1693
|
+
this.storage.removeItem(a);
|
|
1694
|
+
} catch {
|
|
1695
|
+
}
|
|
1696
|
+
}), !0) : !1;
|
|
1697
|
+
} catch (e) {
|
|
1698
|
+
return o("error", "Failed to cleanup old data", { error: e }), !1;
|
|
1699
|
+
}
|
|
1700
|
+
}
|
|
1701
|
+
/**
|
|
1702
|
+
* Initialize storage (localStorage or sessionStorage) with feature detection
|
|
1703
|
+
*/
|
|
1704
|
+
initializeStorage(e) {
|
|
1982
1705
|
if (typeof window > "u")
|
|
1983
1706
|
return null;
|
|
1984
1707
|
try {
|
|
1985
|
-
const
|
|
1986
|
-
return
|
|
1708
|
+
const t = e === "localStorage" ? window.localStorage : window.sessionStorage, r = "__tracelog_test__";
|
|
1709
|
+
return t.setItem(r, "test"), t.removeItem(r), t;
|
|
1987
1710
|
} catch {
|
|
1988
1711
|
return null;
|
|
1989
1712
|
}
|
|
1990
1713
|
}
|
|
1714
|
+
/**
|
|
1715
|
+
* Retrieves an item from sessionStorage
|
|
1716
|
+
*/
|
|
1717
|
+
getSessionItem(e) {
|
|
1718
|
+
try {
|
|
1719
|
+
return this.sessionStorageRef ? this.sessionStorageRef.getItem(e) : this.fallbackSessionStorage.get(e) ?? null;
|
|
1720
|
+
} catch {
|
|
1721
|
+
return this.fallbackSessionStorage.get(e) ?? null;
|
|
1722
|
+
}
|
|
1723
|
+
}
|
|
1724
|
+
/**
|
|
1725
|
+
* Stores an item in sessionStorage
|
|
1726
|
+
*/
|
|
1727
|
+
setSessionItem(e, t) {
|
|
1728
|
+
this.fallbackSessionStorage.set(e, t);
|
|
1729
|
+
try {
|
|
1730
|
+
if (this.sessionStorageRef) {
|
|
1731
|
+
this.sessionStorageRef.setItem(e, t);
|
|
1732
|
+
return;
|
|
1733
|
+
}
|
|
1734
|
+
} catch (r) {
|
|
1735
|
+
r instanceof DOMException && r.name === "QuotaExceededError" && o("error", "sessionStorage quota exceeded - data will not persist", {
|
|
1736
|
+
error: r,
|
|
1737
|
+
data: { key: e, valueSize: t.length }
|
|
1738
|
+
});
|
|
1739
|
+
}
|
|
1740
|
+
}
|
|
1741
|
+
/**
|
|
1742
|
+
* Removes an item from sessionStorage
|
|
1743
|
+
*/
|
|
1744
|
+
removeSessionItem(e) {
|
|
1745
|
+
try {
|
|
1746
|
+
this.sessionStorageRef && this.sessionStorageRef.removeItem(e);
|
|
1747
|
+
} catch {
|
|
1748
|
+
}
|
|
1749
|
+
this.fallbackSessionStorage.delete(e);
|
|
1750
|
+
}
|
|
1991
1751
|
}
|
|
1992
|
-
class
|
|
1752
|
+
class mt extends f {
|
|
1993
1753
|
eventManager;
|
|
1994
1754
|
reportedByNav = /* @__PURE__ */ new Map();
|
|
1995
1755
|
observers = [];
|
|
1996
1756
|
lastLongTaskSentAt = 0;
|
|
1997
|
-
vitalThresholds =
|
|
1757
|
+
vitalThresholds = _e;
|
|
1998
1758
|
constructor(e) {
|
|
1999
1759
|
super(), this.eventManager = e;
|
|
2000
1760
|
}
|
|
@@ -2005,20 +1765,17 @@ class Jt extends m {
|
|
|
2005
1765
|
this.observers.forEach((e, t) => {
|
|
2006
1766
|
try {
|
|
2007
1767
|
e.disconnect();
|
|
2008
|
-
} catch (
|
|
2009
|
-
|
|
2010
|
-
error: n instanceof Error ? n.message : "Unknown error",
|
|
2011
|
-
observerIndex: t
|
|
2012
|
-
});
|
|
1768
|
+
} catch (r) {
|
|
1769
|
+
o("warn", "Failed to disconnect performance observer", { error: r, data: { observerIndex: t } });
|
|
2013
1770
|
}
|
|
2014
1771
|
}), this.observers.length = 0, this.reportedByNav.clear();
|
|
2015
1772
|
}
|
|
2016
1773
|
observeWebVitalsFallback() {
|
|
2017
1774
|
this.reportTTFB(), this.safeObserve(
|
|
2018
1775
|
"largest-contentful-paint",
|
|
2019
|
-
(
|
|
2020
|
-
const
|
|
2021
|
-
i && this.sendVital({ type: "LCP", value: Number(i.startTime.toFixed(
|
|
1776
|
+
(r) => {
|
|
1777
|
+
const n = r.getEntries(), i = n[n.length - 1];
|
|
1778
|
+
i && this.sendVital({ type: "LCP", value: Number(i.startTime.toFixed(2)) });
|
|
2022
1779
|
},
|
|
2023
1780
|
{ type: "largest-contentful-paint", buffered: !0 },
|
|
2024
1781
|
!0
|
|
@@ -2026,52 +1783,50 @@ class Jt extends m {
|
|
|
2026
1783
|
let e = 0, t = this.getNavigationId();
|
|
2027
1784
|
this.safeObserve(
|
|
2028
1785
|
"layout-shift",
|
|
2029
|
-
(
|
|
2030
|
-
const
|
|
2031
|
-
|
|
2032
|
-
const i =
|
|
2033
|
-
for (const
|
|
2034
|
-
if (
|
|
1786
|
+
(r) => {
|
|
1787
|
+
const n = this.getNavigationId();
|
|
1788
|
+
n !== t && (e = 0, t = n);
|
|
1789
|
+
const i = r.getEntries();
|
|
1790
|
+
for (const a of i) {
|
|
1791
|
+
if (a.hadRecentInput === !0)
|
|
2035
1792
|
continue;
|
|
2036
|
-
const c = typeof
|
|
1793
|
+
const c = typeof a.value == "number" ? a.value : 0;
|
|
2037
1794
|
e += c;
|
|
2038
1795
|
}
|
|
2039
|
-
this.sendVital({ type: "CLS", value: Number(e.toFixed(
|
|
1796
|
+
this.sendVital({ type: "CLS", value: Number(e.toFixed(2)) });
|
|
2040
1797
|
},
|
|
2041
1798
|
{ type: "layout-shift", buffered: !0 }
|
|
2042
1799
|
), this.safeObserve(
|
|
2043
1800
|
"paint",
|
|
2044
|
-
(
|
|
2045
|
-
for (const
|
|
2046
|
-
|
|
1801
|
+
(r) => {
|
|
1802
|
+
for (const n of r.getEntries())
|
|
1803
|
+
n.name === "first-contentful-paint" && this.sendVital({ type: "FCP", value: Number(n.startTime.toFixed(2)) });
|
|
2047
1804
|
},
|
|
2048
1805
|
{ type: "paint", buffered: !0 },
|
|
2049
1806
|
!0
|
|
2050
1807
|
), this.safeObserve(
|
|
2051
1808
|
"event",
|
|
2052
|
-
(
|
|
2053
|
-
let
|
|
2054
|
-
const i =
|
|
2055
|
-
for (const
|
|
2056
|
-
const c = (
|
|
2057
|
-
|
|
1809
|
+
(r) => {
|
|
1810
|
+
let n = 0;
|
|
1811
|
+
const i = r.getEntries();
|
|
1812
|
+
for (const a of i) {
|
|
1813
|
+
const c = (a.processingEnd ?? 0) - (a.startTime ?? 0);
|
|
1814
|
+
n = Math.max(n, c);
|
|
2058
1815
|
}
|
|
2059
|
-
|
|
1816
|
+
n > 0 && this.sendVital({ type: "INP", value: Number(n.toFixed(2)) });
|
|
2060
1817
|
},
|
|
2061
1818
|
{ type: "event", buffered: !0 }
|
|
2062
1819
|
);
|
|
2063
1820
|
}
|
|
2064
1821
|
async initWebVitals() {
|
|
2065
1822
|
try {
|
|
2066
|
-
const { onLCP: e, onCLS: t, onFCP:
|
|
2067
|
-
const u = Number(l.value.toFixed(
|
|
1823
|
+
const { onLCP: e, onCLS: t, onFCP: r, onTTFB: n, onINP: i } = await Promise.resolve().then(() => Ht), a = (c) => (l) => {
|
|
1824
|
+
const u = Number(l.value.toFixed(2));
|
|
2068
1825
|
this.sendVital({ type: c, value: u });
|
|
2069
1826
|
};
|
|
2070
|
-
e(
|
|
1827
|
+
e(a("LCP")), t(a("CLS")), r(a("FCP")), n(a("TTFB")), i(a("INP"));
|
|
2071
1828
|
} catch (e) {
|
|
2072
|
-
|
|
2073
|
-
error: e instanceof Error ? e.message : "Unknown error"
|
|
2074
|
-
}), this.observeWebVitalsFallback();
|
|
1829
|
+
o("warn", "Failed to load web-vitals library, using fallback", { error: e }), this.observeWebVitalsFallback();
|
|
2075
1830
|
}
|
|
2076
1831
|
}
|
|
2077
1832
|
reportTTFB() {
|
|
@@ -2080,11 +1835,9 @@ class Jt extends m {
|
|
|
2080
1835
|
if (!e)
|
|
2081
1836
|
return;
|
|
2082
1837
|
const t = e.responseStart;
|
|
2083
|
-
typeof t == "number" && Number.isFinite(t) && this.sendVital({ type: "TTFB", value: Number(t.toFixed(
|
|
1838
|
+
typeof t == "number" && Number.isFinite(t) && this.sendVital({ type: "TTFB", value: Number(t.toFixed(2)) });
|
|
2084
1839
|
} catch (e) {
|
|
2085
|
-
|
|
2086
|
-
error: e instanceof Error ? e.message : "Unknown error"
|
|
2087
|
-
});
|
|
1840
|
+
o("warn", "Failed to report TTFB", { error: e });
|
|
2088
1841
|
}
|
|
2089
1842
|
}
|
|
2090
1843
|
observeLongTasks() {
|
|
@@ -2092,9 +1845,9 @@ class Jt extends m {
|
|
|
2092
1845
|
"longtask",
|
|
2093
1846
|
(e) => {
|
|
2094
1847
|
const t = e.getEntries();
|
|
2095
|
-
for (const
|
|
2096
|
-
const
|
|
2097
|
-
i - this.lastLongTaskSentAt >=
|
|
1848
|
+
for (const r of t) {
|
|
1849
|
+
const n = Number(r.duration.toFixed(2)), i = Date.now();
|
|
1850
|
+
i - this.lastLongTaskSentAt >= ze && (this.shouldSendVital("LONG_TASK", n) && this.trackWebVital("LONG_TASK", n), this.lastLongTaskSentAt = i);
|
|
2098
1851
|
}
|
|
2099
1852
|
},
|
|
2100
1853
|
{ type: "longtask", buffered: !0 }
|
|
@@ -2105,16 +1858,16 @@ class Jt extends m {
|
|
|
2105
1858
|
return;
|
|
2106
1859
|
const t = this.getNavigationId();
|
|
2107
1860
|
if (t) {
|
|
2108
|
-
const
|
|
2109
|
-
if (
|
|
1861
|
+
const r = this.reportedByNav.get(t);
|
|
1862
|
+
if (r?.has(e.type))
|
|
2110
1863
|
return;
|
|
2111
|
-
|
|
1864
|
+
r ? r.add(e.type) : this.reportedByNav.set(t, /* @__PURE__ */ new Set([e.type]));
|
|
2112
1865
|
}
|
|
2113
1866
|
this.trackWebVital(e.type, e.value);
|
|
2114
1867
|
}
|
|
2115
1868
|
trackWebVital(e, t) {
|
|
2116
1869
|
if (!Number.isFinite(t)) {
|
|
2117
|
-
|
|
1870
|
+
o("warn", "Invalid web vital value", { data: { type: e, value: t } });
|
|
2118
1871
|
return;
|
|
2119
1872
|
}
|
|
2120
1873
|
this.eventManager.track({
|
|
@@ -2130,12 +1883,10 @@ class Jt extends m {
|
|
|
2130
1883
|
const e = performance.getEntriesByType("navigation")[0];
|
|
2131
1884
|
if (!e)
|
|
2132
1885
|
return null;
|
|
2133
|
-
const t = e.startTime || performance.now(),
|
|
2134
|
-
return `${t.toFixed(2)}_${window.location.pathname}_${
|
|
1886
|
+
const t = e.startTime || performance.now(), r = Math.random().toString(36).substr(2, 5);
|
|
1887
|
+
return `${t.toFixed(2)}_${window.location.pathname}_${r}`;
|
|
2135
1888
|
} catch (e) {
|
|
2136
|
-
return
|
|
2137
|
-
error: e instanceof Error ? e.message : "Unknown error"
|
|
2138
|
-
}), null;
|
|
1889
|
+
return o("warn", "Failed to get navigation ID", { error: e }), null;
|
|
2139
1890
|
}
|
|
2140
1891
|
}
|
|
2141
1892
|
isObserverSupported(e) {
|
|
@@ -2143,45 +1894,41 @@ class Jt extends m {
|
|
|
2143
1894
|
const t = PerformanceObserver.supportedEntryTypes;
|
|
2144
1895
|
return !t || t.includes(e);
|
|
2145
1896
|
}
|
|
2146
|
-
safeObserve(e, t,
|
|
1897
|
+
safeObserve(e, t, r, n = !1) {
|
|
2147
1898
|
try {
|
|
2148
1899
|
if (!this.isObserverSupported(e))
|
|
2149
1900
|
return !1;
|
|
2150
|
-
const i = new PerformanceObserver((
|
|
1901
|
+
const i = new PerformanceObserver((a, c) => {
|
|
2151
1902
|
try {
|
|
2152
|
-
t(
|
|
1903
|
+
t(a, c);
|
|
2153
1904
|
} catch (l) {
|
|
2154
|
-
|
|
2155
|
-
|
|
2156
|
-
|
|
1905
|
+
o("warn", "Observer callback failed", {
|
|
1906
|
+
error: l,
|
|
1907
|
+
data: { type: e }
|
|
2157
1908
|
});
|
|
2158
1909
|
}
|
|
2159
|
-
if (
|
|
1910
|
+
if (n)
|
|
2160
1911
|
try {
|
|
2161
1912
|
c.disconnect();
|
|
2162
1913
|
} catch {
|
|
2163
1914
|
}
|
|
2164
1915
|
});
|
|
2165
|
-
return i.observe(
|
|
1916
|
+
return i.observe(r ?? { type: e, buffered: !0 }), n || this.observers.push(i), !0;
|
|
2166
1917
|
} catch (i) {
|
|
2167
|
-
return
|
|
2168
|
-
|
|
2169
|
-
|
|
1918
|
+
return o("warn", "Failed to create performance observer", {
|
|
1919
|
+
error: i,
|
|
1920
|
+
data: { type: e }
|
|
2170
1921
|
}), !1;
|
|
2171
1922
|
}
|
|
2172
1923
|
}
|
|
2173
1924
|
shouldSendVital(e, t) {
|
|
2174
1925
|
if (typeof t != "number" || !Number.isFinite(t))
|
|
2175
|
-
return
|
|
2176
|
-
const
|
|
2177
|
-
return typeof
|
|
2178
|
-
type: e,
|
|
2179
|
-
value: t,
|
|
2180
|
-
threshold: n
|
|
2181
|
-
}), !1) : !0;
|
|
1926
|
+
return o("warn", "Invalid web vital value", { data: { type: e, value: t } }), !1;
|
|
1927
|
+
const r = this.vitalThresholds[e];
|
|
1928
|
+
return !(typeof r == "number" && t <= r);
|
|
2182
1929
|
}
|
|
2183
1930
|
}
|
|
2184
|
-
class
|
|
1931
|
+
class pt extends f {
|
|
2185
1932
|
eventManager;
|
|
2186
1933
|
recentErrors = /* @__PURE__ */ new Map();
|
|
2187
1934
|
constructor(e) {
|
|
@@ -2201,32 +1948,28 @@ class Zt extends m {
|
|
|
2201
1948
|
if (!this.shouldSample())
|
|
2202
1949
|
return;
|
|
2203
1950
|
const t = this.sanitize(e.message || "Unknown error");
|
|
2204
|
-
this.shouldSuppressError(
|
|
2205
|
-
message: t,
|
|
2206
|
-
filename: e.filename,
|
|
2207
|
-
line: e.lineno
|
|
2208
|
-
}), this.eventManager.track({
|
|
1951
|
+
this.shouldSuppressError(L.JS_ERROR, t) || this.eventManager.track({
|
|
2209
1952
|
type: d.ERROR,
|
|
2210
1953
|
error_data: {
|
|
2211
|
-
type:
|
|
1954
|
+
type: L.JS_ERROR,
|
|
2212
1955
|
message: t,
|
|
2213
1956
|
...e.filename && { filename: e.filename },
|
|
2214
1957
|
...e.lineno && { line: e.lineno },
|
|
2215
1958
|
...e.colno && { column: e.colno }
|
|
2216
1959
|
}
|
|
2217
|
-
})
|
|
1960
|
+
});
|
|
2218
1961
|
};
|
|
2219
1962
|
handleRejection = (e) => {
|
|
2220
1963
|
if (!this.shouldSample())
|
|
2221
1964
|
return;
|
|
2222
|
-
const t = this.extractRejectionMessage(e.reason),
|
|
2223
|
-
this.shouldSuppressError(
|
|
1965
|
+
const t = this.extractRejectionMessage(e.reason), r = this.sanitize(t);
|
|
1966
|
+
this.shouldSuppressError(L.PROMISE_REJECTION, r) || this.eventManager.track({
|
|
2224
1967
|
type: d.ERROR,
|
|
2225
1968
|
error_data: {
|
|
2226
|
-
type:
|
|
2227
|
-
message:
|
|
1969
|
+
type: L.PROMISE_REJECTION,
|
|
1970
|
+
message: r
|
|
2228
1971
|
}
|
|
2229
|
-
})
|
|
1972
|
+
});
|
|
2230
1973
|
};
|
|
2231
1974
|
extractRejectionMessage(e) {
|
|
2232
1975
|
if (!e) return "Unknown rejection";
|
|
@@ -2242,37 +1985,34 @@ class Zt extends m {
|
|
|
2242
1985
|
}
|
|
2243
1986
|
}
|
|
2244
1987
|
sanitize(e) {
|
|
2245
|
-
let t = e.length >
|
|
2246
|
-
for (const
|
|
2247
|
-
const
|
|
2248
|
-
t = t.replace(
|
|
1988
|
+
let t = e.length > le ? e.slice(0, le) + "..." : e;
|
|
1989
|
+
for (const r of Te) {
|
|
1990
|
+
const n = new RegExp(r.source, r.flags);
|
|
1991
|
+
t = t.replace(n, "[REDACTED]");
|
|
2249
1992
|
}
|
|
2250
1993
|
return t;
|
|
2251
1994
|
}
|
|
2252
1995
|
shouldSuppressError(e, t) {
|
|
2253
|
-
const
|
|
2254
|
-
return i &&
|
|
2255
|
-
size: this.recentErrors.size,
|
|
2256
|
-
limit: Re
|
|
2257
|
-
}), this.recentErrors.clear(), this.recentErrors.set(s, n), !1) : (this.recentErrors.size > G && this.pruneOldErrors(), !1));
|
|
1996
|
+
const r = Date.now(), n = `${e}:${t}`, i = this.recentErrors.get(n);
|
|
1997
|
+
return i && r - i < ue ? (this.recentErrors.set(n, r), !0) : (this.recentErrors.set(n, r), this.recentErrors.size > $e ? (this.recentErrors.clear(), this.recentErrors.set(n, r), !1) : (this.recentErrors.size > k && this.pruneOldErrors(), !1));
|
|
2258
1998
|
}
|
|
2259
1999
|
pruneOldErrors() {
|
|
2260
2000
|
const e = Date.now();
|
|
2261
|
-
for (const [
|
|
2262
|
-
e - i >
|
|
2263
|
-
if (this.recentErrors.size <=
|
|
2001
|
+
for (const [n, i] of this.recentErrors.entries())
|
|
2002
|
+
e - i > ue && this.recentErrors.delete(n);
|
|
2003
|
+
if (this.recentErrors.size <= k)
|
|
2264
2004
|
return;
|
|
2265
|
-
const t = Array.from(this.recentErrors.entries()).sort((
|
|
2266
|
-
for (let
|
|
2267
|
-
const i = t[
|
|
2005
|
+
const t = Array.from(this.recentErrors.entries()).sort((n, i) => n[1] - i[1]), r = this.recentErrors.size - k;
|
|
2006
|
+
for (let n = 0; n < r; n += 1) {
|
|
2007
|
+
const i = t[n];
|
|
2268
2008
|
i && this.recentErrors.delete(i[0]);
|
|
2269
2009
|
}
|
|
2270
2010
|
}
|
|
2271
2011
|
}
|
|
2272
|
-
class
|
|
2012
|
+
class _t extends f {
|
|
2273
2013
|
isInitialized = !1;
|
|
2274
2014
|
suppressNextScrollTimer = null;
|
|
2275
|
-
emitter = new
|
|
2015
|
+
emitter = new at();
|
|
2276
2016
|
managers = {};
|
|
2277
2017
|
handlers = {};
|
|
2278
2018
|
integrations = {};
|
|
@@ -2281,26 +2021,25 @@ class er extends m {
|
|
|
2281
2021
|
}
|
|
2282
2022
|
async init(e) {
|
|
2283
2023
|
if (!this.isInitialized) {
|
|
2284
|
-
|
|
2285
|
-
throw new Error("Project ID is required");
|
|
2286
|
-
this.managers.storage = new qt();
|
|
2024
|
+
this.managers.storage = new Et();
|
|
2287
2025
|
try {
|
|
2288
|
-
|
|
2289
|
-
|
|
2026
|
+
this.setupState(e), await this.setupIntegrations(), this.managers.event = new ct(this.managers.storage, this.integrations.googleAnalytics, this.emitter), await this.initializeHandlers(), await this.managers.event.recoverPersistedEvents().catch((t) => {
|
|
2027
|
+
o("warn", "Failed to recover persisted events", { error: t });
|
|
2290
2028
|
}), this.isInitialized = !0;
|
|
2291
2029
|
} catch (t) {
|
|
2292
|
-
|
|
2030
|
+
await this.destroy(!0);
|
|
2031
|
+
const r = t instanceof Error ? t.message : String(t);
|
|
2032
|
+
throw new Error(`[TraceLog] TraceLog initialization failed: ${r}`);
|
|
2293
2033
|
}
|
|
2294
2034
|
}
|
|
2295
2035
|
}
|
|
2296
2036
|
sendCustomEvent(e, t) {
|
|
2297
2037
|
if (!this.managers.event)
|
|
2298
2038
|
return;
|
|
2299
|
-
const { valid:
|
|
2300
|
-
if (!
|
|
2301
|
-
|
|
2302
|
-
|
|
2303
|
-
throw new Error(`Custom event "${e}" validation failed: ${s}`);
|
|
2039
|
+
const { valid: r, error: n, sanitizedMetadata: i } = it(e, t);
|
|
2040
|
+
if (!r) {
|
|
2041
|
+
if (this.get("mode") === R.QA)
|
|
2042
|
+
throw new Error(`[TraceLog] Custom event "${e}" validation failed: ${n}`);
|
|
2304
2043
|
return;
|
|
2305
2044
|
}
|
|
2306
2045
|
this.managers.event.track({
|
|
@@ -2321,120 +2060,123 @@ class er extends m {
|
|
|
2321
2060
|
if (!this.isInitialized && !e)
|
|
2322
2061
|
return;
|
|
2323
2062
|
this.integrations.googleAnalytics?.cleanup();
|
|
2324
|
-
const t = Object.values(this.handlers).filter(Boolean).map(async (
|
|
2063
|
+
const t = Object.values(this.handlers).filter(Boolean).map(async (r) => {
|
|
2325
2064
|
try {
|
|
2326
|
-
await
|
|
2327
|
-
} catch {
|
|
2328
|
-
|
|
2065
|
+
await r.stopTracking();
|
|
2066
|
+
} catch (n) {
|
|
2067
|
+
o("warn", "Failed to stop tracking", { error: n });
|
|
2329
2068
|
}
|
|
2330
2069
|
});
|
|
2331
2070
|
await Promise.allSettled(t), this.suppressNextScrollTimer && (clearTimeout(this.suppressNextScrollTimer), this.suppressNextScrollTimer = null), this.managers.event?.flushImmediatelySync(), this.managers.event?.stop(), this.emitter.removeAllListeners(), this.set("hasStartSession", !1), this.set("suppressNextScroll", !1), this.set("sessionId", null), this.isInitialized = !1, this.handlers = {};
|
|
2332
2071
|
}
|
|
2333
|
-
|
|
2334
|
-
|
|
2335
|
-
this.
|
|
2336
|
-
|
|
2337
|
-
|
|
2338
|
-
|
|
2339
|
-
|
|
2340
|
-
|
|
2341
|
-
|
|
2072
|
+
setupState(e) {
|
|
2073
|
+
this.set("config", e);
|
|
2074
|
+
const t = lt.getId(this.managers.storage);
|
|
2075
|
+
this.set("userId", t);
|
|
2076
|
+
const r = We(e);
|
|
2077
|
+
this.set("apiUrl", r);
|
|
2078
|
+
const n = He();
|
|
2079
|
+
this.set("device", n);
|
|
2080
|
+
const i = Y(window.location.href, e.sensitiveQueryParams);
|
|
2081
|
+
this.set("pageUrl", i);
|
|
2082
|
+
const a = Be() ? R.QA : void 0;
|
|
2083
|
+
a && this.set("mode", a);
|
|
2342
2084
|
}
|
|
2343
2085
|
async setupIntegrations() {
|
|
2344
|
-
|
|
2345
|
-
if (!e.ipExcluded && t?.trim())
|
|
2086
|
+
if (this.get("config").integrations?.googleAnalytics?.measurementId?.trim())
|
|
2346
2087
|
try {
|
|
2347
|
-
this.integrations.googleAnalytics = new
|
|
2088
|
+
this.integrations.googleAnalytics = new St(), await this.integrations.googleAnalytics.initialize();
|
|
2348
2089
|
} catch {
|
|
2349
2090
|
this.integrations.googleAnalytics = void 0;
|
|
2350
2091
|
}
|
|
2351
2092
|
}
|
|
2352
|
-
initializeHandlers() {
|
|
2353
|
-
this.handlers.session = new
|
|
2093
|
+
async initializeHandlers() {
|
|
2094
|
+
this.handlers.session = new dt(
|
|
2354
2095
|
this.managers.storage,
|
|
2355
2096
|
this.managers.event
|
|
2356
|
-
), this.handlers.session.startTracking()
|
|
2357
|
-
a.error("App", "Session handler failed to start", {
|
|
2358
|
-
message: t instanceof Error ? t.message : "Unknown error"
|
|
2359
|
-
});
|
|
2360
|
-
});
|
|
2097
|
+
), await this.handlers.session.startTracking();
|
|
2361
2098
|
const e = () => {
|
|
2362
2099
|
this.set("suppressNextScroll", !0), this.suppressNextScrollTimer && clearTimeout(this.suppressNextScrollTimer), this.suppressNextScrollTimer = window.setTimeout(() => {
|
|
2363
2100
|
this.set("suppressNextScroll", !1);
|
|
2364
|
-
},
|
|
2101
|
+
}, 250 * 2);
|
|
2365
2102
|
};
|
|
2366
|
-
this.handlers.pageView = new
|
|
2367
|
-
|
|
2368
|
-
}), this.handlers.error = new
|
|
2103
|
+
this.handlers.pageView = new ht(this.managers.event, e), this.handlers.pageView.startTracking(), this.handlers.click = new ft(this.managers.event), this.handlers.click.startTracking(), this.handlers.scroll = new gt(this.managers.event), this.handlers.scroll.startTracking(), this.handlers.performance = new mt(this.managers.event), this.handlers.performance.startTracking().catch((t) => {
|
|
2104
|
+
o("warn", "Failed to start performance tracking", { error: t });
|
|
2105
|
+
}), this.handlers.error = new pt(this.managers.event), this.handlers.error.startTracking();
|
|
2369
2106
|
}
|
|
2370
2107
|
}
|
|
2371
|
-
|
|
2372
|
-
|
|
2108
|
+
const I = [];
|
|
2109
|
+
let h = null, w = !1, U = !1;
|
|
2110
|
+
const Tt = async (s) => {
|
|
2373
2111
|
if (typeof window > "u" || typeof document > "u")
|
|
2374
|
-
throw new Error("This library can only be used in a browser environment");
|
|
2375
|
-
if (!window.__traceLogDisabled) {
|
|
2376
|
-
|
|
2377
|
-
a.debug("API", "Library already initialized, skipping duplicate initialization");
|
|
2378
|
-
return;
|
|
2379
|
-
}
|
|
2380
|
-
if (D)
|
|
2381
|
-
throw a.warn("API", "Initialization already in progress"), new Error("Initialization already in progress");
|
|
2382
|
-
D = !0;
|
|
2112
|
+
throw new Error("[TraceLog] This library can only be used in a browser environment");
|
|
2113
|
+
if (!window.__traceLogDisabled && !h && !w) {
|
|
2114
|
+
w = !0;
|
|
2383
2115
|
try {
|
|
2384
|
-
|
|
2385
|
-
const e = Rt(r), t = new er();
|
|
2116
|
+
const e = et(s), t = new _t();
|
|
2386
2117
|
try {
|
|
2387
|
-
|
|
2388
|
-
|
|
2118
|
+
I.forEach(({ event: i, callback: a }) => {
|
|
2119
|
+
t.on(i, a);
|
|
2120
|
+
}), I.length = 0;
|
|
2121
|
+
const r = t.init(e), n = new Promise((i, a) => {
|
|
2122
|
+
setTimeout(() => {
|
|
2123
|
+
a(new Error("[TraceLog] Initialization timeout after 10000ms"));
|
|
2124
|
+
}, 1e4);
|
|
2125
|
+
});
|
|
2126
|
+
await Promise.race([r, n]), h = t;
|
|
2127
|
+
} catch (r) {
|
|
2389
2128
|
try {
|
|
2390
2129
|
await t.destroy(!0);
|
|
2391
|
-
} catch (
|
|
2392
|
-
|
|
2130
|
+
} catch (n) {
|
|
2131
|
+
o("error", "Failed to cleanup partially initialized app", { error: n });
|
|
2393
2132
|
}
|
|
2394
|
-
throw
|
|
2133
|
+
throw r;
|
|
2395
2134
|
}
|
|
2396
2135
|
} catch (e) {
|
|
2397
|
-
throw
|
|
2136
|
+
throw h = null, e;
|
|
2398
2137
|
} finally {
|
|
2399
|
-
|
|
2138
|
+
w = !1;
|
|
2400
2139
|
}
|
|
2401
2140
|
}
|
|
2402
|
-
},
|
|
2403
|
-
if (!
|
|
2404
|
-
throw new Error("TraceLog not initialized. Please call init() first.");
|
|
2405
|
-
|
|
2406
|
-
|
|
2407
|
-
|
|
2408
|
-
|
|
2409
|
-
|
|
2410
|
-
|
|
2411
|
-
|
|
2412
|
-
|
|
2413
|
-
|
|
2414
|
-
},
|
|
2415
|
-
if (!
|
|
2416
|
-
|
|
2417
|
-
|
|
2418
|
-
|
|
2419
|
-
|
|
2420
|
-
|
|
2421
|
-
|
|
2422
|
-
|
|
2423
|
-
|
|
2141
|
+
}, vt = (s, e) => {
|
|
2142
|
+
if (!h)
|
|
2143
|
+
throw new Error("[TraceLog] TraceLog not initialized. Please call init() first.");
|
|
2144
|
+
if (U)
|
|
2145
|
+
throw new Error("[TraceLog] Cannot send events while TraceLog is being destroyed");
|
|
2146
|
+
h.sendCustomEvent(s, e);
|
|
2147
|
+
}, It = (s, e) => {
|
|
2148
|
+
if (!h || w) {
|
|
2149
|
+
I.push({ event: s, callback: e });
|
|
2150
|
+
return;
|
|
2151
|
+
}
|
|
2152
|
+
h.on(s, e);
|
|
2153
|
+
}, yt = (s, e) => {
|
|
2154
|
+
if (!h) {
|
|
2155
|
+
const t = I.findIndex((r) => r.event === s && r.callback === e);
|
|
2156
|
+
t !== -1 && I.splice(t, 1);
|
|
2157
|
+
return;
|
|
2158
|
+
}
|
|
2159
|
+
h.off(s, e);
|
|
2160
|
+
}, At = () => h !== null, wt = async () => {
|
|
2161
|
+
if (!h)
|
|
2162
|
+
throw new Error("[TraceLog] App not initialized");
|
|
2163
|
+
if (U)
|
|
2164
|
+
throw new Error("[TraceLog] Destroy operation already in progress");
|
|
2165
|
+
U = !0;
|
|
2424
2166
|
try {
|
|
2425
|
-
|
|
2426
|
-
} catch (
|
|
2427
|
-
|
|
2167
|
+
await h.destroy(), h = null, w = !1, I.length = 0;
|
|
2168
|
+
} catch (s) {
|
|
2169
|
+
h = null, w = !1, I.length = 0, o("warn", "Error during destroy, forced cleanup completed", { error: s });
|
|
2428
2170
|
} finally {
|
|
2429
|
-
|
|
2171
|
+
U = !1;
|
|
2430
2172
|
}
|
|
2431
|
-
},
|
|
2432
|
-
WEB_VITALS_THRESHOLDS:
|
|
2173
|
+
}, Vt = {
|
|
2174
|
+
WEB_VITALS_THRESHOLDS: _e
|
|
2433
2175
|
// Business thresholds for performance analysis
|
|
2434
|
-
},
|
|
2435
|
-
PII_PATTERNS:
|
|
2176
|
+
}, Ft = {
|
|
2177
|
+
PII_PATTERNS: Te
|
|
2436
2178
|
// Patterns for sensitive data protection
|
|
2437
|
-
},
|
|
2179
|
+
}, Gt = {
|
|
2438
2180
|
LOW_ACTIVITY_EVENT_COUNT: 50,
|
|
2439
2181
|
HIGH_ACTIVITY_EVENT_COUNT: 1e3,
|
|
2440
2182
|
MIN_EVENTS_FOR_DYNAMIC_CALCULATION: 100,
|
|
@@ -2444,7 +2186,7 @@ const tr = async (r) => {
|
|
|
2444
2186
|
MIN_ENGAGED_SESSION_DURATION_MS: 30 * 1e3,
|
|
2445
2187
|
MIN_SCROLL_DEPTH_ENGAGEMENT: 25
|
|
2446
2188
|
// 25% scroll depth for engagement
|
|
2447
|
-
},
|
|
2189
|
+
}, zt = {
|
|
2448
2190
|
INACTIVITY_TIMEOUT_MS: 30 * 60 * 1e3,
|
|
2449
2191
|
// 30min for analytics (vs 15min client)
|
|
2450
2192
|
SHORT_SESSION_THRESHOLD_MS: 30 * 1e3,
|
|
@@ -2452,20 +2194,20 @@ const tr = async (r) => {
|
|
|
2452
2194
|
LONG_SESSION_THRESHOLD_MS: 30 * 60 * 1e3,
|
|
2453
2195
|
MAX_REALISTIC_SESSION_DURATION_MS: 8 * 60 * 60 * 1e3
|
|
2454
2196
|
// Filter outliers
|
|
2455
|
-
},
|
|
2197
|
+
}, $t = {
|
|
2456
2198
|
MOBILE_MAX_WIDTH: 768,
|
|
2457
2199
|
TABLET_MAX_WIDTH: 1024,
|
|
2458
2200
|
MOBILE_PERFORMANCE_FACTOR: 1.5,
|
|
2459
2201
|
// Mobile typically 1.5x slower
|
|
2460
2202
|
TABLET_PERFORMANCE_FACTOR: 1.2
|
|
2461
|
-
},
|
|
2203
|
+
}, Qt = {
|
|
2462
2204
|
MIN_TEXT_LENGTH_FOR_ANALYSIS: 10,
|
|
2463
2205
|
MIN_CLICKS_FOR_HOT_ELEMENT: 10,
|
|
2464
2206
|
// Popular element threshold
|
|
2465
2207
|
MIN_SCROLL_COMPLETION_PERCENT: 80,
|
|
2466
2208
|
// Page consumption threshold
|
|
2467
2209
|
MIN_TIME_ON_PAGE_FOR_READ_MS: 15 * 1e3
|
|
2468
|
-
},
|
|
2210
|
+
}, Bt = {
|
|
2469
2211
|
SIGNIFICANT_CHANGE_PERCENT: 20,
|
|
2470
2212
|
MAJOR_CHANGE_PERCENT: 50,
|
|
2471
2213
|
MIN_EVENTS_FOR_INSIGHT: 100,
|
|
@@ -2475,19 +2217,19 @@ const tr = async (r) => {
|
|
|
2475
2217
|
LOW_ERROR_RATE_PERCENT: 1,
|
|
2476
2218
|
HIGH_ERROR_RATE_PERCENT: 5,
|
|
2477
2219
|
CRITICAL_ERROR_RATE_PERCENT: 10
|
|
2478
|
-
},
|
|
2220
|
+
}, jt = {
|
|
2479
2221
|
SHORT_TERM_TREND_HOURS: 24,
|
|
2480
2222
|
MEDIUM_TERM_TREND_DAYS: 7,
|
|
2481
2223
|
LONG_TERM_TREND_DAYS: 30,
|
|
2482
2224
|
MIN_DATA_POINTS_FOR_TREND: 5,
|
|
2483
2225
|
WEEKLY_PATTERN_MIN_WEEKS: 4,
|
|
2484
2226
|
DAILY_PATTERN_MIN_DAYS: 14
|
|
2485
|
-
},
|
|
2227
|
+
}, Xt = {
|
|
2486
2228
|
MIN_SEGMENT_SIZE: 10,
|
|
2487
2229
|
MIN_COHORT_SIZE: 5,
|
|
2488
2230
|
COHORT_ANALYSIS_DAYS: [1, 3, 7, 14, 30],
|
|
2489
2231
|
MIN_FUNNEL_EVENTS: 20
|
|
2490
|
-
},
|
|
2232
|
+
}, Wt = {
|
|
2491
2233
|
DEFAULT_EVENTS_LIMIT: 5,
|
|
2492
2234
|
DEFAULT_SESSIONS_LIMIT: 5,
|
|
2493
2235
|
DEFAULT_PAGES_LIMIT: 5,
|
|
@@ -2495,243 +2237,248 @@ const tr = async (r) => {
|
|
|
2495
2237
|
MAX_TIME_RANGE_DAYS: 365,
|
|
2496
2238
|
ANALYTICS_BATCH_SIZE: 1e3
|
|
2497
2239
|
// For historical analysis
|
|
2498
|
-
},
|
|
2240
|
+
}, Yt = {
|
|
2499
2241
|
ANOMALY_THRESHOLD_SIGMA: 2.5,
|
|
2500
2242
|
STRONG_ANOMALY_THRESHOLD_SIGMA: 3,
|
|
2501
2243
|
TRAFFIC_DROP_ALERT_PERCENT: -30,
|
|
2502
2244
|
TRAFFIC_SPIKE_ALERT_PERCENT: 200,
|
|
2503
2245
|
MIN_BASELINE_DAYS: 7,
|
|
2504
2246
|
MIN_EVENTS_FOR_ANOMALY_DETECTION: 50
|
|
2505
|
-
},
|
|
2247
|
+
}, Kt = {
|
|
2506
2248
|
PAGE_URL_EXCLUDED: "excluded",
|
|
2507
2249
|
PAGE_URL_UNKNOWN: "unknown"
|
|
2508
|
-
},
|
|
2509
|
-
init:
|
|
2510
|
-
event:
|
|
2511
|
-
on:
|
|
2512
|
-
off:
|
|
2513
|
-
isInitialized:
|
|
2514
|
-
destroy:
|
|
2250
|
+
}, qt = {
|
|
2251
|
+
init: Tt,
|
|
2252
|
+
event: vt,
|
|
2253
|
+
on: It,
|
|
2254
|
+
off: yt,
|
|
2255
|
+
isInitialized: At,
|
|
2256
|
+
destroy: wt
|
|
2515
2257
|
};
|
|
2516
|
-
var
|
|
2258
|
+
var q, ve = -1, M = function(s) {
|
|
2517
2259
|
addEventListener("pageshow", function(e) {
|
|
2518
|
-
e.persisted && (
|
|
2260
|
+
e.persisted && (ve = e.timeStamp, s(e));
|
|
2519
2261
|
}, !0);
|
|
2520
|
-
},
|
|
2521
|
-
var
|
|
2522
|
-
if (
|
|
2523
|
-
},
|
|
2524
|
-
var
|
|
2525
|
-
return
|
|
2526
|
-
},
|
|
2527
|
-
var t =
|
|
2528
|
-
return
|
|
2529
|
-
},
|
|
2262
|
+
}, se = function() {
|
|
2263
|
+
var s = self.performance && performance.getEntriesByType && performance.getEntriesByType("navigation")[0];
|
|
2264
|
+
if (s && s.responseStart > 0 && s.responseStart < performance.now()) return s;
|
|
2265
|
+
}, V = function() {
|
|
2266
|
+
var s = se();
|
|
2267
|
+
return s && s.activationStart || 0;
|
|
2268
|
+
}, S = function(s, e) {
|
|
2269
|
+
var t = se(), r = "navigate";
|
|
2270
|
+
return ve >= 0 ? r = "back-forward-cache" : t && (document.prerendering || V() > 0 ? r = "prerender" : document.wasDiscarded ? r = "restore" : t.type && (r = t.type.replace(/_/g, "-"))), { name: s, value: e === void 0 ? -1 : e, rating: "good", delta: 0, entries: [], id: "v4-".concat(Date.now(), "-").concat(Math.floor(8999999999999 * Math.random()) + 1e12), navigationType: r };
|
|
2271
|
+
}, b = function(s, e, t) {
|
|
2530
2272
|
try {
|
|
2531
|
-
if (PerformanceObserver.supportedEntryTypes.includes(
|
|
2532
|
-
var
|
|
2273
|
+
if (PerformanceObserver.supportedEntryTypes.includes(s)) {
|
|
2274
|
+
var r = new PerformanceObserver(function(n) {
|
|
2533
2275
|
Promise.resolve().then(function() {
|
|
2534
|
-
e(
|
|
2276
|
+
e(n.getEntries());
|
|
2535
2277
|
});
|
|
2536
2278
|
});
|
|
2537
|
-
return
|
|
2279
|
+
return r.observe(Object.assign({ type: s, buffered: !0 }, t || {})), r;
|
|
2538
2280
|
}
|
|
2539
2281
|
} catch {
|
|
2540
2282
|
}
|
|
2541
|
-
},
|
|
2542
|
-
var
|
|
2543
|
-
return function(
|
|
2544
|
-
e.value >= 0 && (
|
|
2283
|
+
}, E = function(s, e, t, r) {
|
|
2284
|
+
var n, i;
|
|
2285
|
+
return function(a) {
|
|
2286
|
+
e.value >= 0 && (a || r) && ((i = e.value - (n || 0)) || n === void 0) && (n = e.value, e.delta = i, e.rating = function(c, l) {
|
|
2545
2287
|
return c > l[1] ? "poor" : c > l[0] ? "needs-improvement" : "good";
|
|
2546
|
-
}(e.value, t),
|
|
2288
|
+
}(e.value, t), s(e));
|
|
2547
2289
|
};
|
|
2548
|
-
},
|
|
2290
|
+
}, ne = function(s) {
|
|
2549
2291
|
requestAnimationFrame(function() {
|
|
2550
2292
|
return requestAnimationFrame(function() {
|
|
2551
|
-
return
|
|
2293
|
+
return s();
|
|
2552
2294
|
});
|
|
2553
2295
|
});
|
|
2554
|
-
},
|
|
2296
|
+
}, F = function(s) {
|
|
2555
2297
|
document.addEventListener("visibilitychange", function() {
|
|
2556
|
-
document.visibilityState === "hidden" &&
|
|
2298
|
+
document.visibilityState === "hidden" && s();
|
|
2557
2299
|
});
|
|
2558
|
-
},
|
|
2300
|
+
}, ie = function(s) {
|
|
2559
2301
|
var e = !1;
|
|
2560
2302
|
return function() {
|
|
2561
|
-
e || (
|
|
2303
|
+
e || (s(), e = !0);
|
|
2562
2304
|
};
|
|
2563
|
-
},
|
|
2305
|
+
}, A = -1, Ee = function() {
|
|
2564
2306
|
return document.visibilityState !== "hidden" || document.prerendering ? 1 / 0 : 0;
|
|
2565
|
-
},
|
|
2566
|
-
document.visibilityState === "hidden" &&
|
|
2567
|
-
},
|
|
2568
|
-
addEventListener("visibilitychange",
|
|
2569
|
-
},
|
|
2570
|
-
removeEventListener("visibilitychange",
|
|
2571
|
-
},
|
|
2572
|
-
return
|
|
2307
|
+
}, x = function(s) {
|
|
2308
|
+
document.visibilityState === "hidden" && A > -1 && (A = s.type === "visibilitychange" ? s.timeStamp : 0, Mt());
|
|
2309
|
+
}, me = function() {
|
|
2310
|
+
addEventListener("visibilitychange", x, !0), addEventListener("prerenderingchange", x, !0);
|
|
2311
|
+
}, Mt = function() {
|
|
2312
|
+
removeEventListener("visibilitychange", x, !0), removeEventListener("prerenderingchange", x, !0);
|
|
2313
|
+
}, Ie = function() {
|
|
2314
|
+
return A < 0 && (A = Ee(), me(), M(function() {
|
|
2573
2315
|
setTimeout(function() {
|
|
2574
|
-
|
|
2316
|
+
A = Ee(), me();
|
|
2575
2317
|
}, 0);
|
|
2576
2318
|
})), { get firstHiddenTime() {
|
|
2577
|
-
return
|
|
2319
|
+
return A;
|
|
2578
2320
|
} };
|
|
2579
|
-
},
|
|
2321
|
+
}, G = function(s) {
|
|
2580
2322
|
document.prerendering ? addEventListener("prerenderingchange", function() {
|
|
2581
|
-
return
|
|
2582
|
-
}, !0) :
|
|
2583
|
-
},
|
|
2584
|
-
e = e || {},
|
|
2585
|
-
var t,
|
|
2586
|
-
|
|
2587
|
-
c.name === "first-contentful-paint" && (i.disconnect(), c.startTime <
|
|
2323
|
+
return s();
|
|
2324
|
+
}, !0) : s();
|
|
2325
|
+
}, Z = [1800, 3e3], ye = function(s, e) {
|
|
2326
|
+
e = e || {}, G(function() {
|
|
2327
|
+
var t, r = Ie(), n = S("FCP"), i = b("paint", function(a) {
|
|
2328
|
+
a.forEach(function(c) {
|
|
2329
|
+
c.name === "first-contentful-paint" && (i.disconnect(), c.startTime < r.firstHiddenTime && (n.value = Math.max(c.startTime - V(), 0), n.entries.push(c), t(!0)));
|
|
2588
2330
|
});
|
|
2589
2331
|
});
|
|
2590
|
-
i && (t =
|
|
2591
|
-
|
|
2592
|
-
|
|
2332
|
+
i && (t = E(s, n, Z, e.reportAllChanges), M(function(a) {
|
|
2333
|
+
n = S("FCP"), t = E(s, n, Z, e.reportAllChanges), ne(function() {
|
|
2334
|
+
n.value = performance.now() - a.timeStamp, t(!0);
|
|
2593
2335
|
});
|
|
2594
2336
|
}));
|
|
2595
2337
|
});
|
|
2596
|
-
},
|
|
2597
|
-
e = e || {},
|
|
2598
|
-
var t,
|
|
2338
|
+
}, J = [0.1, 0.25], Nt = function(s, e) {
|
|
2339
|
+
e = e || {}, ye(ie(function() {
|
|
2340
|
+
var t, r = S("CLS", 0), n = 0, i = [], a = function(l) {
|
|
2599
2341
|
l.forEach(function(u) {
|
|
2600
2342
|
if (!u.hadRecentInput) {
|
|
2601
|
-
var
|
|
2602
|
-
|
|
2343
|
+
var p = i[0], N = i[i.length - 1];
|
|
2344
|
+
n && u.startTime - N.startTime < 1e3 && u.startTime - p.startTime < 5e3 ? (n += u.value, i.push(u)) : (n = u.value, i = [u]);
|
|
2603
2345
|
}
|
|
2604
|
-
}),
|
|
2605
|
-
}, c =
|
|
2606
|
-
c && (t =
|
|
2607
|
-
|
|
2608
|
-
}),
|
|
2609
|
-
|
|
2346
|
+
}), n > r.value && (r.value = n, r.entries = i, t());
|
|
2347
|
+
}, c = b("layout-shift", a);
|
|
2348
|
+
c && (t = E(s, r, J, e.reportAllChanges), F(function() {
|
|
2349
|
+
a(c.takeRecords()), t(!0);
|
|
2350
|
+
}), M(function() {
|
|
2351
|
+
n = 0, r = S("CLS", 0), t = E(s, r, J, e.reportAllChanges), ne(function() {
|
|
2610
2352
|
return t();
|
|
2611
2353
|
});
|
|
2612
2354
|
}), setTimeout(t, 0));
|
|
2613
2355
|
}));
|
|
2614
|
-
},
|
|
2615
|
-
|
|
2616
|
-
e.interactionId && (
|
|
2356
|
+
}, Ae = 0, Q = 1 / 0, P = 0, Lt = function(s) {
|
|
2357
|
+
s.forEach(function(e) {
|
|
2358
|
+
e.interactionId && (Q = Math.min(Q, e.interactionId), P = Math.max(P, e.interactionId), Ae = P ? (P - Q) / 7 + 1 : 0);
|
|
2617
2359
|
});
|
|
2618
|
-
},
|
|
2619
|
-
return
|
|
2620
|
-
},
|
|
2621
|
-
"interactionCount" in performance ||
|
|
2622
|
-
},
|
|
2623
|
-
var
|
|
2624
|
-
return
|
|
2625
|
-
},
|
|
2626
|
-
if (
|
|
2627
|
-
return s
|
|
2628
|
-
}),
|
|
2629
|
-
var e =
|
|
2630
|
-
if (t ||
|
|
2631
|
-
if (t)
|
|
2360
|
+
}, we = function() {
|
|
2361
|
+
return q ? Ae : performance.interactionCount || 0;
|
|
2362
|
+
}, Rt = function() {
|
|
2363
|
+
"interactionCount" in performance || q || (q = b("event", Lt, { type: "event", buffered: !0, durationThreshold: 0 }));
|
|
2364
|
+
}, g = [], H = /* @__PURE__ */ new Map(), Me = 0, Ct = function() {
|
|
2365
|
+
var s = Math.min(g.length - 1, Math.floor((we() - Me) / 50));
|
|
2366
|
+
return g[s];
|
|
2367
|
+
}, bt = [], Ot = function(s) {
|
|
2368
|
+
if (bt.forEach(function(n) {
|
|
2369
|
+
return n(s);
|
|
2370
|
+
}), s.interactionId || s.entryType === "first-input") {
|
|
2371
|
+
var e = g[g.length - 1], t = H.get(s.interactionId);
|
|
2372
|
+
if (t || g.length < 10 || s.duration > e.latency) {
|
|
2373
|
+
if (t) s.duration > t.latency ? (t.entries = [s], t.latency = s.duration) : s.duration === t.latency && s.startTime === t.entries[0].startTime && t.entries.push(s);
|
|
2632
2374
|
else {
|
|
2633
|
-
var
|
|
2634
|
-
|
|
2375
|
+
var r = { id: s.interactionId, latency: s.duration, entries: [s] };
|
|
2376
|
+
H.set(r.id, r), g.push(r);
|
|
2635
2377
|
}
|
|
2636
|
-
|
|
2637
|
-
return i.latency -
|
|
2638
|
-
}),
|
|
2639
|
-
return
|
|
2378
|
+
g.sort(function(n, i) {
|
|
2379
|
+
return i.latency - n.latency;
|
|
2380
|
+
}), g.length > 10 && g.splice(10).forEach(function(n) {
|
|
2381
|
+
return H.delete(n.id);
|
|
2640
2382
|
});
|
|
2641
2383
|
}
|
|
2642
2384
|
}
|
|
2643
|
-
},
|
|
2385
|
+
}, Ne = function(s) {
|
|
2644
2386
|
var e = self.requestIdleCallback || self.setTimeout, t = -1;
|
|
2645
|
-
return
|
|
2646
|
-
},
|
|
2647
|
-
"PerformanceEventTiming" in self && "interactionId" in PerformanceEventTiming.prototype && (e = e || {},
|
|
2387
|
+
return s = ie(s), document.visibilityState === "hidden" ? s() : (t = e(s), F(s)), t;
|
|
2388
|
+
}, ee = [200, 500], Pt = function(s, e) {
|
|
2389
|
+
"PerformanceEventTiming" in self && "interactionId" in PerformanceEventTiming.prototype && (e = e || {}, G(function() {
|
|
2648
2390
|
var t;
|
|
2649
|
-
|
|
2650
|
-
var
|
|
2651
|
-
|
|
2652
|
-
c.forEach(
|
|
2653
|
-
var l =
|
|
2654
|
-
l && l.latency !==
|
|
2391
|
+
Rt();
|
|
2392
|
+
var r, n = S("INP"), i = function(c) {
|
|
2393
|
+
Ne(function() {
|
|
2394
|
+
c.forEach(Ot);
|
|
2395
|
+
var l = Ct();
|
|
2396
|
+
l && l.latency !== n.value && (n.value = l.latency, n.entries = l.entries, r());
|
|
2655
2397
|
});
|
|
2656
|
-
},
|
|
2657
|
-
|
|
2658
|
-
i(
|
|
2659
|
-
}),
|
|
2660
|
-
|
|
2398
|
+
}, a = b("event", i, { durationThreshold: (t = e.durationThreshold) !== null && t !== void 0 ? t : 40 });
|
|
2399
|
+
r = E(s, n, ee, e.reportAllChanges), a && (a.observe({ type: "first-input", buffered: !0 }), F(function() {
|
|
2400
|
+
i(a.takeRecords()), r(!0);
|
|
2401
|
+
}), M(function() {
|
|
2402
|
+
Me = we(), g.length = 0, H.clear(), n = S("INP"), r = E(s, n, ee, e.reportAllChanges);
|
|
2661
2403
|
}));
|
|
2662
2404
|
}));
|
|
2663
|
-
},
|
|
2664
|
-
e = e || {},
|
|
2665
|
-
var t,
|
|
2405
|
+
}, te = [2500, 4e3], B = {}, Dt = function(s, e) {
|
|
2406
|
+
e = e || {}, G(function() {
|
|
2407
|
+
var t, r = Ie(), n = S("LCP"), i = function(l) {
|
|
2666
2408
|
e.reportAllChanges || (l = l.slice(-1)), l.forEach(function(u) {
|
|
2667
|
-
u.startTime <
|
|
2409
|
+
u.startTime < r.firstHiddenTime && (n.value = Math.max(u.startTime - V(), 0), n.entries = [u], t());
|
|
2668
2410
|
});
|
|
2669
|
-
},
|
|
2670
|
-
if (
|
|
2671
|
-
t =
|
|
2672
|
-
var c =
|
|
2673
|
-
|
|
2411
|
+
}, a = b("largest-contentful-paint", i);
|
|
2412
|
+
if (a) {
|
|
2413
|
+
t = E(s, n, te, e.reportAllChanges);
|
|
2414
|
+
var c = ie(function() {
|
|
2415
|
+
B[n.id] || (i(a.takeRecords()), a.disconnect(), B[n.id] = !0, t(!0));
|
|
2674
2416
|
});
|
|
2675
2417
|
["keydown", "click"].forEach(function(l) {
|
|
2676
2418
|
addEventListener(l, function() {
|
|
2677
|
-
return
|
|
2419
|
+
return Ne(c);
|
|
2678
2420
|
}, { once: !0, capture: !0 });
|
|
2679
|
-
}),
|
|
2680
|
-
|
|
2681
|
-
|
|
2421
|
+
}), F(c), M(function(l) {
|
|
2422
|
+
n = S("LCP"), t = E(s, n, te, e.reportAllChanges), ne(function() {
|
|
2423
|
+
n.value = performance.now() - l.timeStamp, B[n.id] = !0, t(!0);
|
|
2682
2424
|
});
|
|
2683
2425
|
});
|
|
2684
2426
|
}
|
|
2685
2427
|
});
|
|
2686
|
-
},
|
|
2687
|
-
document.prerendering ?
|
|
2688
|
-
return
|
|
2428
|
+
}, re = [800, 1800], kt = function s(e) {
|
|
2429
|
+
document.prerendering ? G(function() {
|
|
2430
|
+
return s(e);
|
|
2689
2431
|
}) : document.readyState !== "complete" ? addEventListener("load", function() {
|
|
2690
|
-
return
|
|
2432
|
+
return s(e);
|
|
2691
2433
|
}, !0) : setTimeout(e, 0);
|
|
2692
|
-
},
|
|
2434
|
+
}, Ut = function(s, e) {
|
|
2693
2435
|
e = e || {};
|
|
2694
|
-
var t =
|
|
2695
|
-
|
|
2696
|
-
var
|
|
2697
|
-
|
|
2698
|
-
t =
|
|
2436
|
+
var t = S("TTFB"), r = E(s, t, re, e.reportAllChanges);
|
|
2437
|
+
kt(function() {
|
|
2438
|
+
var n = se();
|
|
2439
|
+
n && (t.value = Math.max(n.responseStart - V(), 0), t.entries = [n], r(!0), M(function() {
|
|
2440
|
+
t = S("TTFB", 0), (r = E(s, t, re, e.reportAllChanges))(!0);
|
|
2699
2441
|
}));
|
|
2700
2442
|
});
|
|
2701
2443
|
};
|
|
2702
|
-
const
|
|
2444
|
+
const Ht = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
|
|
2703
2445
|
__proto__: null,
|
|
2704
|
-
CLSThresholds:
|
|
2705
|
-
FCPThresholds:
|
|
2706
|
-
INPThresholds:
|
|
2707
|
-
LCPThresholds:
|
|
2708
|
-
TTFBThresholds:
|
|
2709
|
-
onCLS:
|
|
2710
|
-
onFCP:
|
|
2711
|
-
onINP:
|
|
2712
|
-
onLCP:
|
|
2713
|
-
onTTFB:
|
|
2446
|
+
CLSThresholds: J,
|
|
2447
|
+
FCPThresholds: Z,
|
|
2448
|
+
INPThresholds: ee,
|
|
2449
|
+
LCPThresholds: te,
|
|
2450
|
+
TTFBThresholds: re,
|
|
2451
|
+
onCLS: Nt,
|
|
2452
|
+
onFCP: ye,
|
|
2453
|
+
onINP: Pt,
|
|
2454
|
+
onLCP: Dt,
|
|
2455
|
+
onTTFB: Ut
|
|
2714
2456
|
}, Symbol.toStringTag, { value: "Module" }));
|
|
2715
2457
|
export {
|
|
2716
|
-
|
|
2717
|
-
|
|
2718
|
-
|
|
2719
|
-
|
|
2720
|
-
|
|
2721
|
-
|
|
2722
|
-
|
|
2723
|
-
|
|
2458
|
+
Wt as ANALYTICS_QUERY_LIMITS,
|
|
2459
|
+
Yt as ANOMALY_DETECTION,
|
|
2460
|
+
y as AppConfigValidationError,
|
|
2461
|
+
Qt as CONTENT_ANALYTICS,
|
|
2462
|
+
Ft as DATA_PROTECTION,
|
|
2463
|
+
$t as DEVICE_ANALYTICS,
|
|
2464
|
+
_ as DeviceType,
|
|
2465
|
+
Gt as ENGAGEMENT_THRESHOLDS,
|
|
2466
|
+
X as EmitterEvent,
|
|
2467
|
+
L as ErrorType,
|
|
2724
2468
|
d as EventType,
|
|
2725
|
-
|
|
2726
|
-
|
|
2727
|
-
|
|
2728
|
-
|
|
2729
|
-
|
|
2730
|
-
|
|
2731
|
-
|
|
2732
|
-
|
|
2733
|
-
|
|
2734
|
-
|
|
2735
|
-
|
|
2736
|
-
|
|
2469
|
+
Bt as INSIGHT_THRESHOLDS,
|
|
2470
|
+
xt as InitializationTimeoutError,
|
|
2471
|
+
v as IntegrationValidationError,
|
|
2472
|
+
R as Mode,
|
|
2473
|
+
Vt as PERFORMANCE_CONFIG,
|
|
2474
|
+
Xt as SEGMENTATION_ANALYTICS,
|
|
2475
|
+
zt as SESSION_ANALYTICS,
|
|
2476
|
+
Kt as SPECIAL_PAGE_URLS,
|
|
2477
|
+
oe as SamplingRateValidationError,
|
|
2478
|
+
D as ScrollDirection,
|
|
2479
|
+
Pe as SessionTimeoutValidationError,
|
|
2480
|
+
j as SpecialApiUrl,
|
|
2481
|
+
jt as TEMPORAL_ANALYSIS,
|
|
2482
|
+
C as TraceLogValidationError,
|
|
2483
|
+
qt as tracelog
|
|
2737
2484
|
};
|