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