@levo-so/insights 0.3.10 → 0.3.12

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.
@@ -0,0 +1,948 @@
1
+ import { atom as e, computed as t, map as n } from "nanostores";
2
+ import { AnalyticsEvents as r, getLevoError as i } from "@levo-so/core";
3
+ import { Snowflake as a } from "@theinternetfolks/snowflake";
4
+ import { onUserActivity as o } from "@analytics/activity-utils";
5
+ import { debounce as s } from "lodash-es";
6
+ //#region src/stores/config.ts
7
+ var c = n({
8
+ workspace: null,
9
+ page_id: null,
10
+ site_id: null,
11
+ debug: !1,
12
+ insightsUrl: null
13
+ }), l = () => c.get(), u = (e) => c.set({
14
+ ...l(),
15
+ ...e
16
+ }), d = (e, t) => c.setKey(e, t), f = {
17
+ open_tabs: "lv_insights_ot",
18
+ current_tab: "lv_insights_ct",
19
+ session: "lv_insights_session",
20
+ attribution: "lv_insights_attr",
21
+ identity: "lv_insights_identity"
22
+ }, p = {
23
+ client_device: "id_i_cd",
24
+ client_session: "id_i_cs"
25
+ }, m = () => {
26
+ if (typeof window > "u" || !("localStorage" in window)) return !1;
27
+ try {
28
+ let e = "__levo_test__";
29
+ return window.localStorage.setItem(e, "test"), window.localStorage.removeItem(e), !0;
30
+ } catch {
31
+ return !1;
32
+ }
33
+ }, h = (e) => {
34
+ if (typeof document > "u") return null;
35
+ try {
36
+ let t = `${encodeURIComponent(e)}=`, n = document.cookie.split("; ").find((e) => e.startsWith(t));
37
+ if (!n) return null;
38
+ let r = decodeURIComponent(n.slice(t.length));
39
+ return r.length > 0 ? r : null;
40
+ } catch {
41
+ return null;
42
+ }
43
+ }, g = (e, t, n) => {
44
+ if (!(typeof document > "u")) try {
45
+ let r = window.location.protocol === "https:" ? "; Secure" : "";
46
+ document.cookie = `${encodeURIComponent(e)}=${encodeURIComponent(t)}; Max-Age=${n}; Path=/; SameSite=Lax${r}`;
47
+ } catch {}
48
+ }, _ = {
49
+ locale: 20,
50
+ raw: 2048,
51
+ referrerDomain: 255,
52
+ referrerType: 50,
53
+ referrerUrl: 2048,
54
+ timezone: 100
55
+ }, v = {
56
+ identifier: 50,
57
+ pageTitle: 500,
58
+ pathname: 2048,
59
+ resource: 1e3,
60
+ tabCount: 1e3,
61
+ tabId: 100,
62
+ version: 1e3
63
+ }, ee = ["id", "identifier"], te = 1e3, ne = /^[a-zA-Z0-9_-]+$/, re = /^[a-zA-Z0-9][a-zA-Z0-9.-]*[a-zA-Z0-9]$|^[a-zA-Z0-9]$/, ie = (e) => typeof e == "string" && e.length <= _.referrerDomain && re.test(e), ae = /^[A-Z0-9]{8}$/, y = (e, t) => {
64
+ if (!(typeof e != "string" || e.length === 0)) return e.length > t ? e.slice(0, t) : e;
65
+ }, b = (e, t) => {
66
+ if (typeof e != "string") return;
67
+ let n = e.replace(/\0/g, "");
68
+ if (n.length !== 0) return n.length > t ? n.slice(0, t) : n;
69
+ }, x = (e) => {
70
+ if (typeof e != "string" || e.length === 0 || e.length > _.raw) return !1;
71
+ try {
72
+ let t = new URL(e).protocol.toLowerCase();
73
+ return ![
74
+ "javascript:",
75
+ "data:",
76
+ "vbscript:"
77
+ ].includes(t);
78
+ } catch {
79
+ return !1;
80
+ }
81
+ }, oe = (e) => {
82
+ if (!e) return;
83
+ let t = { ...e }, n = { ...e.referrer }, r = (e, t, n) => {
84
+ typeof e[t] == "string" && (e[t] = y(e[t], n) ?? "");
85
+ };
86
+ return r(t, "type", _.referrerType), r(t, "raw", _.raw), r(n, "url", _.referrerUrl), r(n, "domain", _.referrerDomain), typeof n.hostname == "string" && n.hostname && !ie(n.hostname) && (n.hostname = ""), t.referrer = n, t;
87
+ }, se = (e) => ({
88
+ ...x(e.landingUrl) ? { url: e.landingUrl } : {},
89
+ created_at: e.created_at,
90
+ dark_mode: e.darkMode ?? void 0,
91
+ locale: y(e.locale, _.locale),
92
+ properties: e.properties ?? void 0,
93
+ referrer: oe(e.referrer),
94
+ timezone: y(e.timezone, _.timezone)
95
+ }), ce = (e) => {
96
+ if (typeof e == "string" || typeof e != "object" || !e || Array.isArray(e)) return;
97
+ let t = { ...e };
98
+ for (let e of ee) {
99
+ let n = t[e];
100
+ if (n === void 0) continue;
101
+ let r = b(typeof n == "string" ? n : typeof n == "number" || typeof n == "boolean" ? String(n) : void 0, te);
102
+ r === void 0 ? delete t[e] : t[e] = r;
103
+ }
104
+ return t;
105
+ }, le = (e) => ({
106
+ ...e,
107
+ version: typeof e.version == "number" && Number.isInteger(e.version) && e.version >= 0 && e.version <= v.version ? e.version : 1,
108
+ tab_count: typeof e.tab_count == "number" && Number.isFinite(e.tab_count) && e.tab_count >= 0 ? Math.min(Math.trunc(e.tab_count), v.tabCount) : 0,
109
+ identifier: typeof e.identifier == "string" && e.identifier.length <= v.identifier && ne.test(e.identifier) ? e.identifier : void 0,
110
+ url: x(e.url) ? e.url : void 0,
111
+ hostname: ie(e.hostname) ? e.hostname : void 0,
112
+ created_at: typeof e.created_at == "string" ? e.created_at : (/* @__PURE__ */ new Date()).toISOString(),
113
+ properties: ce(e.properties),
114
+ pathname: b(e.pathname, v.pathname),
115
+ page_title: b(e.page_title, v.pageTitle),
116
+ resource: b(e.resource, v.resource),
117
+ tab_id: b(e.tab_id, v.tabId) ?? ""
118
+ }), S = {
119
+ deviceToken: null,
120
+ endpoint: { status: "none" },
121
+ identity: null
122
+ }, ue = JSON.stringify, de = (e) => {
123
+ if (!e) return S;
124
+ try {
125
+ let t = JSON.parse(e), n = {};
126
+ for (let e of Object.keys(S)) t[e] !== void 0 && (n[e] = t[e]);
127
+ return {
128
+ ...S,
129
+ ...n
130
+ };
131
+ } catch {
132
+ return S;
133
+ }
134
+ }, C = e(S), fe = C.set, w = e(!1), pe = () => {
135
+ w.get() || w.set(!0);
136
+ };
137
+ if (m()) {
138
+ let e = localStorage.getItem(f.session);
139
+ fe({
140
+ ...S,
141
+ ...de(e)
142
+ }), pe(), C.set = (e) => {
143
+ fe(e);
144
+ try {
145
+ localStorage.setItem(f.session, ue(e));
146
+ } catch {}
147
+ };
148
+ } else pe();
149
+ var T = () => C.get(), me = (e) => {
150
+ C.set({
151
+ ...T(),
152
+ ...e
153
+ });
154
+ }, he = () => new Promise((e, t) => {
155
+ let n = "Unknown";
156
+ function r(t) {
157
+ e({
158
+ isPrivate: t,
159
+ browserName: n
160
+ });
161
+ }
162
+ function i() {
163
+ let e = navigator.userAgent;
164
+ return e.match(/Chrome/) ? navigator.brave === void 0 ? e.match(/Edg/) ? "Edge" : e.match(/OPR/) ? "Opera" : "Chrome" : "Brave" : "Chromium";
165
+ }
166
+ function a(e) {
167
+ return e === eval.toString().length;
168
+ }
169
+ function o() {
170
+ let e = navigator.vendor;
171
+ return e !== void 0 && e.indexOf("Apple") === 0 && a(37);
172
+ }
173
+ function s() {
174
+ let e = navigator.vendor;
175
+ return e !== void 0 && e.indexOf("Google") === 0 && a(33);
176
+ }
177
+ function c() {
178
+ return document.documentElement !== void 0 && document.documentElement.style.MozAppearance !== void 0 && a(37);
179
+ }
180
+ function l() {
181
+ return navigator.msSaveBlob !== void 0 && a(39);
182
+ }
183
+ function u() {
184
+ let e = String(Math.random());
185
+ try {
186
+ let t = window.indexedDB.open(e, 1);
187
+ t.onupgradeneeded = (t) => {
188
+ let n = t.target?.result;
189
+ try {
190
+ n.createObjectStore("test", { autoIncrement: !0 }).put(new Blob()), r(!1);
191
+ } catch (e) {
192
+ let t = e;
193
+ return e instanceof Error && (t = e.message ?? e), r(typeof t == "string" ? /BlobURLs are not yet supported/.test(t) : !1);
194
+ } finally {
195
+ n.close(), window.indexedDB.deleteDatabase(e);
196
+ }
197
+ };
198
+ } catch {
199
+ return r(!1);
200
+ }
201
+ }
202
+ function d() {
203
+ let e = window.openDatabase, t = window.localStorage;
204
+ try {
205
+ e(null, null, null, null);
206
+ } catch {
207
+ return r(!0);
208
+ }
209
+ try {
210
+ t.setItem("test", "1"), t.removeItem("test");
211
+ } catch {
212
+ return r(!0);
213
+ }
214
+ return r(!1);
215
+ }
216
+ function f() {
217
+ navigator.maxTouchPoints === void 0 ? d() : u();
218
+ }
219
+ function p() {
220
+ let e = window;
221
+ return e.performance !== void 0 && e.performance.memory !== void 0 && e.performance.memory.jsHeapSizeLimit !== void 0 ? performance.memory.jsHeapSizeLimit : 1073741824;
222
+ }
223
+ function m() {
224
+ navigator.webkitTemporaryStorage.queryUsageAndQuota((e, t) => {
225
+ r(Math.round(t / (1024 * 1024)) < Math.round(p() / (1024 * 1024)) * 2);
226
+ }, (e) => {
227
+ t(/* @__PURE__ */ Error(`detectIncognito somehow failed to query storage quota: ${e.message}`));
228
+ });
229
+ }
230
+ function h() {
231
+ let e = window.webkitRequestFileSystem;
232
+ e(0, 1, () => {
233
+ r(!1);
234
+ }, () => {
235
+ r(!0);
236
+ });
237
+ }
238
+ function g() {
239
+ self.Promise !== void 0 && self.Promise.allSettled !== void 0 ? m() : h();
240
+ }
241
+ function _() {
242
+ r(navigator.serviceWorker === void 0);
243
+ }
244
+ function v() {
245
+ r(window.indexedDB === void 0);
246
+ }
247
+ function ee() {
248
+ o() ? (n = "Safari", f()) : s() ? (n = i(), g()) : c() ? (n = "Firefox", _()) : l() ? (n = "Internet Explorer", v()) : t(/* @__PURE__ */ Error("detectIncognito cannot determine the browser"));
249
+ }
250
+ ee();
251
+ }), ge = () => {
252
+ try {
253
+ let e = document.createElement("canvas"), t = e?.getContext("webgl") || e?.getContext("experimental-webgl");
254
+ if (!t) return null;
255
+ let n = t?.getExtension("WEBGL_debug_renderer_info");
256
+ return n ? t?.getParameter(n.UNMASKED_RENDERER_WEBGL) : null;
257
+ } catch {
258
+ return null;
259
+ }
260
+ }, _e = 1e3, E = (e) => Promise.race([e, new Promise((e, t) => setTimeout(() => t(/* @__PURE__ */ Error("probe timed out")), _e))]), ve = async () => {
261
+ if (typeof window > "u" || typeof navigator > "u") return null;
262
+ let [e, t, n] = await Promise.allSettled([
263
+ E(he()),
264
+ E(navigator.getBattery?.() ?? Promise.reject()),
265
+ E("mediaDevices" in navigator ? navigator.mediaDevices.enumerateDevices() : Promise.reject())
266
+ ]), r, i = {};
267
+ if (e.status === "fulfilled" && (r = e.value.isPrivate), t.status === "fulfilled" && t.value) {
268
+ let e = t.value.level;
269
+ typeof e == "number" && (i.battery_level = Number((e * 100).toFixed(0))), i.battery_charging = t.value.charging, i.battery_discharging_time = t.value.dischargingTime, i.battery_full_charge_capacity = t.value.fullChargeCapacity, i.battery_charging_time = t.value.chargingTime;
270
+ }
271
+ let a = ge();
272
+ return a && (i.gpu = a), n.status === "fulfilled" && (i.camera_supported = n.value.some((e) => e?.kind === "videoinput"), i.microphone_supported = n.value.some((e) => e?.kind === "audioinput")), r === void 0 && Object.keys(i).length === 0 ? null : {
273
+ private_mode: r,
274
+ properties: i
275
+ };
276
+ }, D = {
277
+ session_id: null,
278
+ sent: {},
279
+ staged: {}
280
+ }, O = e(D), k = (e, t) => {
281
+ let n = e.properties || t.properties ? {
282
+ ...e.properties ?? {},
283
+ ...t.properties ?? {}
284
+ } : void 0;
285
+ return {
286
+ ...e,
287
+ ...t,
288
+ ...n ? { properties: n } : {}
289
+ };
290
+ }, ye = (e, t) => {
291
+ let n = O.get(), r = n.session_id === e ? n : {
292
+ ...D,
293
+ session_id: e
294
+ };
295
+ O.set({
296
+ ...r,
297
+ session_id: e,
298
+ staged: k(r.staged, t)
299
+ });
300
+ }, be = (e) => {
301
+ let t = O.get();
302
+ return t.session_id !== e || Object.keys(t.staged).length === 0 ? null : (O.set({
303
+ ...t,
304
+ staged: {}
305
+ }), t.staged);
306
+ }, xe = (e, t) => {
307
+ let n = O.get(), r = n.session_id === e, { created_at: i, url: a, ...o } = t, s = r ? t : o;
308
+ O.set({
309
+ ...n,
310
+ staged: k(s, n.staged)
311
+ });
312
+ }, Se = (e, t) => {
313
+ if (!t) return;
314
+ let n = O.get();
315
+ if (n.session_id !== e) {
316
+ xe(e, t);
317
+ return;
318
+ }
319
+ O.set({
320
+ ...n,
321
+ sent: k(n.sent, t)
322
+ });
323
+ }, Ce = (e, t) => {
324
+ t && xe(e, t);
325
+ }, we = (e, t) => {
326
+ let n = O.get(), { created_at: r, url: i, ...a } = k(n.sent, n.staged);
327
+ O.set({
328
+ session_id: e,
329
+ sent: {},
330
+ staged: k(a, t)
331
+ });
332
+ }, Te = () => {
333
+ O.set(D);
334
+ }, Ee = (e) => {
335
+ ve().then((t) => {
336
+ t && ye(e(), {
337
+ ...t.private_mode === void 0 ? {} : { private_mode: t.private_mode },
338
+ properties: t.properties
339
+ });
340
+ }).catch(() => {});
341
+ }, De = 1800 * 1e3, Oe = 400 * 24 * 60 * 60, ke = De / 1e3, A = m(), j = () => {
342
+ let e = typeof window < "u" ? window.crypto : void 0;
343
+ if (!e?.getRandomValues) return a.generate();
344
+ let t = e.getRandomValues(new Uint32Array(2));
345
+ return a.generate({
346
+ shard_id: (t[0] ?? 0) % 1024,
347
+ sequence: (t[1] ?? 0) % 4096
348
+ });
349
+ }, M = (e) => typeof e == "string" && a.isValid(e), Ae = () => {
350
+ let { endpoint: e } = T();
351
+ return !(e.status === "proven" && e.mode === "direct");
352
+ }, je = () => {
353
+ let e = h(p.client_device), t = h(p.client_session);
354
+ return {
355
+ ...M(e) ? { device_id: e } : {},
356
+ ...M(t) ? { session_id: t } : {}
357
+ };
358
+ }, Me = (e) => {
359
+ if (!A) return {};
360
+ try {
361
+ let t = localStorage.getItem(f.identity);
362
+ if (!t) return {};
363
+ let n = JSON.parse(t);
364
+ if (typeof n != "object" || !n || Array.isArray(n)) return {};
365
+ let r = n, i = r.session_expires_at, a = typeof i == "number" && i > e && i <= e + 18e5;
366
+ return {
367
+ ...M(r.device_id) ? { device_id: r.device_id } : {},
368
+ ...a && M(r.session_id) ? { session_id: r.session_id } : {}
369
+ };
370
+ } catch {
371
+ return {};
372
+ }
373
+ }, N = (e) => {
374
+ if (P.set(e), A) try {
375
+ localStorage.setItem(f.identity, JSON.stringify({
376
+ ...e,
377
+ session_expires_at: Date.now() + De
378
+ }));
379
+ } catch {}
380
+ return g(p.client_device, e.device_id, Oe), g(p.client_session, e.session_id, ke), e;
381
+ }, P = e(null), Ne = () => {
382
+ let e = Date.now(), t = je(), n = Me(e), [r, i] = Ae() ? [t, n] : [n, t], a = A ? null : P.get();
383
+ return {
384
+ device_id: r.device_id ?? i.device_id ?? a?.device_id ?? j(),
385
+ session_id: r.session_id ?? i.session_id ?? a?.session_id ?? j()
386
+ };
387
+ }, Pe = () => N(Ne()), Fe = (e) => {
388
+ we(e, {
389
+ created_at: (/* @__PURE__ */ new Date()).toISOString(),
390
+ ...x(ze()) ? { url: ze() } : {}
391
+ });
392
+ }, F = () => {
393
+ let e = Ne(), t = P.get();
394
+ if (t && t.device_id === e.device_id && t.session_id === e.session_id) return t;
395
+ let n = N(e);
396
+ return t && t.session_id !== e.session_id && Fe(e.session_id), n;
397
+ }, Ie = () => P.get() ?? Pe(), Le = () => {
398
+ N(F());
399
+ }, Re = (e = "idle") => {
400
+ let t = F(), n = N({
401
+ ...t,
402
+ session_id: j()
403
+ });
404
+ return Fe(n.session_id), l().debug && console.log(`[@levo-so/insights] Session rotated (${e}):`, `${t.session_id} -> ${n.session_id}`), n;
405
+ }, ze = () => typeof window < "u" ? window.location?.href ?? "" : "", Be = (e) => {
406
+ if (!M(e)) return;
407
+ let t = F();
408
+ t.device_id !== e && N({
409
+ ...t,
410
+ device_id: e
411
+ });
412
+ }, Ve = (e) => {
413
+ let t = F();
414
+ return l().debug && console.log(`[@levo-so/insights] identify(${e ?? ""}) on session`, t.session_id), t;
415
+ }, He = () => Re("reset"), I = (e) => e.status === "none" ? null : e.url, Ue = (e) => e.status === "proven" ? e.mode : "proxy", We = ({ deviceId: e, sessionId: t, deviceToken: n, mode: r }) => {
416
+ if (r !== "direct") return {};
417
+ let i = {};
418
+ return e && (i["Levo-Audience-Client-Device"] = e), t && (i["Levo-Audience-Client-Session"] = t), n && (i["Levo-Audience-Device"] = n), i;
419
+ }, Ge = 60 * 1024, Ke = (e) => !!e && typeof e == "object" && "status" in e, L = (e, t) => me({ endpoint: {
420
+ status: "proven",
421
+ url: e,
422
+ mode: t
423
+ } }), qe = (e) => {
424
+ let { deviceId: t, deviceToken: n, endpoint: r, eventCount: a, sessionId: o, serialized: s, workspace: c } = e, l = `/v2/insights/event/bulk?${new URLSearchParams({ workspace: c }).toString()}`, u = (r, c, d) => fetch(`${r}${l}`, {
425
+ method: "POST",
426
+ body: s,
427
+ headers: {
428
+ "Content-Type": "application/json",
429
+ ...We({
430
+ deviceId: t,
431
+ sessionId: o,
432
+ deviceToken: n,
433
+ mode: c
434
+ })
435
+ },
436
+ keepalive: new Blob([s]).size < Ge,
437
+ credentials: c === "proxy" ? "include" : "omit"
438
+ }).then(async (t) => {
439
+ let n = t.ok ? await t.json().catch(() => null) : null;
440
+ if (t.ok && Ke(n)) return d && L(r, c), e.onSuccess(), n;
441
+ if (d) return L(d, "direct"), u(d, "direct", null);
442
+ let i = t.ok ? "" : await t.text().catch(() => "");
443
+ return console.warn(`[@levo-so/insights] Event batch rejected (${t.status}), ${a} event(s) lost:`, i.slice(0, 500)), e.onFailure(), null;
444
+ }).then((e) => {
445
+ let t = e?.content?.meta?.device;
446
+ typeof t == "string" && t && Be(t);
447
+ }).catch((t) => {
448
+ if (d) return L(d, "direct"), u(d, "direct", null);
449
+ console.warn(`[@levo-so/insights] Event flush failed, ${a} event(s) lost:`, i(t)), e.onFailure();
450
+ });
451
+ u(r.status === "none" ? "" : r.url, Ue(r), r.status === "unproven" ? r.fallback : null);
452
+ }, Je = 10, Ye = 2e3, Xe = 15, Ze = 1e3, Qe = new Set([r["user.idle"], r["page.bounce"]]), R = e([]), z = e(0), $e = t(R, (e) => e.length ?? 0), B = e(null), et = () => R.get(), tt = () => $e.get(), V = !1, H = () => {
453
+ let e = et(), { workspace: t, site_id: n, debug: r } = l(), { deviceToken: a, endpoint: o } = T();
454
+ if (e.length === 0 || !I(o) || !t) return;
455
+ if (!ae.test(t)) {
456
+ console.warn(`[@levo-so/insights] Invalid workspace id "${t}", events not sent.`), R.set([]);
457
+ return;
458
+ }
459
+ rt(), V = !0;
460
+ let { device_id: s, session_id: c } = Ie(), u = { events: e.map((e) => ({
461
+ workspace_id: t,
462
+ ...n ? { site_id: n } : {},
463
+ ...le(e)
464
+ })) }, d = () => {
465
+ try {
466
+ return JSON.stringify(u);
467
+ } catch (t) {
468
+ return console.warn(`[@levo-so/insights] Event batch could not be serialized, ${e.length} event(s) dropped:`, i(t)), null;
469
+ }
470
+ };
471
+ if (r) {
472
+ console.log("[@levo-so/insights] Debug mode enabled. Request:", u), R.set([]);
473
+ return;
474
+ }
475
+ let f = be(c);
476
+ f && (u.session = f);
477
+ let p = d();
478
+ if (!p) {
479
+ Ce(c, f), R.set([]);
480
+ return;
481
+ }
482
+ R.set([]), qe({
483
+ deviceId: s,
484
+ deviceToken: a,
485
+ endpoint: o,
486
+ eventCount: u.events.length,
487
+ onFailure: () => Ce(c, f),
488
+ onSuccess: () => Se(c, f),
489
+ serialized: p,
490
+ sessionId: c,
491
+ workspace: t
492
+ });
493
+ }, nt = () => {
494
+ if (B.get()) return;
495
+ let e = setTimeout(() => {
496
+ B.set(null), H();
497
+ }, Ye);
498
+ B.set(e);
499
+ }, rt = () => {
500
+ let e = B.get();
501
+ e && (clearTimeout(e), B.set(null));
502
+ }, it = (e) => {
503
+ let { debug: t, insightsUrl: n } = l();
504
+ if (!n) {
505
+ t && console.warn("[@levo-so/insights] Event dropped, insightsUrl not configured.", {
506
+ event: e.event,
507
+ resource: e.resource
508
+ });
509
+ return;
510
+ }
511
+ let r = z.get();
512
+ if (r >= Ze) {
513
+ t && console.warn(`[@levo-so/core] Event limit (${Ze}) reached for this page`);
514
+ return;
515
+ }
516
+ z.set(r + 1), Qe.has(e.event) || Le();
517
+ let i = R.get();
518
+ if (i.length >= Xe) {
519
+ t && console.warn(`[@levo-so/insights] Queue full (${Xe}), event dropped:`, e.event);
520
+ return;
521
+ }
522
+ R.set([...i, e]), !V || tt() >= Je ? H() : nt();
523
+ }, at = () => z.set(0), ot = I(C.get().endpoint);
524
+ C.subscribe((e) => {
525
+ let t = I(e.endpoint);
526
+ t && !ot && R.get().length > 0 && H(), ot = t;
527
+ });
528
+ var st = () => {
529
+ R.set([]), z.set(0), rt(), V = !1, Te();
530
+ }, ct = e(!1), lt = e(!1), ut = t([w, ct], (e, t) => e && t), dt = t([ut, lt], (e, t) => e && t), U = n({
531
+ status: "active",
532
+ seconds: 0
533
+ }), ft = (e) => {
534
+ if (typeof window > "u") return () => {};
535
+ let t = o({
536
+ timeout: 6e4,
537
+ throttle: 1e3,
538
+ onIdle: (e) => {
539
+ U.set({
540
+ status: "idle",
541
+ seconds: e
542
+ });
543
+ },
544
+ onWakeUp: (e) => {
545
+ U.set({
546
+ status: "active",
547
+ seconds: e
548
+ });
549
+ }
550
+ }), n = U.listen((t) => {
551
+ t.seconds > 0 && (t.status === "idle" ? e.track("user.idle", { seconds_active: t.seconds }) : e.track("user.active", { seconds_idle: t.seconds }));
552
+ });
553
+ return () => {
554
+ n(), t.disable(), U.set({
555
+ status: "active",
556
+ seconds: 0
557
+ });
558
+ };
559
+ }, pt = () => U.get(), W = /* @__PURE__ */ function(e) {
560
+ return e.ACTIVE = "active", e.PASSIVE = "passive", e.HIDDEN = "hidden", e.FROZEN = "frozen", e.TERMINATED = "terminated", e;
561
+ }(W || {}), G = e(W.ACTIVE), mt = () => typeof document > "u" ? W.ACTIVE : document.visibilityState === "hidden" ? W.HIDDEN : document.hasFocus() ? W.ACTIVE : W.PASSIVE, ht = (e) => {
562
+ if (typeof window > "u") return () => {};
563
+ let t = !1, n = (n) => {
564
+ if (t) return;
565
+ t = !0;
566
+ let r = pt(), a = {};
567
+ r.seconds > 0 && (r.status === "idle" ? a.seconds_active = r.seconds : a.seconds_idle = r.seconds);
568
+ try {
569
+ e.track("page.bounce", {
570
+ resource: "page",
571
+ ...a,
572
+ ...n
573
+ }, {}, () => H());
574
+ } catch (e) {
575
+ console.error("[insights] Failed to send bounce event", i(e));
576
+ }
577
+ }, r = () => {
578
+ let e = performance.getEntriesByType("navigation")?.[0], t = e?.type === "navigate";
579
+ if (!t) try {
580
+ let e = document.activeElement;
581
+ e?.tagName === "A" && e.href && new URL(e.href).origin !== window.location.origin && (t = !0);
582
+ } catch (e) {
583
+ console.warn("[insights] Failed to parse link destination", i(e));
584
+ }
585
+ n({
586
+ is_navigating_away: t,
587
+ navigation_type: e?.type,
588
+ trigger: "beforeunload"
589
+ });
590
+ }, a = (e) => {
591
+ switch (e.type) {
592
+ case "pageshow":
593
+ case "resume":
594
+ case "blur":
595
+ case "focus":
596
+ case "visibilitychange":
597
+ G.set(mt());
598
+ break;
599
+ case "freeze":
600
+ G.set(W.FROZEN);
601
+ break;
602
+ case "pagehide":
603
+ G.set(e.persisted ? W.FROZEN : W.TERMINATED);
604
+ break;
605
+ }
606
+ }, o = [
607
+ "pageshow",
608
+ "pagehide",
609
+ "focus",
610
+ "blur",
611
+ "visibilitychange",
612
+ "resume",
613
+ "freeze"
614
+ ];
615
+ o.forEach((e) => {
616
+ window.addEventListener(e, a, { capture: !0 });
617
+ }), window.addEventListener("beforeunload", r);
618
+ let s = G.listen((e) => {
619
+ e === W.FROZEN || e === W.TERMINATED ? n({
620
+ state: e,
621
+ trigger: "lifecycle"
622
+ }) : e === W.HIDDEN && H();
623
+ }), l = c.get().page_id, u = c.listen((e) => {
624
+ e.page_id !== l && (t = !1, l = e.page_id);
625
+ }), d = z.listen((e) => {
626
+ e === 0 && (t = !1);
627
+ });
628
+ return () => {
629
+ o.forEach((e) => {
630
+ window.removeEventListener(e, a, { capture: !0 });
631
+ }), window.removeEventListener("beforeunload", r), s(), u(), d(), t = !1, G.set(W.ACTIVE);
632
+ };
633
+ }, K = (e) => Object.prototype.toString.call(e) == "[object String]", gt = (e, t) => e.indexOf(t) !== -1, q = (e) => e.replace(/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g, ""), _t = (e) => e === void 0, vt = (e) => e === null, yt = (e) => _t(e) || vt(e), bt = (e) => !!e && e?.nodeType === 3;
634
+ function xt(e) {
635
+ return !!e && e?.nodeType === 1;
636
+ }
637
+ function St(e, t) {
638
+ return !!e && !!e?.tagName && e?.tagName.toLowerCase() === t.toLowerCase();
639
+ }
640
+ function Ct(e) {
641
+ return e ? q(e).split(/\s+/) : [];
642
+ }
643
+ function wt(e) {
644
+ let t = "";
645
+ switch (typeof e?.className) {
646
+ case "string":
647
+ t = e?.className;
648
+ break;
649
+ case "object":
650
+ t = (e?.className && "baseVal" in e.className ? (e?.className).baseVal : null) || e?.getAttribute("class") || "";
651
+ break;
652
+ default: t = "";
653
+ }
654
+ return Ct(t);
655
+ }
656
+ var J = (e, t = 255) => yt(e) ? "" : q(e).split(/(\s+)/).filter((e) => X(e)).join("").replace(/[\r\n]/g, " ").replace(/[ ]+/g, " ").substring(0, t), Tt = [
657
+ "span",
658
+ "strong",
659
+ "em",
660
+ "i",
661
+ "b",
662
+ "mark",
663
+ "code",
664
+ "small",
665
+ "sub",
666
+ "sup",
667
+ "label"
668
+ ], Y = (e) => {
669
+ let t = "";
670
+ if (kt(e) && e?.childNodes && e?.childNodes.length) {
671
+ for (let n of e.childNodes) bt(n) && n.textContent && (t += J(n.textContent) ?? "");
672
+ if (!q(t)) {
673
+ let n = e.querySelectorAll(Tt.join(", "));
674
+ for (let e of n) {
675
+ let n = e.textContent;
676
+ n && (t += `${J(n)} `);
677
+ }
678
+ }
679
+ if (!q(t) && e instanceof HTMLElement) {
680
+ let n = e.innerText;
681
+ n && (t = J(n.substring(0, 500)));
682
+ }
683
+ }
684
+ return q(t);
685
+ }, Et = (e) => _t(e.target) ? e?.srcElement || null : e?.composedPath?.()[0] || e?.target || null, Dt = (e, t) => {
686
+ if (!window || !e || St(e, "html") || !xt(e)) return !1;
687
+ let n = window.getComputedStyle(e);
688
+ if (n && n.getPropertyValue("cursor") === "pointer" && t.type === "click") return !0;
689
+ switch (e?.tagName.toLowerCase()) {
690
+ case "html": return !1;
691
+ case "form": return t.type === "submit";
692
+ case "input":
693
+ case "select":
694
+ case "textarea": return ["change", "click"].includes(t.type);
695
+ default: return t.type === "click";
696
+ }
697
+ }, Ot = new Set([
698
+ "password",
699
+ "passwd",
700
+ "pwd",
701
+ "creditcard",
702
+ "cardnumber",
703
+ "ccnum",
704
+ "ccnumber",
705
+ "cvv",
706
+ "cvc",
707
+ "csc",
708
+ "securitycode",
709
+ "ssn",
710
+ "socialsecurity",
711
+ "routingnumber",
712
+ "accountnumber",
713
+ "bankaccount",
714
+ "secretkey",
715
+ "apikey",
716
+ "accesstoken"
717
+ ]);
718
+ function kt(e) {
719
+ if (gt(wt(e), "ph-include")) return !0;
720
+ let t = e.type || "";
721
+ if (K(t)) switch (t.toLowerCase()) {
722
+ case "hidden": return !1;
723
+ case "password": return !1;
724
+ }
725
+ let n = e.name || e?.id || "";
726
+ if (K(n)) {
727
+ let e = n.toLowerCase().replace(/[^a-z]/g, "");
728
+ if (Ot.has(e)) return !1;
729
+ }
730
+ return !0;
731
+ }
732
+ var At = "(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})", jt = RegExp(`^(?:${At})$`), Mt = new RegExp(At), Nt = "\\d{3}-?\\d{2}-?\\d{4}", Pt = RegExp(`^(${Nt})$`), Ft = RegExp(`(${Nt})`), X = (e, t = !0) => !(yt(e) || K(e) && (e = q(e), (t ? jt : Mt).test((e || "").replace(/[- ]/g, "")) || (t ? Pt : Ft).test(e))), It = (e) => K(e) ? e.substring(0, 10) === "_ngcontent" || e.substring(0, 7) === "_nghost" : !1, Lt = (e) => {
733
+ let t = Y(e);
734
+ return t = `${t} ${Rt(e)}`.trim(), X(t) ? t : "";
735
+ };
736
+ function Rt(e) {
737
+ let t = "";
738
+ if (e?.childNodes.length) for (let n of e.childNodes) {
739
+ let e = n.tagName?.toLowerCase();
740
+ if (n && e && Tt.includes(e)) try {
741
+ let e = Y(n);
742
+ t = `${t} ${e}`.trim(), n?.childNodes.length && (t = `${t} ${Rt(n)}`.trim());
743
+ } catch {}
744
+ }
745
+ return t;
746
+ }
747
+ var zt = (e) => {
748
+ let t = e.tagName?.toLowerCase(), n = t === "a" || t === "button" ? Lt(e) : Y(e);
749
+ if (n) return {
750
+ text: n,
751
+ source: "text"
752
+ };
753
+ let r = e.getAttribute("aria-label");
754
+ if (r) return {
755
+ text: J(r),
756
+ source: "aria-label"
757
+ };
758
+ let i = e.getAttribute("title");
759
+ if (i) return {
760
+ text: J(i),
761
+ source: "title"
762
+ };
763
+ let a = e.getAttribute("data-track-label");
764
+ if (a) return {
765
+ text: J(a),
766
+ source: "data-track-label"
767
+ };
768
+ let o = e.querySelector("img[alt], svg[aria-label]");
769
+ if (o) {
770
+ let e = o.getAttribute("alt") || o.getAttribute("aria-label");
771
+ if (e) return {
772
+ text: J(e),
773
+ source: "alt"
774
+ };
775
+ }
776
+ let s = e.getAttribute("placeholder");
777
+ if (s) return {
778
+ text: J(s),
779
+ source: "placeholder"
780
+ };
781
+ if (e instanceof HTMLElement && e.innerText) {
782
+ let t = e.innerText.substring(0, 500);
783
+ if (t.trim()) return {
784
+ text: J(t),
785
+ source: "innerText"
786
+ };
787
+ }
788
+ return {
789
+ text: "",
790
+ source: "none"
791
+ };
792
+ }, Bt = [
793
+ "input",
794
+ "textarea",
795
+ "select"
796
+ ], Vt = (e) => {
797
+ let t = e?.tagName?.toLowerCase(), n = { element: t }, r = zt(e);
798
+ n.text = r.text, n.text_source = r.source;
799
+ let i = e.getAttribute("aria-label");
800
+ i && (n.aria_label = J(i));
801
+ let a = e.getAttribute("role");
802
+ a && (n.role = a);
803
+ let o = {};
804
+ for (let t of e.attributes) (t.name.startsWith("data-track-") || t.name.startsWith("data-analytics-")) && (o[t.name] = J(t.value));
805
+ if (Object.keys(o).length && (n.tracking_data = o), n.attributes = Array.from(e.attributes).reduce((e, t) => {
806
+ if (X(t.value) && !It(t.name)) {
807
+ if (t.name === "class" || t.name.startsWith("data-track-") || t.name.startsWith("data-analytics-")) return e;
808
+ e[t.name] = typeof t?.value == "string" ? J(t.value) : t.value;
809
+ }
810
+ return e;
811
+ }, {}), Bt.includes(t) || e?.getAttribute("contenteditable") === "true") {
812
+ let t;
813
+ e.matches("input[type=\"checkbox\"], input[type=\"radio\"]") ? t = e.checked : e.matches("input, select, textarea") && !e.matches("input[type=\"password\"]") && (t = e.value), t !== void 0 && (n.value = typeof t == "string" || t === null ? J(t, 1024) : t);
814
+ let r = "";
815
+ n?.attributes.id && (r = J(document.querySelector(`label[for="${n?.attributes.id}"]`)?.textContent?.trim() || ""));
816
+ let i = e.closest("label");
817
+ r ||= J(i?.textContent?.trim() || ""), r && (n.label = r);
818
+ }
819
+ return n;
820
+ }, Ht = (e, t) => {
821
+ let n = Et(e);
822
+ bt(n) && (n = n.parentNode || null);
823
+ let r = ["copy", "cut"].includes(t);
824
+ if (n && (r || Dt(n, e))) {
825
+ let t = Vt(n);
826
+ if (r) {
827
+ let n = J(window?.getSelection()?.toString()), r = e?.type || "clipboard";
828
+ t.copy_text = n ?? "", t.copy_type = r ?? "";
829
+ }
830
+ return t;
831
+ }
832
+ return null;
833
+ }, Z = e(null), Ut = 3e3, Wt = 1e4, Gt = `${f.open_tabs}:`, Kt = (e) => `${Gt}${e}`, qt = (e) => {
834
+ try {
835
+ localStorage.setItem(Kt(e), String(Date.now()));
836
+ } catch {}
837
+ }, Jt = (e) => {
838
+ try {
839
+ localStorage.removeItem(Kt(e));
840
+ } catch {}
841
+ }, Yt = (e) => {
842
+ try {
843
+ let t = Number(localStorage.getItem(Kt(e)));
844
+ return Number.isFinite(t) && Date.now() - t <= Wt;
845
+ } catch {
846
+ return !1;
847
+ }
848
+ }, Xt = () => {
849
+ try {
850
+ let e = Date.now(), t = 0, n = [];
851
+ for (let r = 0; r < localStorage.length; r++) {
852
+ let i = localStorage.key(r);
853
+ if (!i || !i.startsWith(Gt)) continue;
854
+ let a = Number(localStorage.getItem(i));
855
+ Number.isFinite(a) && e - a <= Wt ? t += 1 : n.push(i);
856
+ }
857
+ for (let e of n) try {
858
+ localStorage.removeItem(e);
859
+ } catch {}
860
+ return Math.max(1, t);
861
+ } catch {
862
+ return 1;
863
+ }
864
+ }, Zt = 1, Qt = () => {
865
+ Zt = Xt();
866
+ }, $t = (e) => {
867
+ if (typeof window > "u") return () => {};
868
+ let t = null;
869
+ try {
870
+ t = sessionStorage.getItem(f.current_tab);
871
+ } catch {}
872
+ if (t && Yt(t) && (t = null), !t) {
873
+ t = `${Date.now()}-${Math.random().toString(36).substring(2, 11)}`;
874
+ try {
875
+ sessionStorage.setItem(f.current_tab, t);
876
+ } catch {}
877
+ }
878
+ let n = t;
879
+ Z.set(n), qt(n), Qt();
880
+ let r = window.setInterval(() => {
881
+ qt(n), Qt();
882
+ }, Ut), i = (e) => {
883
+ e.persisted || Jt(n);
884
+ };
885
+ return window.addEventListener("beforeunload", i), window.addEventListener("pagehide", i), () => {
886
+ window.clearInterval(r), window.removeEventListener("beforeunload", i), window.removeEventListener("pagehide", i), Jt(n), Z.set(null);
887
+ };
888
+ }, en = () => Z.get(), tn = () => Zt, Q = n({
889
+ depth: 0,
890
+ milestone: 0,
891
+ speedCategory: "read",
892
+ direction: "down"
893
+ }), nn = (e) => {
894
+ if (typeof window > "u") return () => {};
895
+ let t = {
896
+ prevMilestone: -1,
897
+ prevScrollY: 0,
898
+ prevTime: Date.now()
899
+ }, n = () => {
900
+ let e = window.scrollY, n = document.documentElement.scrollHeight - window.innerHeight;
901
+ if (n <= 0) return;
902
+ let r = Math.round(e / n * 100), i = Math.max(0, Math.min(100, r)), a = Math.floor(i / 5) * 5, { prevScrollY: o, prevTime: s } = t, c = Date.now(), l = (c - s) / 1e3, u = Math.abs(e - o), d = l > 0 ? u / l : 0, f = i > t.prevScrollY / n * 100 ? "down" : "up", p = d > 300 ? "scan" : "read";
903
+ Q.set({
904
+ depth: i,
905
+ milestone: a,
906
+ speedCategory: p,
907
+ direction: f
908
+ }), t = {
909
+ prevMilestone: a,
910
+ prevScrollY: e,
911
+ prevTime: c
912
+ };
913
+ }, r = s(n, 250);
914
+ window.addEventListener("scroll", r);
915
+ let i = 0, a = Q.listen((t) => {
916
+ t.milestone !== i && (i = t.milestone, e.track("page.scroll", {
917
+ depth: t.milestone,
918
+ speed_category: t.speedCategory,
919
+ direction: t.direction
920
+ }));
921
+ });
922
+ return typeof window.requestIdleCallback == "function" ? window.requestIdleCallback(() => n()) : setTimeout(n, 0), () => {
923
+ window.removeEventListener("scroll", r), r.cancel(), a(), Q.set({
924
+ depth: 0,
925
+ milestone: 0,
926
+ speedCategory: "read",
927
+ direction: "down"
928
+ });
929
+ };
930
+ }, $ = e(null), rn = (e) => {
931
+ if (typeof window > "u") return () => {};
932
+ let t = s(() => {
933
+ let e = window.getSelection();
934
+ if (e && e.rangeCount > 0) {
935
+ let t = e.toString().trim();
936
+ t && $.set(t);
937
+ }
938
+ }, 1e3);
939
+ document.addEventListener("selectionchange", t);
940
+ let n = $.listen((t) => {
941
+ t && e.track("page.selection", { text: J(t) });
942
+ });
943
+ return () => {
944
+ document.removeEventListener("selectionchange", t), t.cancel(), n(), $.set(null);
945
+ };
946
+ };
947
+ //#endregion
948
+ export { F as A, T as B, st as C, r as D, at as E, Le as F, l as G, se as H, Ee as I, u as K, ye as L, Ve as M, He as N, We as O, Re as P, w as R, $e as S, it as T, f as U, me as V, c as W, ut as _, Z as a, R as b, $t as c, Ht as d, G as f, lt as g, ft as h, nn as i, Pe as j, P as k, Vt as l, U as m, rn as n, en as o, ht as p, d as q, Q as r, tn as s, $ as t, Et as u, ct as v, H as w, z as x, dt as y, C as z };