@levo-so/insights 0.1.78 → 0.1.80
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/index.js +663 -4
- package/dist/stores.js +11 -18
- package/dist/textSelection-CnZdywep.js +583 -0
- package/package.json +2 -2
- package/dist/constants/storageKeys.js +0 -21
- package/dist/lib/analytics.js +0 -140
- package/dist/lib/insights.js +0 -141
- package/dist/stores/config.js +0 -13
- package/dist/stores/events.js +0 -90
- package/dist/stores/session.js +0 -66
- package/dist/tracking/activity.js +0 -33
- package/dist/tracking/bounce.js +0 -90
- package/dist/tracking/clicks.js +0 -122
- package/dist/tracking/clipboard.js +0 -20
- package/dist/tracking/currentTab.js +0 -28
- package/dist/tracking/forms.js +0 -23
- package/dist/tracking/page.js +0 -47
- package/dist/tracking/scrollBehavior.js +0 -52
- package/dist/tracking/textSelection.js +0 -27
- package/dist/utils/autocapture.js +0 -203
- package/dist/utils/checkLocalStorage.js +0 -13
- package/dist/utils/detectMode.js +0 -17
- package/dist/utils/getAuthHeaders.js +0 -11
- package/dist/utils/getReferrer.js +0 -20
- package/dist/utils/getUserProperties.js +0 -66
- package/dist/utils/isIncognito.js +0 -110
- package/dist/utils/pingEndpoint.js +0 -18
- package/dist/utils/rageclick.js +0 -13
package/dist/lib/analytics.js
DELETED
|
@@ -1,140 +0,0 @@
|
|
|
1
|
-
import { getLevoError as S } from "@levo-so/core";
|
|
2
|
-
import { Analytics as j } from "analytics";
|
|
3
|
-
import { getConfig as k } from "../stores/config.js";
|
|
4
|
-
import { resetRateLimit as z } from "../stores/events.js";
|
|
5
|
-
import { getSession as f, updateSession as a } from "../stores/session.js";
|
|
6
|
-
import { getCurrentTab as D } from "../tracking/currentTab.js";
|
|
7
|
-
import { getAuthHeaders as M } from "../utils/getAuthHeaders.js";
|
|
8
|
-
const q = (r, p, s) => {
|
|
9
|
-
const { debug: I } = k();
|
|
10
|
-
if (!r)
|
|
11
|
-
return null;
|
|
12
|
-
const h = {
|
|
13
|
-
name: r.workspace,
|
|
14
|
-
/**
|
|
15
|
-
* Handle track events (custom events like clicks, scrolls, etc.)
|
|
16
|
-
*
|
|
17
|
-
* Enriches the event with:
|
|
18
|
-
* - Session/device IDs
|
|
19
|
-
* - Page metadata (URL, title, etc.)
|
|
20
|
-
* - Tab information
|
|
21
|
-
* - Timestamp
|
|
22
|
-
*
|
|
23
|
-
* Then queues for batched sending.
|
|
24
|
-
*/
|
|
25
|
-
track: ({ payload: e }) => {
|
|
26
|
-
if (!s()) return;
|
|
27
|
-
const o = e?.properties || {};
|
|
28
|
-
p(e.event, o);
|
|
29
|
-
},
|
|
30
|
-
/**
|
|
31
|
-
* Handle page view events.
|
|
32
|
-
*
|
|
33
|
-
* Called when navigating to a new page (in SPAs) or on initial load.
|
|
34
|
-
* Resets the rate limit counter and tracks a page.view event.
|
|
35
|
-
*/
|
|
36
|
-
page: ({ payload: e }) => {
|
|
37
|
-
if (!s()) return;
|
|
38
|
-
z();
|
|
39
|
-
const o = e?.properties || {};
|
|
40
|
-
p("page.view", {
|
|
41
|
-
...o,
|
|
42
|
-
resource: "page"
|
|
43
|
-
});
|
|
44
|
-
},
|
|
45
|
-
/**
|
|
46
|
-
* Handle identify events (session establishment).
|
|
47
|
-
*
|
|
48
|
-
* This is called when identify() is invoked. It:
|
|
49
|
-
* 1. Reads identity from session store (set by init())
|
|
50
|
-
* 2. Checks if already identified (via BroadcastChannel) - if so, skip
|
|
51
|
-
* 3. Calls /welcome API to get session/device IDs
|
|
52
|
-
* 4. On success, broadcasts session to other tabs
|
|
53
|
-
*
|
|
54
|
-
* The /welcome API uses HttpOnly cookies to maintain persistent
|
|
55
|
-
* device identity across sessions.
|
|
56
|
-
*/
|
|
57
|
-
identify: ({ payload: e }) => {
|
|
58
|
-
if (!s()) return;
|
|
59
|
-
const { workspace: o, site_id: w, debug: l } = k(), {
|
|
60
|
-
mode: d,
|
|
61
|
-
isIdentified: m,
|
|
62
|
-
isIdentifying: g,
|
|
63
|
-
sessionToken: _,
|
|
64
|
-
deviceToken: b,
|
|
65
|
-
insightsBaseUrl: u,
|
|
66
|
-
identity: i
|
|
67
|
-
} = f(), y = D(), T = f().allTabs.length;
|
|
68
|
-
if (!u || !i)
|
|
69
|
-
return;
|
|
70
|
-
const v = {
|
|
71
|
-
...{
|
|
72
|
-
private_mode: e.traits?.private_mode ?? i.privateMode ?? !1,
|
|
73
|
-
dark_mode: e.traits?.dark_mode ?? i.darkMode ?? !1,
|
|
74
|
-
timezone: e.traits?.timezone ?? i.timezone ?? "",
|
|
75
|
-
locale: e.traits?.locale ?? i.locale ?? "",
|
|
76
|
-
referrer: e.traits?.referrer ?? i.referrer ?? { type: "", referrer: {}, data: {} },
|
|
77
|
-
properties: {
|
|
78
|
-
...i.properties
|
|
79
|
-
}
|
|
80
|
-
},
|
|
81
|
-
workspace_id: o ?? "",
|
|
82
|
-
site_id: w ?? void 0,
|
|
83
|
-
hostname: window.location.hostname,
|
|
84
|
-
pathname: window.location.pathname,
|
|
85
|
-
page_title: document.title,
|
|
86
|
-
url: window.location.href,
|
|
87
|
-
created_at: (/* @__PURE__ */ new Date()).toISOString(),
|
|
88
|
-
tab_id: y ?? "",
|
|
89
|
-
tab_count: T ?? 0
|
|
90
|
-
};
|
|
91
|
-
if (l && console.log("[@levo-so/insights] Identification triggered:", {
|
|
92
|
-
isIdentified: m,
|
|
93
|
-
isIdentifying: g,
|
|
94
|
-
welcomeInput: v
|
|
95
|
-
}), m || g)
|
|
96
|
-
return;
|
|
97
|
-
if (a({ isIdentifying: !0 }), l) {
|
|
98
|
-
console.log("[@levo-so/insights] Debug mode enabled. Mocking session identification."), a({
|
|
99
|
-
isIdentified: !0,
|
|
100
|
-
isIdentifying: !1,
|
|
101
|
-
sessionId: "debug-session",
|
|
102
|
-
deviceId: "debug-device"
|
|
103
|
-
});
|
|
104
|
-
return;
|
|
105
|
-
}
|
|
106
|
-
const A = {
|
|
107
|
-
Accept: "application/json",
|
|
108
|
-
"Content-Type": "application/json",
|
|
109
|
-
...M({ sessionToken: _, deviceToken: b, mode: d })
|
|
110
|
-
};
|
|
111
|
-
r.fetch.url(u, !0).url("/v1/insights/event/welcome").options({
|
|
112
|
-
keepAlive: !0,
|
|
113
|
-
credentials: d === "proxy" ? "include" : "omit"
|
|
114
|
-
}).headers(A).post(v).json().then((t) => {
|
|
115
|
-
if (!s()) return;
|
|
116
|
-
const { isIdentified: C } = f();
|
|
117
|
-
if (!C) {
|
|
118
|
-
const n = { isIdentified: !0 };
|
|
119
|
-
if (t?.content?.data?.session && (n.sessionId = t?.content?.data?.session), t?.content?.data?.device && (n.deviceId = t?.content?.data?.device), d === "direct" && t?.content?.meta) {
|
|
120
|
-
const c = t.content.meta;
|
|
121
|
-
c.device_token && (n.deviceToken = c.device_token), c.session_token && (n.sessionToken = c.session_token);
|
|
122
|
-
}
|
|
123
|
-
a(n);
|
|
124
|
-
}
|
|
125
|
-
}).catch((t) => {
|
|
126
|
-
console.log("/welcome failed with error", S(t));
|
|
127
|
-
}).finally(() => {
|
|
128
|
-
a({ isIdentifying: !1 });
|
|
129
|
-
});
|
|
130
|
-
}
|
|
131
|
-
};
|
|
132
|
-
return j({
|
|
133
|
-
app: r.workspace || "",
|
|
134
|
-
debug: !!I,
|
|
135
|
-
plugins: [h]
|
|
136
|
-
});
|
|
137
|
-
};
|
|
138
|
-
export {
|
|
139
|
-
q as createAnalytics
|
|
140
|
-
};
|
package/dist/lib/insights.js
DELETED
|
@@ -1,141 +0,0 @@
|
|
|
1
|
-
import { setConfig as b, getConfig as h, updateConfigKey as _ } from "../stores/config.js";
|
|
2
|
-
import { queueEvent as T, flushEventQueue as C, getEventQueue as E, clearEventQueue as S, initSessionFlushListener as I } from "../stores/events.js";
|
|
3
|
-
import { updateSession as s, getSession as f, onSessionReady as B, $isContextReady as U } from "../stores/session.js";
|
|
4
|
-
import { initActivityTracker as z } from "../tracking/activity.js";
|
|
5
|
-
import { initBounceTracker as M } from "../tracking/bounce.js";
|
|
6
|
-
import { initClicksTracker as P } from "../tracking/clicks.js";
|
|
7
|
-
import { initClipboardTracker as x } from "../tracking/clipboard.js";
|
|
8
|
-
import { getCurrentTab as L, initCurrentTabTracker as Q } from "../tracking/currentTab.js";
|
|
9
|
-
import { initFormsTracker as q } from "../tracking/forms.js";
|
|
10
|
-
import { initPageTracker as A } from "../tracking/page.js";
|
|
11
|
-
import { initScrollBehaviorTracker as D } from "../tracking/scrollBehavior.js";
|
|
12
|
-
import { initTextSelectionTracker as F } from "../tracking/textSelection.js";
|
|
13
|
-
import { detectMode as N } from "../utils/detectMode.js";
|
|
14
|
-
import { getReferrer as O } from "../utils/getReferrer.js";
|
|
15
|
-
import { getUserProperties as K } from "../utils/getUserProperties.js";
|
|
16
|
-
import { createAnalytics as V } from "./analytics.js";
|
|
17
|
-
let t = null, n = !1;
|
|
18
|
-
const d = [], de = (c, m) => {
|
|
19
|
-
const { insightsUrl: l, debug: p = !1, site: v = null } = m;
|
|
20
|
-
b({
|
|
21
|
-
workspace: c.workspace,
|
|
22
|
-
debug: p,
|
|
23
|
-
site_id: v
|
|
24
|
-
}), typeof window < "u" && Promise.all([K(), O()]).then(([i, e]) => {
|
|
25
|
-
const r = e?.type ? {
|
|
26
|
-
type: e.type,
|
|
27
|
-
referrer: e.referrer,
|
|
28
|
-
data: e.data,
|
|
29
|
-
raw: e.raw ?? ""
|
|
30
|
-
} : null;
|
|
31
|
-
s({
|
|
32
|
-
identity: {
|
|
33
|
-
locale: i.locale,
|
|
34
|
-
timezone: i.timezone,
|
|
35
|
-
darkMode: i.dark_mode,
|
|
36
|
-
privateMode: i.private_mode,
|
|
37
|
-
referrer: r,
|
|
38
|
-
properties: i.properties
|
|
39
|
-
}
|
|
40
|
-
});
|
|
41
|
-
}).catch(() => {
|
|
42
|
-
s({
|
|
43
|
-
identity: {
|
|
44
|
-
locale: null,
|
|
45
|
-
timezone: null,
|
|
46
|
-
darkMode: null,
|
|
47
|
-
privateMode: null,
|
|
48
|
-
referrer: null,
|
|
49
|
-
properties: null
|
|
50
|
-
}
|
|
51
|
-
});
|
|
52
|
-
});
|
|
53
|
-
const g = async (i, e) => {
|
|
54
|
-
if (typeof window > "u")
|
|
55
|
-
return;
|
|
56
|
-
const { page_id: r } = h(), { allTabs: u } = f(), a = L(), o = u.length, k = {
|
|
57
|
-
event: i,
|
|
58
|
-
version: e?.version || 1,
|
|
59
|
-
properties: {
|
|
60
|
-
...e,
|
|
61
|
-
version: void 0,
|
|
62
|
-
resource: void 0,
|
|
63
|
-
identifier: void 0,
|
|
64
|
-
hostname: void 0,
|
|
65
|
-
pathname: void 0,
|
|
66
|
-
url: void 0,
|
|
67
|
-
page_title: void 0,
|
|
68
|
-
created_at: void 0
|
|
69
|
-
},
|
|
70
|
-
hostname: window.location.hostname,
|
|
71
|
-
pathname: window.location.pathname,
|
|
72
|
-
url: e?.url ?? window.location.href,
|
|
73
|
-
page_title: e?.page_title ?? document.title,
|
|
74
|
-
resource: e?.resource ?? "page",
|
|
75
|
-
identifier: e?.id ?? r ?? void 0,
|
|
76
|
-
created_at: e?.created_at ?? (/* @__PURE__ */ new Date()).toISOString(),
|
|
77
|
-
tab_id: a ?? "",
|
|
78
|
-
tab_count: o
|
|
79
|
-
};
|
|
80
|
-
T(k);
|
|
81
|
-
}, w = (i) => {
|
|
82
|
-
!t || !n || t.identify("", { withLock: !0 });
|
|
83
|
-
}, y = (i) => {
|
|
84
|
-
const { page_id: e } = h();
|
|
85
|
-
e !== i && _("page_id", i);
|
|
86
|
-
};
|
|
87
|
-
return {
|
|
88
|
-
init: (i = {}) => {
|
|
89
|
-
if (typeof window > "u")
|
|
90
|
-
throw new Error("[@levo-so/insights] init() should only be called on the client side.");
|
|
91
|
-
const { pageId: e } = i;
|
|
92
|
-
if (e && y(e), !n && !(c.NODE_ENV === "development" && !p)) {
|
|
93
|
-
if (!l) {
|
|
94
|
-
console.error(
|
|
95
|
-
"[@levo-so/insights] The utility could not be initialized due to missing insights endpoint."
|
|
96
|
-
);
|
|
97
|
-
return;
|
|
98
|
-
}
|
|
99
|
-
n = !0, B(() => {
|
|
100
|
-
if (!n) return;
|
|
101
|
-
const { insightsBaseUrl: r } = f();
|
|
102
|
-
r || N(m).then(({ mode: a, url: o }) => {
|
|
103
|
-
n && o && s({ mode: a, insightsBaseUrl: o });
|
|
104
|
-
}).catch(() => {
|
|
105
|
-
l && s({ mode: "proxy", insightsBaseUrl: l });
|
|
106
|
-
});
|
|
107
|
-
const u = U.subscribe((a) => {
|
|
108
|
-
if (!(!a || !n) && !t) {
|
|
109
|
-
const o = V(c, g, () => t === o);
|
|
110
|
-
t = o, f().insightsBaseUrl && t && (d.push(
|
|
111
|
-
I(),
|
|
112
|
-
z(t),
|
|
113
|
-
M(t),
|
|
114
|
-
P(t),
|
|
115
|
-
x(t),
|
|
116
|
-
Q(),
|
|
117
|
-
q(t),
|
|
118
|
-
A(t),
|
|
119
|
-
D(t),
|
|
120
|
-
F(t)
|
|
121
|
-
), w(), t.page({ resource: "page" }));
|
|
122
|
-
}
|
|
123
|
-
});
|
|
124
|
-
d.push(u);
|
|
125
|
-
});
|
|
126
|
-
}
|
|
127
|
-
},
|
|
128
|
-
destroy: () => {
|
|
129
|
-
n && (C(E()), S(), d.forEach((i) => {
|
|
130
|
-
i();
|
|
131
|
-
}), d.length = 0, t = null, n = !1);
|
|
132
|
-
},
|
|
133
|
-
track: g,
|
|
134
|
-
get instance() {
|
|
135
|
-
return t;
|
|
136
|
-
}
|
|
137
|
-
};
|
|
138
|
-
};
|
|
139
|
-
export {
|
|
140
|
-
de as createLevoInsights
|
|
141
|
-
};
|
package/dist/stores/config.js
DELETED
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
import { map as n } from "nanostores";
|
|
2
|
-
const t = n({
|
|
3
|
-
workspace: null,
|
|
4
|
-
page_id: null,
|
|
5
|
-
site_id: null,
|
|
6
|
-
debug: !1
|
|
7
|
-
}), s = () => t.get(), i = (e) => t.set({ ...s(), ...e }), l = (e, o) => t.setKey(e, o);
|
|
8
|
-
export {
|
|
9
|
-
t as $config,
|
|
10
|
-
s as getConfig,
|
|
11
|
-
i as setConfig,
|
|
12
|
-
l as updateConfigKey
|
|
13
|
-
};
|
package/dist/stores/events.js
DELETED
|
@@ -1,90 +0,0 @@
|
|
|
1
|
-
import { atom as l, computed as $ } from "nanostores";
|
|
2
|
-
import { getAuthHeaders as k } from "../utils/getAuthHeaders.js";
|
|
3
|
-
import { getConfig as h } from "./config.js";
|
|
4
|
-
import { getSession as v, $session as y } from "./session.js";
|
|
5
|
-
const A = 10, B = 2e3, p = 500, o = l([]), c = l(0), N = $(o, (e) => e.length ?? 0), i = l(null), O = () => {
|
|
6
|
-
let e = !1;
|
|
7
|
-
return y.subscribe((t) => {
|
|
8
|
-
if (t.isIdentified && !e) {
|
|
9
|
-
e = !0;
|
|
10
|
-
const s = o.get();
|
|
11
|
-
s.length > 0 && f(s);
|
|
12
|
-
}
|
|
13
|
-
});
|
|
14
|
-
}, _ = () => o.get(), P = () => N.get(), f = (e) => {
|
|
15
|
-
const { workspace: t, debug: s, site_id: r, page_id: a } = h(), { isIdentified: T, mode: u, sessionId: b, deviceId: w, sessionToken: C, deviceToken: I, insightsBaseUrl: g } = v();
|
|
16
|
-
if (e.length === 0 || !T || !g || !t)
|
|
17
|
-
return;
|
|
18
|
-
const d = e.map(
|
|
19
|
-
(n) => ({
|
|
20
|
-
// Default values from stores
|
|
21
|
-
workspace_id: t,
|
|
22
|
-
site_id: r ?? void 0,
|
|
23
|
-
session_id: b ?? void 0,
|
|
24
|
-
device_id: w ?? void 0,
|
|
25
|
-
identifier: a ?? void 0,
|
|
26
|
-
hostname: window.location.hostname,
|
|
27
|
-
pathname: window.location.pathname,
|
|
28
|
-
page_title: document.title,
|
|
29
|
-
url: window.location.href,
|
|
30
|
-
tab_id: "",
|
|
31
|
-
tab_count: 0,
|
|
32
|
-
// Event values override defaults (includes tab_id, tab_count captured at track time)
|
|
33
|
-
...n,
|
|
34
|
-
// Ensure required fields have values
|
|
35
|
-
event: n.event,
|
|
36
|
-
created_at: n.created_at,
|
|
37
|
-
resource: n.resource ?? "page",
|
|
38
|
-
properties: n.properties ?? {}
|
|
39
|
-
})
|
|
40
|
-
);
|
|
41
|
-
if (o.set([]), s) {
|
|
42
|
-
console.log("[@levo-so/insights] Debug mode enabled. Events batch:", d);
|
|
43
|
-
return;
|
|
44
|
-
}
|
|
45
|
-
const m = `${g}/v1/insights/event/bulk?workspace=${t}`, S = {
|
|
46
|
-
"Content-Type": "application/json",
|
|
47
|
-
...k({ deviceToken: I, sessionToken: C, mode: u })
|
|
48
|
-
};
|
|
49
|
-
u === "proxy" && navigator.sendBeacon && navigator.sendBeacon(m, JSON.stringify(d)) || fetch(m, {
|
|
50
|
-
method: "POST",
|
|
51
|
-
body: JSON.stringify(d),
|
|
52
|
-
headers: S,
|
|
53
|
-
keepalive: !0,
|
|
54
|
-
credentials: u === "proxy" ? "include" : "omit"
|
|
55
|
-
}).catch(() => {
|
|
56
|
-
});
|
|
57
|
-
}, Q = () => {
|
|
58
|
-
if (i.get()) return;
|
|
59
|
-
const e = setTimeout(() => {
|
|
60
|
-
f(_()), i.set(null);
|
|
61
|
-
}, B);
|
|
62
|
-
i.set(e);
|
|
63
|
-
}, E = () => {
|
|
64
|
-
const e = i.get();
|
|
65
|
-
e && (clearTimeout(e), i.set(null));
|
|
66
|
-
}, R = (e) => {
|
|
67
|
-
const { debug: t } = h(), s = c.get();
|
|
68
|
-
if (s >= p) {
|
|
69
|
-
t && console.warn(`[@levo-so/core] Event limit (${p}) reached for this page`);
|
|
70
|
-
return;
|
|
71
|
-
}
|
|
72
|
-
c.set(s + 1);
|
|
73
|
-
const r = o.get();
|
|
74
|
-
o.set([...r, e]);
|
|
75
|
-
const { isIdentified: a } = v();
|
|
76
|
-
P() >= A ? (E(), f(_())) : a && Q();
|
|
77
|
-
}, q = () => c.set(0), J = () => {
|
|
78
|
-
o.set([]), c.set(0), E();
|
|
79
|
-
};
|
|
80
|
-
export {
|
|
81
|
-
o as $eventQueue,
|
|
82
|
-
c as $lifetimePageCount,
|
|
83
|
-
N as $totalEventCount,
|
|
84
|
-
J as clearEventQueue,
|
|
85
|
-
f as flushEventQueue,
|
|
86
|
-
_ as getEventQueue,
|
|
87
|
-
O as initSessionFlushListener,
|
|
88
|
-
R as queueEvent,
|
|
89
|
-
q as resetRateLimit
|
|
90
|
-
};
|
package/dist/stores/session.js
DELETED
|
@@ -1,66 +0,0 @@
|
|
|
1
|
-
import { computed as u, atom as g } from "nanostores";
|
|
2
|
-
import { STORAGE_KEYS as i } from "../constants/storageKeys.js";
|
|
3
|
-
import { checkLocalStorageAvailable as y } from "../utils/checkLocalStorage.js";
|
|
4
|
-
const c = {
|
|
5
|
-
isIdentified: !1,
|
|
6
|
-
isIdentifying: !1,
|
|
7
|
-
sessionId: null,
|
|
8
|
-
deviceId: null,
|
|
9
|
-
deviceToken: null,
|
|
10
|
-
sessionToken: null,
|
|
11
|
-
allTabs: [],
|
|
12
|
-
mode: "proxy",
|
|
13
|
-
insightsBaseUrl: null,
|
|
14
|
-
identity: null
|
|
15
|
-
}, S = JSON.stringify, f = (e) => {
|
|
16
|
-
if (!e) return c;
|
|
17
|
-
try {
|
|
18
|
-
return JSON.parse(e);
|
|
19
|
-
} catch {
|
|
20
|
-
return c;
|
|
21
|
-
}
|
|
22
|
-
}, t = g(c), n = t.set;
|
|
23
|
-
let l = !1;
|
|
24
|
-
const d = [], a = () => {
|
|
25
|
-
l || (l = !0, d.forEach((e) => {
|
|
26
|
-
e();
|
|
27
|
-
}), d.length = 0);
|
|
28
|
-
}, I = (e) => {
|
|
29
|
-
l ? e() : d.push(e);
|
|
30
|
-
};
|
|
31
|
-
if (y()) {
|
|
32
|
-
const e = localStorage.getItem(i.session);
|
|
33
|
-
e && n(f(e)), a(), t.set = (s) => {
|
|
34
|
-
n(s);
|
|
35
|
-
try {
|
|
36
|
-
localStorage.setItem(i.session, S(s));
|
|
37
|
-
} catch {
|
|
38
|
-
}
|
|
39
|
-
}, window.addEventListener("storage", (s) => {
|
|
40
|
-
s.key === i.session && n(f(s.newValue));
|
|
41
|
-
});
|
|
42
|
-
} else if (typeof BroadcastChannel < "u") {
|
|
43
|
-
const e = new BroadcastChannel(i.session);
|
|
44
|
-
e.onmessage = (s) => {
|
|
45
|
-
const { type: r, value: o } = s.data;
|
|
46
|
-
r === "UPDATE" && o ? n(o) : r === "QUERY" ? l && e.postMessage({ type: "RESPONSE", value: t.get() }) : r === "RESPONSE" && o && (n(o), a());
|
|
47
|
-
}, t.set = (s) => {
|
|
48
|
-
n(s), e.postMessage({ type: "UPDATE", value: s });
|
|
49
|
-
}, e.postMessage({ type: "QUERY" }), setTimeout(() => {
|
|
50
|
-
a();
|
|
51
|
-
}, 150);
|
|
52
|
-
} else
|
|
53
|
-
a();
|
|
54
|
-
const p = () => t.get(), R = (e) => {
|
|
55
|
-
t.set({ ...p(), ...e });
|
|
56
|
-
}, T = u(
|
|
57
|
-
t,
|
|
58
|
-
(e) => e.insightsBaseUrl !== null && e.identity !== null
|
|
59
|
-
);
|
|
60
|
-
export {
|
|
61
|
-
T as $isContextReady,
|
|
62
|
-
t as $session,
|
|
63
|
-
p as getSession,
|
|
64
|
-
I as onSessionReady,
|
|
65
|
-
R as updateSession
|
|
66
|
-
};
|
|
@@ -1,33 +0,0 @@
|
|
|
1
|
-
import { onUserActivity as o } from "@analytics/activity-utils";
|
|
2
|
-
import { map as n } from "nanostores";
|
|
3
|
-
const s = n({
|
|
4
|
-
status: "active",
|
|
5
|
-
seconds: 0
|
|
6
|
-
}), T = (e) => {
|
|
7
|
-
if (typeof window > "u") return () => {
|
|
8
|
-
};
|
|
9
|
-
const i = o({
|
|
10
|
-
timeout: 6e4,
|
|
11
|
-
throttle: 1e3,
|
|
12
|
-
onIdle: (t) => {
|
|
13
|
-
s.set({ status: "idle", seconds: t });
|
|
14
|
-
},
|
|
15
|
-
onWakeUp: (t) => {
|
|
16
|
-
s.set({ status: "active", seconds: t });
|
|
17
|
-
}
|
|
18
|
-
}), c = s.listen((t) => {
|
|
19
|
-
t.seconds > 0 && (t.status === "idle" ? e.track("user.idle", {
|
|
20
|
-
seconds_active: t.seconds
|
|
21
|
-
}) : e.track("user.active", {
|
|
22
|
-
seconds_idle: t.seconds
|
|
23
|
-
}));
|
|
24
|
-
});
|
|
25
|
-
return () => {
|
|
26
|
-
c(), i.disable(), s.set({ status: "active", seconds: 0 });
|
|
27
|
-
};
|
|
28
|
-
}, v = () => s.get();
|
|
29
|
-
export {
|
|
30
|
-
s as $activity,
|
|
31
|
-
v as getActivityStatus,
|
|
32
|
-
T as initActivityTracker
|
|
33
|
-
};
|
package/dist/tracking/bounce.js
DELETED
|
@@ -1,90 +0,0 @@
|
|
|
1
|
-
import { getLevoError as u } from "@levo-so/core";
|
|
2
|
-
import { atom as y } from "nanostores";
|
|
3
|
-
import { $config as l } from "../stores/config.js";
|
|
4
|
-
import { flushEventQueue as g, getEventQueue as p } from "../stores/events.js";
|
|
5
|
-
import { getActivityStatus as w } from "./activity.js";
|
|
6
|
-
const n = y(
|
|
7
|
-
"active"
|
|
8
|
-
/* ACTIVE */
|
|
9
|
-
), b = () => typeof document > "u" ? "active" : document.visibilityState === "hidden" ? "hidden" : document.hasFocus() ? "active" : "passive", S = (v) => {
|
|
10
|
-
if (typeof window > "u") return () => {
|
|
11
|
-
};
|
|
12
|
-
let o = !1;
|
|
13
|
-
const r = (e) => {
|
|
14
|
-
if (o) return;
|
|
15
|
-
o = !0;
|
|
16
|
-
const i = w(), t = {};
|
|
17
|
-
i.seconds > 0 && (i.status === "idle" ? t.seconds_idle = i.seconds : t.seconds_active = i.seconds);
|
|
18
|
-
try {
|
|
19
|
-
v.track("page.bounce", {
|
|
20
|
-
resource: "page",
|
|
21
|
-
...t,
|
|
22
|
-
...e
|
|
23
|
-
}), g(p());
|
|
24
|
-
} catch (f) {
|
|
25
|
-
console.error("[insights] Failed to send bounce event", u(f));
|
|
26
|
-
}
|
|
27
|
-
}, a = () => {
|
|
28
|
-
const e = performance.getEntriesByType("navigation")?.[0];
|
|
29
|
-
let i = e?.type === "navigate";
|
|
30
|
-
if (!i)
|
|
31
|
-
try {
|
|
32
|
-
const t = document.activeElement;
|
|
33
|
-
t?.tagName === "A" && t.href && new URL(t.href).origin !== window.location.origin && (i = !0);
|
|
34
|
-
} catch (t) {
|
|
35
|
-
console.warn("[insights] Failed to parse link destination", u(t));
|
|
36
|
-
}
|
|
37
|
-
r({
|
|
38
|
-
is_navigating_away: i,
|
|
39
|
-
navigation_type: e?.type,
|
|
40
|
-
trigger: "beforeunload"
|
|
41
|
-
});
|
|
42
|
-
}, s = (e) => {
|
|
43
|
-
switch (e.type) {
|
|
44
|
-
case "pageshow":
|
|
45
|
-
case "resume":
|
|
46
|
-
case "blur":
|
|
47
|
-
case "focus":
|
|
48
|
-
case "visibilitychange":
|
|
49
|
-
n.set(b());
|
|
50
|
-
break;
|
|
51
|
-
case "freeze":
|
|
52
|
-
n.set(
|
|
53
|
-
"frozen"
|
|
54
|
-
/* FROZEN */
|
|
55
|
-
);
|
|
56
|
-
break;
|
|
57
|
-
case "pagehide":
|
|
58
|
-
n.set(
|
|
59
|
-
e.persisted ? "frozen" : "terminated"
|
|
60
|
-
/* TERMINATED */
|
|
61
|
-
);
|
|
62
|
-
break;
|
|
63
|
-
}
|
|
64
|
-
}, c = ["pageshow", "pagehide", "focus", "blur", "visibilitychange", "resume", "freeze"];
|
|
65
|
-
c.forEach((e) => {
|
|
66
|
-
window.addEventListener(e, s, { capture: !0 });
|
|
67
|
-
}), window.addEventListener("beforeunload", a);
|
|
68
|
-
const m = n.listen((e) => {
|
|
69
|
-
e === "frozen" || e === "terminated" ? r({
|
|
70
|
-
state: e,
|
|
71
|
-
trigger: "lifecycle"
|
|
72
|
-
}) : e === "hidden" && g(p());
|
|
73
|
-
});
|
|
74
|
-
let d = l.get().page_id;
|
|
75
|
-
const h = l.listen((e) => {
|
|
76
|
-
e.page_id !== d && (o = !1, d = e.page_id);
|
|
77
|
-
});
|
|
78
|
-
return () => {
|
|
79
|
-
c.forEach((e) => {
|
|
80
|
-
window.removeEventListener(e, s, { capture: !0 });
|
|
81
|
-
}), window.removeEventListener("beforeunload", a), m(), h(), o = !1, n.set(
|
|
82
|
-
"active"
|
|
83
|
-
/* ACTIVE */
|
|
84
|
-
);
|
|
85
|
-
};
|
|
86
|
-
};
|
|
87
|
-
export {
|
|
88
|
-
n as $pageLifecycle,
|
|
89
|
-
S as initBounceTracker
|
|
90
|
-
};
|
package/dist/tracking/clicks.js
DELETED
|
@@ -1,122 +0,0 @@
|
|
|
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
|
-
};
|