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