@levo-so/insights 0.1.76 → 0.1.79
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/constants/storageKeys.js +21 -0
- package/dist/index.js +4 -662
- package/dist/lib/analytics.js +140 -0
- package/dist/lib/insights.js +141 -0
- package/dist/stores/config.js +13 -0
- package/dist/stores/events.js +90 -0
- package/dist/stores/session.js +66 -0
- package/dist/stores.js +18 -11
- package/dist/tracking/activity.js +33 -0
- package/dist/tracking/bounce.js +90 -0
- package/dist/tracking/clicks.js +122 -0
- package/dist/tracking/clipboard.js +20 -0
- package/dist/tracking/currentTab.js +28 -0
- package/dist/tracking/forms.js +23 -0
- package/dist/tracking/page.js +47 -0
- package/dist/tracking/scrollBehavior.js +52 -0
- package/dist/tracking/textSelection.js +27 -0
- package/dist/utils/autocapture.js +203 -0
- package/dist/utils/checkLocalStorage.js +13 -0
- package/dist/utils/detectMode.js +17 -0
- package/dist/utils/getAuthHeaders.js +11 -0
- package/dist/utils/getReferrer.js +20 -0
- package/dist/utils/getUserProperties.js +66 -0
- package/dist/utils/isIncognito.js +110 -0
- package/dist/utils/pingEndpoint.js +18 -0
- package/dist/utils/rageclick.js +13 -0
- package/package.json +3 -2
- package/dist/DA6yh6E3HQLu.js +0 -857
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
import { getLevoError as s } from "@levo-so/core";
|
|
2
|
+
import { getAttributes as g } from "../utils/autocapture.js";
|
|
3
|
+
import { isRageClick as y } from "../utils/rageclick.js";
|
|
4
|
+
const w = (c) => {
|
|
5
|
+
let i = c, e = 0;
|
|
6
|
+
for (; i && e < 10; ) {
|
|
7
|
+
const o = i.getAttribute?.("href");
|
|
8
|
+
if (o)
|
|
9
|
+
return o;
|
|
10
|
+
i = i.parentElement, e++;
|
|
11
|
+
}
|
|
12
|
+
return null;
|
|
13
|
+
}, u = (c) => {
|
|
14
|
+
const i = c.closest("a[href]"), e = i?.getAttribute("href") || w(c);
|
|
15
|
+
if (!e) return { type: null, href: null };
|
|
16
|
+
if (i?.hasAttribute("download"))
|
|
17
|
+
return { type: "download", href: e };
|
|
18
|
+
if (e.startsWith("tel:")) return { type: "tel", href: e };
|
|
19
|
+
if (e.startsWith("mailto:")) return { type: "mailto", href: e };
|
|
20
|
+
if (e.startsWith("#")) return { type: "anchor", href: e };
|
|
21
|
+
try {
|
|
22
|
+
return {
|
|
23
|
+
type: new URL(e, window.location.origin).origin === window.location.origin ? "internal" : "external",
|
|
24
|
+
href: e
|
|
25
|
+
};
|
|
26
|
+
} catch (o) {
|
|
27
|
+
return console.warn("[insights] Failed to classify link", s(o)), { type: "internal", href: e };
|
|
28
|
+
}
|
|
29
|
+
}, _ = (c) => {
|
|
30
|
+
if (typeof window > "u") return () => {
|
|
31
|
+
};
|
|
32
|
+
let i = 0, e = null;
|
|
33
|
+
const o = (t, r = !1) => {
|
|
34
|
+
const n = t.target, l = "clientX" in t ? t.clientX : t.changedTouches?.[0]?.clientX ?? 0, m = "clientY" in t ? t.clientY : t.changedTouches?.[0]?.clientY ?? 0;
|
|
35
|
+
let a = {
|
|
36
|
+
hostname: window.location.hostname,
|
|
37
|
+
pathname: window.location.pathname,
|
|
38
|
+
page_title: document.title,
|
|
39
|
+
url: window.location.href,
|
|
40
|
+
created_at: (/* @__PURE__ */ new Date()).toISOString(),
|
|
41
|
+
event_type: r ? "dblclick" : "click",
|
|
42
|
+
button_type: "button" in t ? t.button : 0
|
|
43
|
+
};
|
|
44
|
+
return n instanceof HTMLElement && (a.rage_click = y(l, m, Date.now()), a = {
|
|
45
|
+
...a,
|
|
46
|
+
...g(n)
|
|
47
|
+
}), a;
|
|
48
|
+
}, k = (t, r) => {
|
|
49
|
+
try {
|
|
50
|
+
if (Date.now() - i < 300) return;
|
|
51
|
+
const n = o(t);
|
|
52
|
+
c.track("page.click", {
|
|
53
|
+
...n,
|
|
54
|
+
href: r.href || void 0,
|
|
55
|
+
link_type: r.type,
|
|
56
|
+
is_navigation: !0
|
|
57
|
+
});
|
|
58
|
+
} catch (n) {
|
|
59
|
+
console.error("[insights] Failed to track navigation click", s(n));
|
|
60
|
+
}
|
|
61
|
+
}, d = (t, r = !1) => {
|
|
62
|
+
try {
|
|
63
|
+
if (!(t.target instanceof HTMLElement) || Date.now() - i < 300) return;
|
|
64
|
+
const n = o(t, r), l = u(t.target);
|
|
65
|
+
c.track("page.click", {
|
|
66
|
+
...n,
|
|
67
|
+
href: l.href || void 0,
|
|
68
|
+
link_type: l.type || void 0
|
|
69
|
+
});
|
|
70
|
+
} catch (n) {
|
|
71
|
+
console.error("[insights] Failed to track click", s(n));
|
|
72
|
+
}
|
|
73
|
+
}, f = (t) => {
|
|
74
|
+
if (!(t.target instanceof HTMLElement)) return;
|
|
75
|
+
const r = u(t.target);
|
|
76
|
+
if (r.type === "external" || r.type === "download") {
|
|
77
|
+
k(t, r);
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
80
|
+
if (e) {
|
|
81
|
+
clearTimeout(e), e = null;
|
|
82
|
+
return;
|
|
83
|
+
}
|
|
84
|
+
e = setTimeout(() => {
|
|
85
|
+
d(t, !1), e = null;
|
|
86
|
+
}, 250);
|
|
87
|
+
}, h = (t) => {
|
|
88
|
+
e && (clearTimeout(e), e = null), d(t, !0);
|
|
89
|
+
}, p = (t) => {
|
|
90
|
+
try {
|
|
91
|
+
if (!(t.target instanceof HTMLElement)) return;
|
|
92
|
+
i = Date.now();
|
|
93
|
+
const r = u(t.target);
|
|
94
|
+
if (r.type === "external" || r.type === "download") {
|
|
95
|
+
const l = o(t);
|
|
96
|
+
c.track("page.click", {
|
|
97
|
+
...l,
|
|
98
|
+
href: r.href || void 0,
|
|
99
|
+
link_type: r.type,
|
|
100
|
+
is_navigation: !0,
|
|
101
|
+
is_touch: !0
|
|
102
|
+
});
|
|
103
|
+
return;
|
|
104
|
+
}
|
|
105
|
+
const n = o(t);
|
|
106
|
+
c.track("page.click", {
|
|
107
|
+
...n,
|
|
108
|
+
href: r.href || void 0,
|
|
109
|
+
link_type: r.type || void 0,
|
|
110
|
+
is_touch: !0
|
|
111
|
+
});
|
|
112
|
+
} catch (r) {
|
|
113
|
+
console.error("[insights] Failed to track touch", s(r));
|
|
114
|
+
}
|
|
115
|
+
};
|
|
116
|
+
return document.addEventListener("click", f), document.addEventListener("dblclick", h), document.addEventListener("touchend", p, { passive: !0 }), () => {
|
|
117
|
+
document.removeEventListener("click", f), document.removeEventListener("dblclick", h), document.removeEventListener("touchend", p), e && clearTimeout(e);
|
|
118
|
+
};
|
|
119
|
+
};
|
|
120
|
+
export {
|
|
121
|
+
_ as initClicksTracker
|
|
122
|
+
};
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { getLevoError as p } from "@levo-so/core";
|
|
2
|
+
import { getPropertiesFromEvent as u } from "../utils/autocapture.js";
|
|
3
|
+
const s = (c) => {
|
|
4
|
+
if (typeof window > "u") return () => {
|
|
5
|
+
};
|
|
6
|
+
const t = (n) => (i) => {
|
|
7
|
+
try {
|
|
8
|
+
const e = u(i, n);
|
|
9
|
+
e && c.track("page.copy", e);
|
|
10
|
+
} catch (e) {
|
|
11
|
+
console.error(`[insights] Failed to track clipboard ${n}`, p(e));
|
|
12
|
+
}
|
|
13
|
+
}, r = t("copy"), o = t("cut");
|
|
14
|
+
return document.addEventListener("copy", r, { capture: !0 }), document.addEventListener("cut", o, { capture: !0 }), () => {
|
|
15
|
+
document.removeEventListener("copy", r, { capture: !0 }), document.removeEventListener("cut", o, { capture: !0 });
|
|
16
|
+
};
|
|
17
|
+
};
|
|
18
|
+
export {
|
|
19
|
+
s as initClipboardTracker
|
|
20
|
+
};
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { atom as c } from "nanostores";
|
|
2
|
+
import { STORAGE_KEYS as a } from "../constants/storageKeys.js";
|
|
3
|
+
import { $session as i, updateSession as l } from "../stores/session.js";
|
|
4
|
+
const s = c(null), g = (b) => {
|
|
5
|
+
if (typeof window > "u") return () => {
|
|
6
|
+
};
|
|
7
|
+
let t = sessionStorage.getItem(a.current_tab);
|
|
8
|
+
const { allTabs: n } = i.get();
|
|
9
|
+
t && n.includes(t) && (t = null), t || (t = `${Date.now()}-${Math.random().toString(36).substring(2, 11)}`, sessionStorage.setItem(a.current_tab, t));
|
|
10
|
+
const e = t;
|
|
11
|
+
s.set(e), n.includes(e) || l({ allTabs: [...n, e] });
|
|
12
|
+
const r = () => {
|
|
13
|
+
if (!e) return;
|
|
14
|
+
const { allTabs: o } = i.get();
|
|
15
|
+
if (o.includes(e)) {
|
|
16
|
+
const u = o.filter((d) => d !== e);
|
|
17
|
+
l({ allTabs: u });
|
|
18
|
+
}
|
|
19
|
+
};
|
|
20
|
+
return window.addEventListener("beforeunload", r), () => {
|
|
21
|
+
window.removeEventListener("beforeunload", r), r(), s.set(null);
|
|
22
|
+
};
|
|
23
|
+
}, p = () => s.get();
|
|
24
|
+
export {
|
|
25
|
+
s as $currentTab,
|
|
26
|
+
p as getCurrentTab,
|
|
27
|
+
g as initCurrentTabTracker
|
|
28
|
+
};
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { getLevoError as u } from "@levo-so/core";
|
|
2
|
+
import { getPropertiesFromEvent as m } from "../utils/autocapture.js";
|
|
3
|
+
const p = (c) => {
|
|
4
|
+
if (typeof window > "u") return () => {
|
|
5
|
+
};
|
|
6
|
+
const r = (t) => (i) => {
|
|
7
|
+
try {
|
|
8
|
+
const e = m(i, t);
|
|
9
|
+
if (e) {
|
|
10
|
+
const s = t === "submit" ? "form.submit" : "form.change";
|
|
11
|
+
c.track(s, e);
|
|
12
|
+
}
|
|
13
|
+
} catch (e) {
|
|
14
|
+
console.error(`[insights] Failed to track form ${t}`, u(e));
|
|
15
|
+
}
|
|
16
|
+
}, o = r("change"), n = r("submit");
|
|
17
|
+
return document.addEventListener("change", o, { capture: !0 }), document.addEventListener("submit", n, { capture: !0 }), () => {
|
|
18
|
+
document.removeEventListener("change", o, { capture: !0 }), document.removeEventListener("submit", n, { capture: !0 });
|
|
19
|
+
};
|
|
20
|
+
};
|
|
21
|
+
export {
|
|
22
|
+
p as initFormsTracker
|
|
23
|
+
};
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { getLevoError as w } from "@levo-so/core";
|
|
2
|
+
import { $config as c } from "../stores/config.js";
|
|
3
|
+
import { $session as f } from "../stores/session.js";
|
|
4
|
+
const u = (p) => {
|
|
5
|
+
if (typeof window > "u") return () => {
|
|
6
|
+
};
|
|
7
|
+
const { page_id: r } = c.get();
|
|
8
|
+
let a = r || "", s = typeof window < "u" ? window.location.href : "";
|
|
9
|
+
const d = () => {
|
|
10
|
+
const { isIdentified: e } = f.get();
|
|
11
|
+
if (e)
|
|
12
|
+
try {
|
|
13
|
+
p.page({
|
|
14
|
+
resource: "page"
|
|
15
|
+
});
|
|
16
|
+
} catch (i) {
|
|
17
|
+
console.error("[insights] Failed to send page view", w(i));
|
|
18
|
+
}
|
|
19
|
+
};
|
|
20
|
+
if (r) {
|
|
21
|
+
const e = c.listen((i, o, t) => {
|
|
22
|
+
const { page_id: n } = i;
|
|
23
|
+
t === "page_id" && n && a !== n && (a = n, d());
|
|
24
|
+
});
|
|
25
|
+
return () => {
|
|
26
|
+
e();
|
|
27
|
+
};
|
|
28
|
+
} else {
|
|
29
|
+
const e = () => {
|
|
30
|
+
if (typeof window > "u") return;
|
|
31
|
+
const t = window.location.href;
|
|
32
|
+
t !== s && (s = t, d());
|
|
33
|
+
};
|
|
34
|
+
window.addEventListener("popstate", e);
|
|
35
|
+
const i = window.history.pushState, o = window.history.replaceState;
|
|
36
|
+
return window.history.pushState = function(...t) {
|
|
37
|
+
i.apply(this, t), e();
|
|
38
|
+
}, window.history.replaceState = function(...t) {
|
|
39
|
+
o.apply(this, t), e();
|
|
40
|
+
}, () => {
|
|
41
|
+
window.removeEventListener("popstate", e), window.history.pushState = i, window.history.replaceState = o;
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
};
|
|
45
|
+
export {
|
|
46
|
+
u as initPageTracker
|
|
47
|
+
};
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { debounce as _ } from "lodash-es";
|
|
2
|
+
import { map as b } from "nanostores";
|
|
3
|
+
const r = b({
|
|
4
|
+
depth: 0,
|
|
5
|
+
speedCategory: "read",
|
|
6
|
+
direction: "down"
|
|
7
|
+
}), Y = (h) => {
|
|
8
|
+
if (typeof window > "u") return () => {
|
|
9
|
+
};
|
|
10
|
+
let c = {
|
|
11
|
+
prevMilestone: -1,
|
|
12
|
+
// Use -1 to ensure first milestone (even 0) is tracked
|
|
13
|
+
prevScrollY: 0,
|
|
14
|
+
prevTime: Date.now()
|
|
15
|
+
};
|
|
16
|
+
const i = 5, u = 300, w = 250, o = () => {
|
|
17
|
+
const e = window.scrollY, f = document.documentElement.scrollHeight, v = window.innerHeight, d = f - v;
|
|
18
|
+
if (d <= 0) return;
|
|
19
|
+
const S = Math.round(e / d * 100), D = Math.max(0, Math.min(100, S)), t = Math.floor(D / i) * i, { prevMilestone: s, prevScrollY: g, prevTime: E } = c;
|
|
20
|
+
if (t === s) return;
|
|
21
|
+
const p = Date.now(), a = (p - E) / 1e3, C = Math.abs(e - g), M = a > 0 ? C / a : 0, T = t > s ? "down" : "up", H = M > u ? "scan" : "read";
|
|
22
|
+
r.set({
|
|
23
|
+
depth: t,
|
|
24
|
+
speedCategory: H,
|
|
25
|
+
direction: T
|
|
26
|
+
}), c = {
|
|
27
|
+
prevMilestone: t,
|
|
28
|
+
prevScrollY: e,
|
|
29
|
+
prevTime: p
|
|
30
|
+
};
|
|
31
|
+
}, n = _(o, w);
|
|
32
|
+
window.addEventListener("scroll", n);
|
|
33
|
+
let l = 0;
|
|
34
|
+
const m = r.listen((e) => {
|
|
35
|
+
e.depth !== l && (l = e.depth, h.track("page.scroll", {
|
|
36
|
+
depth: e.depth,
|
|
37
|
+
speed_category: e.speedCategory,
|
|
38
|
+
direction: e.direction
|
|
39
|
+
}));
|
|
40
|
+
});
|
|
41
|
+
return typeof window.requestIdleCallback == "function" ? window.requestIdleCallback(() => o()) : setTimeout(o, 0), () => {
|
|
42
|
+
window.removeEventListener("scroll", n), n.cancel(), m(), r.set({
|
|
43
|
+
depth: 0,
|
|
44
|
+
speedCategory: "read",
|
|
45
|
+
direction: "down"
|
|
46
|
+
});
|
|
47
|
+
};
|
|
48
|
+
};
|
|
49
|
+
export {
|
|
50
|
+
r as $scrollBehavior,
|
|
51
|
+
Y as initScrollBehaviorTracker
|
|
52
|
+
};
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { debounce as r } from "lodash-es";
|
|
2
|
+
import { atom as l } from "nanostores";
|
|
3
|
+
import { makeSafeText as s } from "../utils/autocapture.js";
|
|
4
|
+
const n = l(null), f = (c) => {
|
|
5
|
+
if (typeof window > "u") return () => {
|
|
6
|
+
};
|
|
7
|
+
const t = r(() => {
|
|
8
|
+
const e = window.getSelection();
|
|
9
|
+
if (e && e.rangeCount > 0) {
|
|
10
|
+
const o = e.toString().trim();
|
|
11
|
+
o && n.set(o);
|
|
12
|
+
}
|
|
13
|
+
}, 1e3);
|
|
14
|
+
document.addEventListener("selectionchange", t);
|
|
15
|
+
const i = n.listen((e) => {
|
|
16
|
+
e && c.track("page.selection", {
|
|
17
|
+
text: s(e)
|
|
18
|
+
});
|
|
19
|
+
});
|
|
20
|
+
return () => {
|
|
21
|
+
document.removeEventListener("selectionchange", t), t.cancel(), i(), n.set(null);
|
|
22
|
+
};
|
|
23
|
+
};
|
|
24
|
+
export {
|
|
25
|
+
n as $selectedText,
|
|
26
|
+
f as initTextSelectionTracker
|
|
27
|
+
};
|
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
const d = (t) => Object.prototype.toString.call(t) == "[object String]", E = (t, e) => t.indexOf(e) !== -1, l = (t) => t.replace(/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g, ""), b = (t) => t === void 0, S = (t) => t === null, m = (t) => b(t) || S(t), x = (t) => !!t && t?.nodeType === 3;
|
|
2
|
+
function T(t) {
|
|
3
|
+
return !!t && t?.nodeType === 1;
|
|
4
|
+
}
|
|
5
|
+
function k(t, e) {
|
|
6
|
+
return !!t && !!t?.tagName && t?.tagName.toLowerCase() === e.toLowerCase();
|
|
7
|
+
}
|
|
8
|
+
function A(t) {
|
|
9
|
+
return t ? l(t).split(/\s+/) : [];
|
|
10
|
+
}
|
|
11
|
+
function L(t) {
|
|
12
|
+
let e = "";
|
|
13
|
+
switch (typeof t?.className) {
|
|
14
|
+
case "string":
|
|
15
|
+
e = t?.className;
|
|
16
|
+
break;
|
|
17
|
+
// TODO: when is this ever used?
|
|
18
|
+
case "object":
|
|
19
|
+
e = (t?.className && "baseVal" in t.className ? (t?.className).baseVal : null) || t?.getAttribute("class") || "";
|
|
20
|
+
break;
|
|
21
|
+
default:
|
|
22
|
+
e = "";
|
|
23
|
+
}
|
|
24
|
+
return A(e);
|
|
25
|
+
}
|
|
26
|
+
const a = (t, e = 255) => m(t) ? "" : l(t).split(/(\s+)/).filter((n) => p(n)).join("").replace(/[\r\n]/g, " ").replace(/[ ]+/g, " ").substring(0, e), h = ["span", "strong", "em", "i", "b", "mark", "code", "small", "sub", "sup", "label"], g = (t) => {
|
|
27
|
+
let e = "";
|
|
28
|
+
if (v(t) && t?.childNodes && t?.childNodes.length) {
|
|
29
|
+
for (const n of t.childNodes)
|
|
30
|
+
x(n) && n.textContent && (e += a(n.textContent) ?? "");
|
|
31
|
+
if (!l(e)) {
|
|
32
|
+
const n = t.querySelectorAll(h.join(", "));
|
|
33
|
+
for (const s of n) {
|
|
34
|
+
const i = s.textContent;
|
|
35
|
+
i && (e += `${a(i)} `);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
if (!l(e) && t instanceof HTMLElement) {
|
|
39
|
+
const n = t.innerText;
|
|
40
|
+
n && (e = a(n.substring(0, 500)));
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
return l(e);
|
|
44
|
+
}, $ = (t) => b(t.target) ? t?.srcElement || null : t?.target?.shadowRoot ? t?.composedPath()?.[0] || null : t?.target || null, R = (t, e) => {
|
|
45
|
+
if (!window || !t || k(t, "html") || !T(t))
|
|
46
|
+
return !1;
|
|
47
|
+
const n = window.getComputedStyle(t);
|
|
48
|
+
if (n && n.getPropertyValue("cursor") === "pointer" && e.type === "click")
|
|
49
|
+
return !0;
|
|
50
|
+
switch (t?.tagName.toLowerCase()) {
|
|
51
|
+
case "html":
|
|
52
|
+
return !1;
|
|
53
|
+
case "form":
|
|
54
|
+
return e.type === "submit";
|
|
55
|
+
case "input":
|
|
56
|
+
case "select":
|
|
57
|
+
case "textarea":
|
|
58
|
+
return ["change", "click"].includes(e.type);
|
|
59
|
+
default:
|
|
60
|
+
return e.type === "click";
|
|
61
|
+
}
|
|
62
|
+
}, _ = /* @__PURE__ */ new Set([
|
|
63
|
+
"password",
|
|
64
|
+
"passwd",
|
|
65
|
+
"pwd",
|
|
66
|
+
"creditcard",
|
|
67
|
+
"cardnumber",
|
|
68
|
+
"ccnum",
|
|
69
|
+
"ccnumber",
|
|
70
|
+
"cvv",
|
|
71
|
+
"cvc",
|
|
72
|
+
"csc",
|
|
73
|
+
"securitycode",
|
|
74
|
+
"ssn",
|
|
75
|
+
"socialsecurity",
|
|
76
|
+
"routingnumber",
|
|
77
|
+
"accountnumber",
|
|
78
|
+
"bankaccount",
|
|
79
|
+
"secretkey",
|
|
80
|
+
"apikey",
|
|
81
|
+
"accesstoken"
|
|
82
|
+
]);
|
|
83
|
+
function v(t) {
|
|
84
|
+
if (E(L(t), "ph-include"))
|
|
85
|
+
return !0;
|
|
86
|
+
const e = t.type || "";
|
|
87
|
+
if (d(e))
|
|
88
|
+
switch (e.toLowerCase()) {
|
|
89
|
+
case "hidden":
|
|
90
|
+
return !1;
|
|
91
|
+
case "password":
|
|
92
|
+
return !1;
|
|
93
|
+
}
|
|
94
|
+
const n = t.name || t?.id || "";
|
|
95
|
+
if (d(n)) {
|
|
96
|
+
const s = n.toLowerCase().replace(/[^a-z]/g, "");
|
|
97
|
+
if (_.has(s))
|
|
98
|
+
return !1;
|
|
99
|
+
}
|
|
100
|
+
return !0;
|
|
101
|
+
}
|
|
102
|
+
const y = "(4[0-9]{12}(?:[0-9]{3})?)|(5[1-5][0-9]{14})|(6(?:011|5[0-9]{2})[0-9]{12})|(3[47][0-9]{13})|(3(?:0[0-5]|[68][0-9])[0-9]{11})|((?:2131|1800|35[0-9]{3})[0-9]{11})", F = new RegExp(`^(?:${y})$`), j = new RegExp(y), N = "\\d{3}-?\\d{2}-?\\d{4}", I = new RegExp(`^(${N})$`), P = new RegExp(`(${N})`), p = (t, e = !0) => !(m(t) || d(t) && (t = l(t), (e ? F : j).test((t || "").replace(/[- ]/g, "")) || (e ? I : P).test(t))), V = (t) => d(t) ? t.substring(0, 10) === "_ngcontent" || t.substring(0, 7) === "_nghost" : !1, W = (t) => {
|
|
103
|
+
let e = g(t);
|
|
104
|
+
return e = `${e} ${w(t)}`.trim(), p(e) ? e : "";
|
|
105
|
+
};
|
|
106
|
+
function w(t) {
|
|
107
|
+
let e = "";
|
|
108
|
+
if (t?.childNodes.length)
|
|
109
|
+
for (const n of t.childNodes) {
|
|
110
|
+
const s = n.tagName?.toLowerCase();
|
|
111
|
+
if (n && s && h.includes(s))
|
|
112
|
+
try {
|
|
113
|
+
const i = g(n);
|
|
114
|
+
e = `${e} ${i}`.trim(), n?.childNodes.length && (e = `${e} ${w(n)}`.trim());
|
|
115
|
+
} catch {
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
return e;
|
|
119
|
+
}
|
|
120
|
+
const D = (t) => {
|
|
121
|
+
const e = t.tagName?.toLowerCase(), n = e === "a" || e === "button" ? W(t) : g(t);
|
|
122
|
+
if (n) return { text: n, source: "text" };
|
|
123
|
+
const s = t.getAttribute("aria-label");
|
|
124
|
+
if (s) return { text: a(s), source: "aria-label" };
|
|
125
|
+
const i = t.getAttribute("title");
|
|
126
|
+
if (i) return { text: a(i), source: "title" };
|
|
127
|
+
const u = t.getAttribute("data-track-label");
|
|
128
|
+
if (u) return { text: a(u), source: "data-track-label" };
|
|
129
|
+
const o = t.querySelector("img[alt], svg[aria-label]");
|
|
130
|
+
if (o) {
|
|
131
|
+
const r = o.getAttribute("alt") || o.getAttribute("aria-label");
|
|
132
|
+
if (r) return { text: a(r), source: "alt" };
|
|
133
|
+
}
|
|
134
|
+
const f = t.getAttribute("placeholder");
|
|
135
|
+
if (f) return { text: a(f), source: "placeholder" };
|
|
136
|
+
if (t instanceof HTMLElement && t.innerText) {
|
|
137
|
+
const r = t.innerText.substring(0, 500);
|
|
138
|
+
if (r.trim())
|
|
139
|
+
return { text: a(r), source: "innerText" };
|
|
140
|
+
}
|
|
141
|
+
return { text: "", source: "none" };
|
|
142
|
+
}, M = ["input", "textarea", "select"], q = (t) => {
|
|
143
|
+
const e = t?.tagName?.toLowerCase(), n = {
|
|
144
|
+
element: e
|
|
145
|
+
}, s = D(t);
|
|
146
|
+
n.text = s.text, n.text_source = s.source;
|
|
147
|
+
const i = t.getAttribute("aria-label");
|
|
148
|
+
i && (n.aria_label = a(i));
|
|
149
|
+
const u = t.getAttribute("role");
|
|
150
|
+
u && (n.role = u);
|
|
151
|
+
const o = {};
|
|
152
|
+
for (const r of t.attributes)
|
|
153
|
+
(r.name.startsWith("data-track-") || r.name.startsWith("data-analytics-")) && (o[r.name] = a(r.value));
|
|
154
|
+
Object.keys(o).length && (n.tracking_data = o);
|
|
155
|
+
const f = Array.from(t.attributes).reduce(
|
|
156
|
+
(r, c) => {
|
|
157
|
+
if (p(c.value) && !V(c.name)) {
|
|
158
|
+
if (c.name === "class" || c.name.startsWith("data-track-") || c.name.startsWith("data-analytics-"))
|
|
159
|
+
return r;
|
|
160
|
+
r[c.name] = typeof c?.value == "string" ? a(c.value) : c.value;
|
|
161
|
+
}
|
|
162
|
+
return r;
|
|
163
|
+
},
|
|
164
|
+
{}
|
|
165
|
+
);
|
|
166
|
+
if (n.attributes = f, M.includes(e) || t?.getAttribute("contenteditable") === "true") {
|
|
167
|
+
let r;
|
|
168
|
+
t.matches('input[type="checkbox"], input[type="radio"]') ? r = t.checked : t.matches("input, select, textarea") && !t.matches('input[type="password"]') && (r = t.value), r !== void 0 && (n.value = typeof r == "string" || r === null ? a(r, 1024) : r);
|
|
169
|
+
let c = "";
|
|
170
|
+
n?.attributes.id && (c = a(
|
|
171
|
+
document.querySelector(`label[for="${n?.attributes.id}"]`)?.textContent?.trim() || ""
|
|
172
|
+
));
|
|
173
|
+
const C = t.closest("label");
|
|
174
|
+
c || (c = a(C?.textContent?.trim() || "")), c && (n.label = c);
|
|
175
|
+
}
|
|
176
|
+
return n;
|
|
177
|
+
}, O = (t, e) => {
|
|
178
|
+
let n = $(t);
|
|
179
|
+
x(n) && (n = n.parentNode || null);
|
|
180
|
+
const s = ["copy", "cut"].includes(e);
|
|
181
|
+
if (n && (s || R(n, t))) {
|
|
182
|
+
const i = q(n);
|
|
183
|
+
if (s) {
|
|
184
|
+
const u = a(window?.getSelection()?.toString()), o = t?.type || "clipboard";
|
|
185
|
+
i.copy_text = u ?? "", i.copy_type = o;
|
|
186
|
+
}
|
|
187
|
+
return i;
|
|
188
|
+
}
|
|
189
|
+
return null;
|
|
190
|
+
};
|
|
191
|
+
export {
|
|
192
|
+
q as getAttributes,
|
|
193
|
+
W as getDirectAndNestedSpanText,
|
|
194
|
+
D as getElementTextWithFallback,
|
|
195
|
+
$ as getEventTarget,
|
|
196
|
+
O as getPropertiesFromEvent,
|
|
197
|
+
g as getSafeText,
|
|
198
|
+
V as isAngularStyleAttr,
|
|
199
|
+
x as isTextNode,
|
|
200
|
+
a as makeSafeText,
|
|
201
|
+
R as shouldCaptureDomEvent,
|
|
202
|
+
p as shouldCaptureValue
|
|
203
|
+
};
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
const t = () => {
|
|
2
|
+
if (typeof window > "u" || !("localStorage" in window))
|
|
3
|
+
return !1;
|
|
4
|
+
try {
|
|
5
|
+
const e = "__levo_test__";
|
|
6
|
+
return window.localStorage.setItem(e, "test"), window.localStorage.removeItem(e), !0;
|
|
7
|
+
} catch {
|
|
8
|
+
return !1;
|
|
9
|
+
}
|
|
10
|
+
};
|
|
11
|
+
export {
|
|
12
|
+
t as checkLocalStorageAvailable
|
|
13
|
+
};
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { pingEndpoint as n } from "./pingEndpoint.js";
|
|
2
|
+
const s = async (u) => {
|
|
3
|
+
const {
|
|
4
|
+
mode: t = "auto",
|
|
5
|
+
insightsUrl: e,
|
|
6
|
+
directInsightsUrl: r,
|
|
7
|
+
pingTimeout: i = 3e3,
|
|
8
|
+
debug: l = !1
|
|
9
|
+
} = u;
|
|
10
|
+
if (l)
|
|
11
|
+
return { mode: "proxy", url: e || "/debug-api" };
|
|
12
|
+
const o = Number.isFinite(i) && i >= 0 ? i : 3e3;
|
|
13
|
+
return t === "direct" ? { mode: "direct", url: r ?? null } : t === "proxy" || !r ? { mode: "proxy", url: e ?? null } : (e ? await n(`${e}/ping`, o) : !1) ? { mode: "proxy", url: e ?? null } : await n(`${r}/ping`, o) ? { mode: "direct", url: r } : { mode: "proxy", url: e ?? null };
|
|
14
|
+
};
|
|
15
|
+
export {
|
|
16
|
+
s as detectMode
|
|
17
|
+
};
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { getVisitorSource as f } from "@analytics/visitor-source";
|
|
2
|
+
const a = () => {
|
|
3
|
+
if (typeof document > "u")
|
|
4
|
+
return {};
|
|
5
|
+
const {
|
|
6
|
+
type: t,
|
|
7
|
+
referrer: o,
|
|
8
|
+
data: r = {}
|
|
9
|
+
} = f({
|
|
10
|
+
referrer: document.referrer,
|
|
11
|
+
currentUrl: window.location.href,
|
|
12
|
+
mapper: null
|
|
13
|
+
}), n = Object.keys(r);
|
|
14
|
+
for (const e of n)
|
|
15
|
+
r[e] && Array.isArray(r[e]) && r[e].length > 0 && (r[e] = r[e]?.[0]);
|
|
16
|
+
return { type: t, referrer: o, data: r, raw: document.referrer };
|
|
17
|
+
};
|
|
18
|
+
export {
|
|
19
|
+
a as getReferrer
|
|
20
|
+
};
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import h from "get-user-locale";
|
|
2
|
+
import m from "./isIncognito.js";
|
|
3
|
+
const l = () => {
|
|
4
|
+
const o = document.createElement("canvas"), n = o?.getContext("webgl") || o?.getContext("experimental-webgl");
|
|
5
|
+
if (!n)
|
|
6
|
+
return null;
|
|
7
|
+
const r = n?.getExtension("WEBGL_debug_renderer_info");
|
|
8
|
+
return r ? n?.getParameter(r.UNMASKED_RENDERER_WEBGL) : null;
|
|
9
|
+
}, u = async () => {
|
|
10
|
+
let o = "", n = "", r = !1, i = !1;
|
|
11
|
+
const e = {};
|
|
12
|
+
if (!window)
|
|
13
|
+
return {
|
|
14
|
+
locale: o,
|
|
15
|
+
timezone: n,
|
|
16
|
+
dark_mode: r,
|
|
17
|
+
private_mode: i,
|
|
18
|
+
properties: e
|
|
19
|
+
};
|
|
20
|
+
try {
|
|
21
|
+
({ isPrivate: i } = await m());
|
|
22
|
+
} catch (t) {
|
|
23
|
+
console.error(t);
|
|
24
|
+
}
|
|
25
|
+
try {
|
|
26
|
+
r = window.matchMedia?.("(prefers-color-scheme: dark)").matches;
|
|
27
|
+
} catch (t) {
|
|
28
|
+
console.error(t);
|
|
29
|
+
}
|
|
30
|
+
try {
|
|
31
|
+
n = Intl.DateTimeFormat().resolvedOptions().timeZone;
|
|
32
|
+
} catch (t) {
|
|
33
|
+
console.error(t);
|
|
34
|
+
}
|
|
35
|
+
try {
|
|
36
|
+
o = h();
|
|
37
|
+
} catch (t) {
|
|
38
|
+
console.error(t);
|
|
39
|
+
}
|
|
40
|
+
if (navigator && "connection" in navigator) {
|
|
41
|
+
const t = navigator.connection || navigator?.mozConnection || navigator.webkitConnection;
|
|
42
|
+
e.network_type = t.effectiveType;
|
|
43
|
+
}
|
|
44
|
+
if (e.width = window?.innerWidth, e.height = window?.innerHeight, e.pixel_ratio = window?.devicePixelRatio, screen && (e.screen_width = screen?.width, e.screen_height = screen?.height, e.color_depth = screen?.colorDepth, e.orientation = screen?.orientation?.type), navigator && "getBattery" in navigator) {
|
|
45
|
+
const t = await navigator?.getBattery();
|
|
46
|
+
t && (e.battery_level = Number((t?.level * 100).toFixed(0)), e.battery_charging = t?.charging, e.battery_discharging_time = t?.dischargingTime, e.battery_full_charge_capacity = t?.fullChargeCapacity, e.battery_charging_time = t?.chargingTime);
|
|
47
|
+
}
|
|
48
|
+
navigator && "deviceMemory" in navigator && (e.device_memory = navigator?.deviceMemory);
|
|
49
|
+
const s = "ontouchstart" in window || typeof navigator?.maxTouchPoints < "u" && navigator?.maxTouchPoints > 0;
|
|
50
|
+
if (e.touch_supported = s, "hardwareConcurrency" in navigator && (e.hardware_concurrency = navigator?.hardwareConcurrency), navigator && "mediaDevices" in navigator) {
|
|
51
|
+
const c = await navigator?.mediaDevices?.enumerateDevices(), g = c.some((a) => a?.kind === "videoinput");
|
|
52
|
+
e.camera_supported = g;
|
|
53
|
+
const d = c.some((a) => a?.kind === "audioinput");
|
|
54
|
+
e.microphone_supported = d;
|
|
55
|
+
}
|
|
56
|
+
return e.gpu = l(), {
|
|
57
|
+
locale: o,
|
|
58
|
+
timezone: n,
|
|
59
|
+
dark_mode: r,
|
|
60
|
+
private_mode: i,
|
|
61
|
+
properties: e
|
|
62
|
+
};
|
|
63
|
+
};
|
|
64
|
+
export {
|
|
65
|
+
u as getUserProperties
|
|
66
|
+
};
|