@levo-so/insights 0.1.82 → 0.1.85

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.
@@ -1,71 +0,0 @@
1
- import { ILevoClient } from '@levo-so/core';
2
- import { AnalyticsInstance } from 'analytics';
3
- import { AnalyticsEventType, ILevoAudience } from '../types/analytics';
4
- import { IInsightOptions } from '../types/options';
5
- /**
6
- * Creates the Levo Audience analytics module.
7
- *
8
- * This factory function creates a new audience module instance tied to
9
- * a specific Levo control instance and HTTP client. The module manages
10
- * all analytics tracking for the page.
11
- *
12
- * @param core - The Levo control instance containing workspace config
13
- * @param httpClient - HTTP client for making API requests
14
- * @returns The audience module with tracking methods
15
- *
16
- * @example
17
- * ```typescript
18
- * const audience = createLevoAudienceModule(levoControl, httpClient);
19
- *
20
- * // Initialize on page load
21
- * await audience.initiate({ id: 'page-123' });
22
- *
23
- * // Track custom events
24
- * audience.track('button.click', { buttonId: 'cta-signup' });
25
- *
26
- * // Cleanup on unmount (optional, for SPAs)
27
- * audience.destroy();
28
- * ```
29
- */
30
- export declare const createLevoInsights: (client: ILevoClient, options: IInsightOptions) => {
31
- /** Get the underlying analytics instance (read-only) */
32
- readonly instance: AnalyticsInstance | null;
33
- /** Check if session has been established (read-only) */
34
- readonly is_identified: boolean;
35
- /** Storage keys used by the module */
36
- storage_keys: {
37
- readonly identify: "lock:lv_aud_identify";
38
- readonly open_tabs: "lv_insights_ot";
39
- readonly current_tab: "lv_insights_ct";
40
- readonly all_tabs: "lv_insights_at";
41
- readonly device_token: "lv_aud_device";
42
- readonly session_token: "lv_aud_session";
43
- readonly mode: "lv_aud_mode";
44
- readonly session: "lv_insights_session";
45
- };
46
- /** Initialize the module for a page */
47
- initiate: (properties: ILevoAudience.Properties) => Promise<any>;
48
- /** Identify/establish session */
49
- identify: (options?: {
50
- withLock?: boolean;
51
- }) => Promise<void>;
52
- /** Track a custom event */
53
- track: <T extends ILevoAudience.Properties>(event: AnalyticsEventType, properties: T & ILevoAudience.Properties) => Promise<any>;
54
- /** Track a bounce event */
55
- bounce: (properties: ILevoAudience.Properties) => Promise<void>;
56
- /** Cleanup the module */
57
- destroy: () => void;
58
- };
59
- /**
60
- * Type representing the audience module instance.
61
- * Use this when you need to type a variable holding the module.
62
- *
63
- * @example
64
- * ```typescript
65
- * let audience: ILevoAudienceModule;
66
- * audience = createLevoAudienceModule(core, httpClient);
67
- * ```
68
- */
69
- export type ILevoInsights = ReturnType<typeof createLevoInsights>;
70
- export * from '../types/analytics';
71
- export * from '../types/options';
@@ -1,583 +0,0 @@
1
- import { getLevoError as z } from "@levo-so/core";
2
- import { map as B, computed as J, atom as b } from "nanostores";
3
- import { onUserActivity as de } from "@analytics/activity-utils";
4
- import { debounce as K } from "lodash-es";
5
- const x = B({
6
- workspace: null,
7
- page_id: null,
8
- site_id: null,
9
- debug: !1
10
- }), U = () => x.get(), ze = (e) => x.set({ ...U(), ...e }), Ve = (e, t) => x.setKey(e, t), fe = ({
11
- deviceToken: e,
12
- sessionToken: t,
13
- mode: n
14
- }) => {
15
- const i = {};
16
- return n === "direct" && (e && (i["Levo-Audience-Device"] = e), t && (i["Levo-Audience-Session"] = t)), i;
17
- }, v = {
18
- /** Legacy: Lock key for identify operation (no longer used internally) */
19
- identify: "lock:lv_aud_identify",
20
- /** Key for tracking open tab count */
21
- open_tabs: "lv_insights_ot",
22
- /** Key for current tab ID (sessionStorage) */
23
- current_tab: "lv_insights_ct",
24
- /** Key for all tabs registry */
25
- all_tabs: "lv_insights_at",
26
- /** Device JWT for direct mode (1yr expiry, rotated on /welcome, analytics-only scope) */
27
- device_token: "lv_aud_device",
28
- /** Session JWT for direct mode (1yr expiry, rotated on /welcome, analytics-only scope) */
29
- session_token: "lv_aud_session",
30
- /** Cached insights mode ('proxy' | 'direct') */
31
- mode: "lv_aud_mode",
32
- /** Key to store session data **/
33
- session: "lv_insights_session"
34
- }, ge = () => {
35
- if (typeof window > "u" || !("localStorage" in window))
36
- return !1;
37
- try {
38
- const e = "__levo_test__";
39
- return window.localStorage.setItem(e, "test"), window.localStorage.removeItem(e), !0;
40
- } catch {
41
- return !1;
42
- }
43
- }, M = {
44
- isIdentified: !1,
45
- isIdentifying: !1,
46
- sessionId: null,
47
- deviceId: null,
48
- deviceToken: null,
49
- sessionToken: null,
50
- allTabs: [],
51
- mode: "proxy",
52
- insightsBaseUrl: null,
53
- identity: null
54
- }, pe = JSON.stringify, V = (e) => {
55
- if (!e) return M;
56
- try {
57
- return JSON.parse(e);
58
- } catch {
59
- return M;
60
- }
61
- }, p = b(M), y = p.set;
62
- let N = !1;
63
- const O = [], L = () => {
64
- N || (N = !0, O.forEach((e) => {
65
- e();
66
- }), O.length = 0);
67
- }, Qe = (e) => {
68
- N ? e() : O.push(e);
69
- };
70
- if (ge()) {
71
- const e = localStorage.getItem(v.session);
72
- e && y(V(e)), L(), p.set = (t) => {
73
- y(t);
74
- try {
75
- localStorage.setItem(v.session, pe(t));
76
- } catch {
77
- }
78
- }, window.addEventListener("storage", (t) => {
79
- t.key === v.session && y(V(t.newValue));
80
- });
81
- } else if (typeof BroadcastChannel < "u") {
82
- const e = new BroadcastChannel(v.session);
83
- e.onmessage = (t) => {
84
- const { type: n, value: i } = t.data;
85
- n === "UPDATE" && i ? y(i) : n === "QUERY" ? N && e.postMessage({ type: "RESPONSE", value: p.get() }) : n === "RESPONSE" && i && (y(i), L());
86
- }, p.set = (t) => {
87
- y(t), e.postMessage({ type: "UPDATE", value: t });
88
- }, e.postMessage({ type: "QUERY" }), setTimeout(() => {
89
- L();
90
- }, 150);
91
- } else
92
- L();
93
- const H = () => p.get(), Q = (e) => {
94
- p.set({ ...H(), ...e });
95
- }, We = J(
96
- p,
97
- (e) => e.insightsBaseUrl !== null && e.identity !== null
98
- ), me = 10, he = 2e3, W = 500, h = b([]), I = b(0), be = J(h, (e) => e.length ?? 0), T = b(null), Je = () => {
99
- let e = !1;
100
- return p.subscribe((t) => {
101
- if (t.isIdentified && !e) {
102
- e = !0;
103
- const n = h.get();
104
- n.length > 0 && C(n);
105
- }
106
- });
107
- }, A = () => h.get(), ye = () => be.get(), C = (e) => {
108
- const { workspace: t, debug: n, site_id: i, page_id: o } = U(), { isIdentified: r, mode: c, sessionId: u, deviceId: a, sessionToken: s, deviceToken: d, insightsBaseUrl: f } = H();
109
- if (e.length === 0 || !r || !f || !t)
110
- return;
111
- const g = e.map(
112
- (m) => ({
113
- // Default values from stores
114
- workspace_id: t,
115
- site_id: i ?? void 0,
116
- session_id: u ?? void 0,
117
- device_id: a ?? void 0,
118
- identifier: o ?? void 0,
119
- hostname: window.location.hostname,
120
- pathname: window.location.pathname,
121
- page_title: document.title,
122
- url: window.location.href,
123
- tab_id: "",
124
- tab_count: 0,
125
- // Event values override defaults (includes tab_id, tab_count captured at track time)
126
- ...m,
127
- // Ensure required fields have values
128
- event: m.event,
129
- created_at: m.created_at,
130
- resource: m.resource ?? "page",
131
- properties: m.properties ?? {}
132
- })
133
- );
134
- if (h.set([]), n) {
135
- console.log("[@levo-so/insights] Debug mode enabled. Events batch:", g);
136
- return;
137
- }
138
- const k = `${f}/v1/insights/event/bulk?workspace=${t}`, E = {
139
- "Content-Type": "application/json",
140
- ...fe({ deviceToken: d, sessionToken: s, mode: c })
141
- };
142
- c === "proxy" && navigator.sendBeacon && navigator.sendBeacon(k, JSON.stringify(g)) || fetch(k, {
143
- method: "POST",
144
- body: JSON.stringify(g),
145
- headers: E,
146
- keepalive: !0,
147
- credentials: c === "proxy" ? "include" : "omit"
148
- }).catch(() => {
149
- });
150
- }, ve = () => {
151
- if (T.get()) return;
152
- const e = setTimeout(() => {
153
- C(A()), T.set(null);
154
- }, he);
155
- T.set(e);
156
- }, G = () => {
157
- const e = T.get();
158
- e && (clearTimeout(e), T.set(null));
159
- }, Ke = (e) => {
160
- const { debug: t } = U(), n = I.get();
161
- if (n >= W) {
162
- t && console.warn(`[@levo-so/core] Event limit (${W}) reached for this page`);
163
- return;
164
- }
165
- I.set(n + 1);
166
- const i = h.get();
167
- h.set([...i, e]);
168
- const { isIdentified: o } = H();
169
- ye() >= me ? (G(), C(A())) : o && ve();
170
- }, Ge = () => I.set(0), Xe = () => {
171
- h.set([]), I.set(0), G();
172
- }, _ = B({
173
- status: "active",
174
- seconds: 0
175
- }), Ze = (e) => {
176
- if (typeof window > "u") return () => {
177
- };
178
- const i = de({
179
- timeout: 6e4,
180
- throttle: 1e3,
181
- onIdle: (r) => {
182
- _.set({ status: "idle", seconds: r });
183
- },
184
- onWakeUp: (r) => {
185
- _.set({ status: "active", seconds: r });
186
- }
187
- }), o = _.listen((r) => {
188
- r.seconds > 0 && (r.status === "idle" ? e.track("user.idle", {
189
- seconds_active: r.seconds
190
- }) : e.track("user.active", {
191
- seconds_idle: r.seconds
192
- }));
193
- });
194
- return () => {
195
- o(), i.disable(), _.set({ status: "active", seconds: 0 });
196
- };
197
- }, we = () => _.get(), S = b(
198
- "active"
199
- /* ACTIVE */
200
- ), Ee = () => typeof document > "u" ? "active" : document.visibilityState === "hidden" ? "hidden" : document.hasFocus() ? "active" : "passive", et = (e) => {
201
- if (typeof window > "u") return () => {
202
- };
203
- let t = !1;
204
- const n = (s) => {
205
- if (t) return;
206
- t = !0;
207
- const d = we(), f = {};
208
- d.seconds > 0 && (d.status === "idle" ? f.seconds_idle = d.seconds : f.seconds_active = d.seconds);
209
- try {
210
- e.track("page.bounce", {
211
- resource: "page",
212
- ...f,
213
- ...s
214
- }), C(A());
215
- } catch (g) {
216
- console.error("[insights] Failed to send bounce event", z(g));
217
- }
218
- }, i = () => {
219
- const s = performance.getEntriesByType("navigation")?.[0];
220
- let d = s?.type === "navigate";
221
- if (!d)
222
- try {
223
- const f = document.activeElement;
224
- f?.tagName === "A" && f.href && new URL(f.href).origin !== window.location.origin && (d = !0);
225
- } catch (f) {
226
- console.warn("[insights] Failed to parse link destination", z(f));
227
- }
228
- n({
229
- is_navigating_away: d,
230
- navigation_type: s?.type,
231
- trigger: "beforeunload"
232
- });
233
- }, o = (s) => {
234
- switch (s.type) {
235
- case "pageshow":
236
- case "resume":
237
- case "blur":
238
- case "focus":
239
- case "visibilitychange":
240
- S.set(Ee());
241
- break;
242
- case "freeze":
243
- S.set(
244
- "frozen"
245
- /* FROZEN */
246
- );
247
- break;
248
- case "pagehide":
249
- S.set(
250
- s.persisted ? "frozen" : "terminated"
251
- /* TERMINATED */
252
- );
253
- break;
254
- }
255
- }, r = ["pageshow", "pagehide", "focus", "blur", "visibilitychange", "resume", "freeze"];
256
- r.forEach((s) => {
257
- window.addEventListener(s, o, { capture: !0 });
258
- }), window.addEventListener("beforeunload", i);
259
- const c = S.listen((s) => {
260
- s === "frozen" || s === "terminated" ? n({
261
- state: s,
262
- trigger: "lifecycle"
263
- }) : s === "hidden" && C(A());
264
- });
265
- let u = x.get().page_id;
266
- const a = x.listen((s) => {
267
- s.page_id !== u && (t = !1, u = s.page_id);
268
- });
269
- return () => {
270
- r.forEach((s) => {
271
- window.removeEventListener(s, o, { capture: !0 });
272
- }), window.removeEventListener("beforeunload", i), c(), a(), t = !1, S.set(
273
- "active"
274
- /* ACTIVE */
275
- );
276
- };
277
- }, R = (e) => Object.prototype.toString.call(e) == "[object String]", Se = (e, t) => e.indexOf(t) !== -1, w = (e) => e.replace(/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g, ""), X = (e) => e === void 0, _e = (e) => e === null, Z = (e) => X(e) || _e(e), ee = (e) => !!e && e?.nodeType === 3;
278
- function Te(e) {
279
- return !!e && e?.nodeType === 1;
280
- }
281
- function xe(e, t) {
282
- return !!e && !!e?.tagName && e?.tagName.toLowerCase() === t.toLowerCase();
283
- }
284
- function Ce(e) {
285
- return e ? w(e).split(/\s+/) : [];
286
- }
287
- function ke(e) {
288
- let t = "";
289
- switch (typeof e?.className) {
290
- case "string":
291
- t = e?.className;
292
- break;
293
- // TODO: when is this ever used?
294
- case "object":
295
- t = (e?.className && "baseVal" in e.className ? (e?.className).baseVal : null) || e?.getAttribute("class") || "";
296
- break;
297
- default:
298
- t = "";
299
- }
300
- return Ce(t);
301
- }
302
- const l = (e, t = 255) => Z(e) ? "" : w(e).split(/(\s+)/).filter((n) => Y(n)).join("").replace(/[\r\n]/g, " ").replace(/[ ]+/g, " ").substring(0, t), te = ["span", "strong", "em", "i", "b", "mark", "code", "small", "sub", "sup", "label"], F = (e) => {
303
- let t = "";
304
- if (Ae(e) && e?.childNodes && e?.childNodes.length) {
305
- for (const n of e.childNodes)
306
- ee(n) && n.textContent && (t += l(n.textContent) ?? "");
307
- if (!w(t)) {
308
- const n = e.querySelectorAll(te.join(", "));
309
- for (const i of n) {
310
- const o = i.textContent;
311
- o && (t += `${l(o)} `);
312
- }
313
- }
314
- if (!w(t) && e instanceof HTMLElement) {
315
- const n = e.innerText;
316
- n && (t = l(n.substring(0, 500)));
317
- }
318
- }
319
- return w(t);
320
- }, Le = (e) => X(e.target) ? e?.srcElement || null : e?.target?.shadowRoot ? e?.composedPath()?.[0] || null : e?.target || null, Ne = (e, t) => {
321
- if (!window || !e || xe(e, "html") || !Te(e))
322
- return !1;
323
- const n = window.getComputedStyle(e);
324
- if (n && n.getPropertyValue("cursor") === "pointer" && t.type === "click")
325
- return !0;
326
- switch (e?.tagName.toLowerCase()) {
327
- case "html":
328
- return !1;
329
- case "form":
330
- return t.type === "submit";
331
- case "input":
332
- case "select":
333
- case "textarea":
334
- return ["change", "click"].includes(t.type);
335
- default:
336
- return t.type === "click";
337
- }
338
- }, Ie = /* @__PURE__ */ new Set([
339
- "password",
340
- "passwd",
341
- "pwd",
342
- "creditcard",
343
- "cardnumber",
344
- "ccnum",
345
- "ccnumber",
346
- "cvv",
347
- "cvc",
348
- "csc",
349
- "securitycode",
350
- "ssn",
351
- "socialsecurity",
352
- "routingnumber",
353
- "accountnumber",
354
- "bankaccount",
355
- "secretkey",
356
- "apikey",
357
- "accesstoken"
358
- ]);
359
- function Ae(e) {
360
- if (Se(ke(e), "ph-include"))
361
- return !0;
362
- const t = e.type || "";
363
- if (R(t))
364
- switch (t.toLowerCase()) {
365
- case "hidden":
366
- return !1;
367
- case "password":
368
- return !1;
369
- }
370
- const n = e.name || e?.id || "";
371
- if (R(n)) {
372
- const i = n.toLowerCase().replace(/[^a-z]/g, "");
373
- if (Ie.has(i))
374
- return !1;
375
- }
376
- return !0;
377
- }
378
- const ne = "(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})", Re = new RegExp(`^(?:${ne})$`), $e = new RegExp(ne), se = "\\d{3}-?\\d{2}-?\\d{4}", De = new RegExp(`^(${se})$`), Me = new RegExp(`(${se})`), Y = (e, t = !0) => !(Z(e) || R(e) && (e = w(e), (t ? Re : $e).test((e || "").replace(/[- ]/g, "")) || (t ? De : Me).test(e))), Oe = (e) => R(e) ? e.substring(0, 10) === "_ngcontent" || e.substring(0, 7) === "_nghost" : !1, Pe = (e) => {
379
- let t = F(e);
380
- return t = `${t} ${ie(e)}`.trim(), Y(t) ? t : "";
381
- };
382
- function ie(e) {
383
- let t = "";
384
- if (e?.childNodes.length)
385
- for (const n of e.childNodes) {
386
- const i = n.tagName?.toLowerCase();
387
- if (n && i && te.includes(i))
388
- try {
389
- const o = F(n);
390
- t = `${t} ${o}`.trim(), n?.childNodes.length && (t = `${t} ${ie(n)}`.trim());
391
- } catch {
392
- }
393
- }
394
- return t;
395
- }
396
- const Be = (e) => {
397
- const t = e.tagName?.toLowerCase(), n = t === "a" || t === "button" ? Pe(e) : F(e);
398
- if (n) return { text: n, source: "text" };
399
- const i = e.getAttribute("aria-label");
400
- if (i) return { text: l(i), source: "aria-label" };
401
- const o = e.getAttribute("title");
402
- if (o) return { text: l(o), source: "title" };
403
- const r = e.getAttribute("data-track-label");
404
- if (r) return { text: l(r), source: "data-track-label" };
405
- const c = e.querySelector("img[alt], svg[aria-label]");
406
- if (c) {
407
- const a = c.getAttribute("alt") || c.getAttribute("aria-label");
408
- if (a) return { text: l(a), source: "alt" };
409
- }
410
- const u = e.getAttribute("placeholder");
411
- if (u) return { text: l(u), source: "placeholder" };
412
- if (e instanceof HTMLElement && e.innerText) {
413
- const a = e.innerText.substring(0, 500);
414
- if (a.trim())
415
- return { text: l(a), source: "innerText" };
416
- }
417
- return { text: "", source: "none" };
418
- }, Ue = ["input", "textarea", "select"], He = (e) => {
419
- const t = e?.tagName?.toLowerCase(), n = {
420
- element: t
421
- }, i = Be(e);
422
- n.text = i.text, n.text_source = i.source;
423
- const o = e.getAttribute("aria-label");
424
- o && (n.aria_label = l(o));
425
- const r = e.getAttribute("role");
426
- r && (n.role = r);
427
- const c = {};
428
- for (const a of e.attributes)
429
- (a.name.startsWith("data-track-") || a.name.startsWith("data-analytics-")) && (c[a.name] = l(a.value));
430
- Object.keys(c).length && (n.tracking_data = c);
431
- const u = Array.from(e.attributes).reduce(
432
- (a, s) => {
433
- if (Y(s.value) && !Oe(s.name)) {
434
- if (s.name === "class" || s.name.startsWith("data-track-") || s.name.startsWith("data-analytics-"))
435
- return a;
436
- a[s.name] = typeof s?.value == "string" ? l(s.value) : s.value;
437
- }
438
- return a;
439
- },
440
- {}
441
- );
442
- if (n.attributes = u, Ue.includes(t) || e?.getAttribute("contenteditable") === "true") {
443
- let a;
444
- e.matches('input[type="checkbox"], input[type="radio"]') ? a = e.checked : e.matches("input, select, textarea") && !e.matches('input[type="password"]') && (a = e.value), a !== void 0 && (n.value = typeof a == "string" || a === null ? l(a, 1024) : a);
445
- let s = "";
446
- n?.attributes.id && (s = l(
447
- document.querySelector(`label[for="${n?.attributes.id}"]`)?.textContent?.trim() || ""
448
- ));
449
- const d = e.closest("label");
450
- s || (s = l(d?.textContent?.trim() || "")), s && (n.label = s);
451
- }
452
- return n;
453
- }, tt = (e, t) => {
454
- let n = Le(e);
455
- ee(n) && (n = n.parentNode || null);
456
- const i = ["copy", "cut"].includes(t);
457
- if (n && (i || Ne(n, e))) {
458
- const o = He(n);
459
- if (i) {
460
- const r = l(window?.getSelection()?.toString()), c = e?.type || "clipboard";
461
- o.copy_text = r ?? "", o.copy_type = c;
462
- }
463
- return o;
464
- }
465
- return null;
466
- }, P = b(null), nt = (e) => {
467
- if (typeof window > "u") return () => {
468
- };
469
- let t = sessionStorage.getItem(v.current_tab);
470
- const { allTabs: n } = p.get();
471
- t && n.includes(t) && (t = null), t || (t = `${Date.now()}-${Math.random().toString(36).substring(2, 11)}`, sessionStorage.setItem(v.current_tab, t));
472
- const i = t;
473
- P.set(i), n.includes(i) || Q({ allTabs: [...n, i] });
474
- const o = () => {
475
- if (!i) return;
476
- const { allTabs: r } = p.get();
477
- if (r.includes(i)) {
478
- const c = r.filter((u) => u !== i);
479
- Q({ allTabs: c });
480
- }
481
- };
482
- return window.addEventListener("beforeunload", o), () => {
483
- window.removeEventListener("beforeunload", o), o(), P.set(null);
484
- };
485
- }, st = () => P.get(), $ = B({
486
- depth: 0,
487
- milestone: 0,
488
- speedCategory: "read",
489
- direction: "down"
490
- }), it = (e) => {
491
- if (typeof window > "u") return () => {
492
- };
493
- let t = {
494
- // Use -1 to ensure first milestone (even 0) is tracked
495
- prevScrollY: 0,
496
- prevTime: Date.now()
497
- };
498
- const n = 5, i = 300, o = 250, r = () => {
499
- const s = window.scrollY, d = document.documentElement.scrollHeight, f = window.innerHeight, g = d - f;
500
- if (g <= 0) return;
501
- const k = Math.round(s / g * 100), E = Math.max(0, Math.min(100, k)), m = Math.floor(E / n) * n, { prevScrollY: oe, prevTime: re } = t, j = Date.now(), q = (j - re) / 1e3, ae = Math.abs(s - oe), ce = q > 0 ? ae / q : 0, le = E > t.prevScrollY / g * 100 ? "down" : "up", ue = ce > i ? "scan" : "read";
502
- $.set({
503
- depth: E,
504
- milestone: m,
505
- speedCategory: ue,
506
- direction: le
507
- }), t = {
508
- prevMilestone: m,
509
- prevScrollY: s,
510
- prevTime: j
511
- };
512
- }, c = K(r, o);
513
- window.addEventListener("scroll", c);
514
- let u = 0;
515
- const a = $.listen((s) => {
516
- s.milestone !== u && (u = s.milestone, e.track("page.scroll", {
517
- depth: s.milestone,
518
- speed_category: s.speedCategory,
519
- direction: s.direction
520
- }));
521
- });
522
- return typeof window.requestIdleCallback == "function" ? window.requestIdleCallback(() => r()) : setTimeout(r, 0), () => {
523
- window.removeEventListener("scroll", c), c.cancel(), a(), $.set({
524
- depth: 0,
525
- milestone: 0,
526
- speedCategory: "read",
527
- direction: "down"
528
- });
529
- };
530
- }, D = b(null), ot = (e) => {
531
- if (typeof window > "u") return () => {
532
- };
533
- const n = K(() => {
534
- const o = window.getSelection();
535
- if (o && o.rangeCount > 0) {
536
- const r = o.toString().trim();
537
- r && D.set(r);
538
- }
539
- }, 1e3);
540
- document.addEventListener("selectionchange", n);
541
- const i = D.listen((o) => {
542
- o && e.track("page.selection", {
543
- text: l(o)
544
- });
545
- });
546
- return () => {
547
- document.removeEventListener("selectionchange", n), n.cancel(), i(), D.set(null);
548
- };
549
- };
550
- export {
551
- x as $,
552
- Ze as A,
553
- et as B,
554
- nt as C,
555
- it as D,
556
- ot as E,
557
- h as a,
558
- I as b,
559
- be as c,
560
- We as d,
561
- p as e,
562
- _ as f,
563
- S as g,
564
- P as h,
565
- $ as i,
566
- D as j,
567
- He as k,
568
- tt as l,
569
- U as m,
570
- H as n,
571
- st as o,
572
- fe as p,
573
- Ke as q,
574
- Ge as r,
575
- ze as s,
576
- Ve as t,
577
- Q as u,
578
- Qe as v,
579
- C as w,
580
- A as x,
581
- Xe as y,
582
- Je as z
583
- };