@useindeks/core 0.0.0-stage → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +159 -2
- package/dist/indeks.global.js +1 -0
- package/dist/index.cjs +2810 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +79 -0
- package/dist/index.d.ts +79 -0
- package/dist/index.js +2797 -0
- package/dist/index.js.map +1 -0
- package/package.json +68 -4
package/README.md
CHANGED
|
@@ -1,3 +1,160 @@
|
|
|
1
|
-
|
|
1
|
+
<p align="center">
|
|
2
|
+
<a href="https://github.com/ru-dr/indeks-sdk">
|
|
3
|
+
<picture>
|
|
4
|
+
<source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/ru-dr/indeks-sdk/main/assets/logo-sdk-dark.svg">
|
|
5
|
+
<img src="https://raw.githubusercontent.com/ru-dr/indeks-sdk/main/assets/logo-sdk-light.svg" alt="Indeks SDK" width="420">
|
|
6
|
+
</picture>
|
|
7
|
+
</a>
|
|
8
|
+
</p>
|
|
2
9
|
|
|
3
|
-
|
|
10
|
+
<p align="center">
|
|
11
|
+
<a href="https://www.npmjs.com/package/@useindeks/core"><img alt="@useindeks/core on npm" src="https://shieldcn.dev/npm/@useindeks/core.svg"></a>
|
|
12
|
+
<a href="https://www.npmjs.com/package/@useindeks/core"><img alt="@useindeks/core downloads" src="https://shieldcn.dev/npm/dw/@useindeks/core.svg"></a>
|
|
13
|
+
<a href="https://www.npmjs.com/package/@useindeks/core"><img alt="@useindeks/core types" src="https://shieldcn.dev/npm/types/@useindeks/core.svg"></a>
|
|
14
|
+
</p>
|
|
15
|
+
|
|
16
|
+
<p align="center">
|
|
17
|
+
<a href="https://github.com/ru-dr/indeks-sdk/blob/main/LICENSE"><img alt="License" src="https://shieldcn.dev/github/license/ru-dr/indeks-sdk.svg"></a>
|
|
18
|
+
<a href="https://github.com/ru-dr/indeks-sdk/actions/workflows/ci.yml"><img alt="CI" src="https://shieldcn.dev/github/ci/ru-dr/indeks-sdk.svg"></a>
|
|
19
|
+
</p>
|
|
20
|
+
|
|
21
|
+
# @useindeks/core
|
|
22
|
+
|
|
23
|
+
Framework-agnostic tracker for the Indeks SDK.
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
npm install @useindeks/core
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
```ts
|
|
30
|
+
import { indeks } from "@useindeks/core";
|
|
31
|
+
|
|
32
|
+
const tracker = indeks("YOUR_PROJECT_KEY", {
|
|
33
|
+
endpoint: "https://analytics.example.com/api/v1/collect",
|
|
34
|
+
preset: "standard",
|
|
35
|
+
debug: false,
|
|
36
|
+
});
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
`indeks()` creates a tracker and starts it once the DOM is ready. Use `new IndeksTracker(config)` and `await tracker.init()` if you want to control startup yourself. The constructor throws if the configuration is invalid.
|
|
40
|
+
|
|
41
|
+
## Script tag
|
|
42
|
+
|
|
43
|
+
`dist/indeks.global.js` (about 20 kB gzipped) is a minified build that exposes `window.indeks` and `window.IndeksTracker` when the script tag has `data-indeks-global`:
|
|
44
|
+
|
|
45
|
+
```html
|
|
46
|
+
<script src="/indeks.global.js" data-indeks-global></script>
|
|
47
|
+
<script>
|
|
48
|
+
indeks("YOUR_PROJECT_KEY", { endpoint: "https://analytics.example.com/api/v1/collect" });
|
|
49
|
+
</script>
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
The script-tag build cannot use `privacy.fingerprint`, because the optional fingerprint library is not bundled into it. Use the npm packages if you need it.
|
|
53
|
+
|
|
54
|
+
## Tracker API
|
|
55
|
+
|
|
56
|
+
| Method | Description |
|
|
57
|
+
| --- | --- |
|
|
58
|
+
| `track(name, properties?, { category, value, label }?)` | Send a custom event. Properties are sanitized. Calls made before `init()` finishes are buffered. |
|
|
59
|
+
| `trackElements({ selectors, eventType?, eventName?, properties? })` | Send a custom event when matching elements receive an event (default `click`). Returns a function that stops tracking. |
|
|
60
|
+
| `identify(id, traits?)` | Attach your own user id to all later events and send an `identify` event. Persisted in `localStorage`. |
|
|
61
|
+
| `page(name?, properties?)` | Send a manual page view (useful when the `pageview` collector is off). |
|
|
62
|
+
| `reset()` | Forget the identified user and start a new anonymous user and session (for logout). |
|
|
63
|
+
| `optOut()` / `optIn()` / `isOptedOut()` | Persistent opt-out. `optOut()` stops collection and deletes buffered events. |
|
|
64
|
+
| `updateConfig({ privacy, debug })` | Make privacy stricter or toggle debug logging at runtime. Privacy can never be loosened after start. |
|
|
65
|
+
| `flush()` / `destroy()` | Send queued events now / remove every listener and stop. |
|
|
66
|
+
| `getEvents()` / `clearEvents()` | Inspect or clear the in-memory debug buffer. |
|
|
67
|
+
| `getSessionId()` / `getUserId()` / `getExternalUserId()` / `getDeviceInfo()` | Read identity and device info. |
|
|
68
|
+
|
|
69
|
+
## Configuration
|
|
70
|
+
|
|
71
|
+
```ts
|
|
72
|
+
interface IndeksConfig {
|
|
73
|
+
apiKey: string;
|
|
74
|
+
endpoint?: string; // absolute URL or same-origin path such as "/api/collect"; required to send events
|
|
75
|
+
localOnly?: boolean; // track but never send
|
|
76
|
+
debug?: boolean; // console logging
|
|
77
|
+
preset?: "minimal" | "standard" | "full"; // default "standard"
|
|
78
|
+
collectors?: Partial<Record<CollectorName, boolean>>;
|
|
79
|
+
privacy?: PrivacyConfig;
|
|
80
|
+
collectorOptions?: CollectorOptions; // tune the heuristic collectors
|
|
81
|
+
debounceMs?: number; // default 100
|
|
82
|
+
idleTimeoutMs?: number; // default 30000
|
|
83
|
+
scrollDepthThresholds?: number[]; // default [25, 50, 75, 100]
|
|
84
|
+
}
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
### Collectors
|
|
88
|
+
|
|
89
|
+
| Group | Names |
|
|
90
|
+
| --- | --- |
|
|
91
|
+
| Interaction | `click`, `doubleClick`, `contextMenu`, `mousePress`, `hover`, `mouseMove`, `wheel`, `touch`, `dragDrop`, `keystroke` |
|
|
92
|
+
| Engagement | `scroll`, `scrollDepth`, `resize`, `fullscreen`, `orientation`, `idle` |
|
|
93
|
+
| Navigation | `pageview`, `pageLoad`, `pageLeave`, `pageLifecycle`, `beforeUnload`, `hashChange`, `popState`, `visibility`, `windowFocus`, `tabFocus`, `session` |
|
|
94
|
+
| Forms | `formSubmit`, `inputChange`, `fieldFocus`, `formAbandon`, `formError`, `clipboard`, `textSelection`, `search` |
|
|
95
|
+
| Links | `download`, `outboundLink`, `print`, `share` |
|
|
96
|
+
| Frustration | `frustration` (rage clicks, dead clicks, error clicks) |
|
|
97
|
+
| Media | `media`, `mediaProgress` |
|
|
98
|
+
| Reliability | `error`, `resourceError`, `networkStatus`, `networkChange`, `performance` (FCP, LCP, CLS, INP, TTFB) |
|
|
99
|
+
|
|
100
|
+
`search` and `frustration` are heuristic collectors. They infer intent from common markup and timing, so treat their output as a signal and tune them with `collectorOptions` for your site:
|
|
101
|
+
|
|
102
|
+
```ts
|
|
103
|
+
collectorOptions: {
|
|
104
|
+
search: {
|
|
105
|
+
inputSelector: "#site-search", // default: input[type=search], [name*=search], [name*=query], [name=q]
|
|
106
|
+
resultsCountSelector: ".hit-count", // element whose text contains the number of results
|
|
107
|
+
resultItemSelector: ".hit", // fallback: count matching elements
|
|
108
|
+
},
|
|
109
|
+
frustration: {
|
|
110
|
+
rageClickCount: 3, // clicks on one element ...
|
|
111
|
+
rageClickWindowMs: 2000, // ... within this window
|
|
112
|
+
deadClickWindowMs: 500, // no DOM change or navigation within this time = dead click
|
|
113
|
+
clickableSelector: ".btn, .card", // elements that look clickable besides cursor: pointer
|
|
114
|
+
},
|
|
115
|
+
}
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
Traffic source on `session_start` follows fixed rules: a paid `utm_medium` (cpc, ppc, paid, ...) is `paid`; email medium or source is `email`; social medium or known social source is `social`; any other `utm_source` is `other`; otherwise the referrer decides (same site or none is `direct`, search engines `organic`, social networks `social`, anything else `referral`).
|
|
119
|
+
|
|
120
|
+
Presets: `minimal` (click, pageview, session, error, pageLeave, scrollDepth, outboundLink, download, performance), `standard` (everything except `keystroke`, `mouseMove`, `hover`, `mousePress`, `textSelection`), `full` (everything). Collectors are fixed when the tracker starts.
|
|
121
|
+
|
|
122
|
+
### Privacy
|
|
123
|
+
|
|
124
|
+
| Option | Default | Effect |
|
|
125
|
+
| --- | --- | --- |
|
|
126
|
+
| `respectDoNotTrack` | `true` | Do nothing if Do Not Track or Global Privacy Control is on |
|
|
127
|
+
| `elementText` | `true` | Include (redacted) text of clicked elements |
|
|
128
|
+
| `formValues` | `false` | Include non-sensitive form values (`[len:n]` otherwise) |
|
|
129
|
+
| `clipboardText` | `false` | Include copied or selected text |
|
|
130
|
+
| `searchTerms` | `false` | Include search queries |
|
|
131
|
+
| `fingerprint` | `false` | Use a [ThumbmarkJS](https://www.thumbmarkjs.com) (MIT) browser fingerprint as the anonymous user id. Install `@thumbmarkjs/thumbmarkjs` (optional peer dependency). Indeks always creates it with `logging: false` and no API key, so it makes no network calls. Fingerprinting is still tracking: get consent where the law requires it. |
|
|
132
|
+
|
|
133
|
+
What is always applied:
|
|
134
|
+
|
|
135
|
+
- Inputs that look sensitive (password, email, phone, card and similar types or names) produce no input events at all, not even their length, and show as `[redacted]` in form submissions. Printable keystrokes never include the key code.
|
|
136
|
+
- Search terms are never part of a URL: parameters such as `q`, `query`, `search`, `s` and `keyword` are redacted, along with session ids, tokens and email-valued parameters. Terms are only sent as `query` when `privacy.searchTerms` is on.
|
|
137
|
+
- Links that are not http(s) (`mailto:`, `tel:`, `javascript:`, `data:`, `blob:`) are reduced to their scheme, and emails or token-like segments in URL paths are redacted.
|
|
138
|
+
- Custom event names, labels and categories are redacted and capped at 200 characters; property strings are redacted, arrays capped at 100 items, and values JSON cannot represent are converted or dropped. `identify` ids are capped at 256 characters; use an opaque id and not an email address.
|
|
139
|
+
- With `elementText: false`, text-bearing attributes (`alt`, `title`, `aria-label`) are dropped as well, and search filters and sort labels are not read.
|
|
140
|
+
- URLs: fragments (except hash-router routes), credentials, and values of sensitive query params (`token`, `code`, `email`, ...) are removed.
|
|
141
|
+
- Free text (element text, errors, share text) is redacted for emails, card numbers, JWTs and bearer tokens.
|
|
142
|
+
- Password, email, tel, number and similar fields are never recorded, and sensitive field names are shown as `[redacted]`.
|
|
143
|
+
- Add `data-indeks-mask` (or `data-indeks-ignore`) to an element to drop its text and ignore its fields.
|
|
144
|
+
- Custom event and `identify` properties with sensitive key names are redacted.
|
|
145
|
+
|
|
146
|
+
## Behavior notes
|
|
147
|
+
|
|
148
|
+
- `session_end` and `pageleave` are snapshots sent when the page is hidden or unloaded; use the last one per session or page. `pageleave` time counts only the time the tab was visible, and is also sent for the page being left on a `pushState` or `replaceState` navigation (not for back and forward).
|
|
149
|
+
- `form_abandon` is reported when the page is unloaded or the form leaves the page, not when the tab is merely hidden.
|
|
150
|
+
- `track`, `identify` and `page` made before initialization are buffered and keep the time they were called. After `destroy()` or `optOut()` they are dropped.
|
|
151
|
+
- `page()` is meant for apps that turn the `pageview` collector off. The automatic collector already reports route changes.
|
|
152
|
+
- `wheel` and `touchmove` events are throttled to one per 100 ms, and text selection changes are debounced.
|
|
153
|
+
- `optOut()` also removes the stored user id, external id, session and buffered events, and takes effect in other open tabs. A Do Not Track or Global Privacy Control change is honored when the tab becomes visible again.
|
|
154
|
+
- Calling `init()` right after `destroy()` (for example React StrictMode or a config change) is safe: teardown is immediate and a tracker destroyed before it finishes starting never starts.
|
|
155
|
+
|
|
156
|
+
## Events and transport
|
|
157
|
+
|
|
158
|
+
Every event has `type`, `timestamp`, `url`, `userAgent`, `sessionId`, `userId` and optionally `referrer` and `externalUserId`. `session_start` also carries the device details. Events are batched (50 per batch, flushed every 5 s), sent as `text/plain` JSON `{ apiKey, events }`, retried with backoff on 5xx/429/408, dropped on other 4xx, and flushed with `sendBeacon` when the page is hidden or unloaded. If the browser is offline, events are kept in `localStorage` and restored on the next visit.
|
|
159
|
+
|
|
160
|
+
Sessions end after 30 minutes without activity. `session_end` is sent when the page is hidden or unloaded and carries the latest totals for that session, so use the last one per `sessionId`.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";(()=>{var Gt=Object.create;var ve=Object.defineProperty;var Yt=Object.getOwnPropertyDescriptor;var Wt=Object.getOwnPropertyNames;var jt=Object.getPrototypeOf,Qt=Object.prototype.hasOwnProperty;var qt=(t=>typeof require<"u"?require:typeof Proxy<"u"?new Proxy(t,{get:(e,n)=>(typeof require<"u"?require:e)[n]}):t)(function(t){if(typeof require<"u")return require.apply(this,arguments);throw Error('Dynamic require of "'+t+'" is not supported')});var Zt=(t,e,n,r)=>{if(e&&typeof e=="object"||typeof e=="function")for(let o of Wt(e))!Qt.call(t,o)&&o!==n&&ve(t,o,{get:()=>e[o],enumerable:!(r=Yt(e,o))||r.enumerable});return t};var Jt=(t,e,n)=>(n=t!=null?Gt(jt(t)):{},Zt(e||!t||!t.__esModule?ve(n,"default",{value:t,enumerable:!0}):n,t));var N={preset:"standard",debounceMs:100,idleTimeoutMs:3e4,scrollDepthThresholds:[25,50,75,100],privacy:{respectDoNotTrack:!0,elementText:!0,formValues:!1,clipboardText:!1,searchTerms:!1,fingerprint:!1}},be={search:{inputSelector:'input[type="search"], input[name*="search"], input[name*="query"], input[name="q"]',resultsCountSelector:".results-count, .search-results-count, [data-results-count], .total-results",resultItemSelector:".search-result, .result-item, .product-item, .item"},frustration:{rageClickCount:3,rageClickWindowMs:2e3,deadClickWindowMs:500,clickableSelector:".btn, .button, .clickable"}},we=["keystroke","mouseMove","clipboard","textSelection","inputChange","formSubmit"],q=1800*1e3,f={EVENTS:"indeks_events",USER_ID:"indeks_user_id",LAST_VISIT:"indeks_last_visit",LAST_SEARCH:"indeks_last_search",OPT_OUT:"indeks_opt_out",EXTERNAL_ID:"indeks_external_id",SESSION_ID:"indeks_session_id"},y={DEFAULT_BATCH_SIZE:50,AUTO_FLUSH_INTERVAL:5e3,MAX_BATCH_SIZE:100,MIN_BATCH_SIZE:1,MAX_QUEUE_SIZE:1e3,MAX_EVENT_QUEUE_SIZE:1e3,RETRY_BASE_MS:1e3,RETRY_MAX_MS:3e4,KEEPALIVE_MAX_BODY_BYTES:6e4,MAX_PERSISTED_EVENTS:500},ke=["password","passwd","secret","apikey","authorization","bearer","csrf","accesstoken","refreshtoken","idtoken","socialsecurity","taxid","creditcard","cardnumber","cardnum","cardexpiry","accountnumber","routingnumber","dateofbirth","birthdate","passport","nationalid","driverslicense","licensenumber","mothersmaiden","securityanswer","onetimecode","streetaddress","postalcode","zipcode","emailaddress","ccnumber","cardno","securitycode","expdate","sessionid","authkey","credential","birthday","passcode","taxnumber","mobile","address","username","fullname","phonenumber","telephone","email","phone"],Te=["pwd","pin","ssn","ein","dob","cc","cvv","cvc","otp","iban","token","zip","tel","postal","expiry","cardholder","jwt","pass","mail","auth","ticket"],Mr=[...ke,...Te],en=["token","access_token","id_token","refresh_token","code","state","session","sid","key","api_key","apikey","password","email","signature","sig","session_id","sessionid","auth","auth_key","authkey","jwt","ticket","credential","passcode","pass","q","query","search","s","keyword","keywords","term","terms","text"],tn=["ref","referrer","source"],v="[redacted]",nn=["id","class","href","src","alt","title","type","role","name","aria-label","data-testid"],H={MIN_API_KEY_LENGTH:10,MAX_DEBOUNCE_MS:1e4,MAX_IDLE_TIMEOUT_MS:36e5,MAX_TEXT_LENGTH:100,MAX_SELECTION_LENGTH:200};function rn(t){try{return new URL(t),!0}catch{return!1}}function Se(){return typeof globalThis<"u"?globalThis.crypto:void 0}function on(){let t=Se();if(t?.randomUUID)return t.randomUUID().replace(/-/g,"").substring(0,13);if(t?.getRandomValues){let e=new Uint8Array(8);return t.getRandomValues(e),Array.from(e).map(n=>n.toString(36).padStart(2,"0")).join("").substring(0,13)}return Math.random().toString(36).substring(2,15)}function Z(t=""){let e=`${Date.now()}_${on()}`;return t?`${t}_${e}`:e}function J(){let t=Se();return t?.randomUUID?t.randomUUID():Z("indeks")}function Ie(t,e){let n,r=((...o)=>{n!==void 0&&clearTimeout(n),n=setTimeout(()=>{n=void 0,t(...o)},e)});return r.cancel=()=>{n!==void 0&&clearTimeout(n),n=void 0},r}function Ce(t,e){try{return JSON.parse(t)}catch{return e}}var x=(t=>(t[t.DEBUG=0]="DEBUG",t[t.INFO=1]="INFO",t[t.WARN=2]="WARN",t[t.ERROR=3]="ERROR",t))(x||{}),sn={0:"debug",1:"info",2:"warn",3:"error"},U=class{constructor(t={}){this.options={level:1,prefix:"[Indeks]",enableConsole:!0,...t}}debug(t,...e){this.log(0,t,e)}info(t,...e){this.log(1,t,e)}warn(t,...e){this.log(2,t,e)}error(t,...e){this.log(3,t,e)}setConsoleEnabled(t){this.options.enableConsole=t}log(t,e,n){!this.options.enableConsole||t<this.options.level||console[sn[t]](`${this.options.prefix} ${e}`,...n)}},an=6,ln=200,ye=2e4,cn=new Set(["__proto__","constructor","prototype"]);function dn(t){return t.toLowerCase().replace(/[^a-z0-9]/g,"")}function un(t){return t.replace(/([a-z0-9])([A-Z])/g,"$1 $2").replace(/([A-Z]+)([A-Z][a-z])/g,"$1 $2").split(/[^a-zA-Z0-9]+/).flatMap(e=>e.split(/(?<=[a-zA-Z])(?=[0-9])/)).map(e=>e.toLowerCase()).filter(Boolean)}function I(t){if(!t||typeof t!="string")return!1;let e=dn(t);if(!e)return!1;if(ke.some(r=>e.includes(r)))return!0;let n=new Set(un(t));return Te.some(r=>n.has(r))}function C(t){return typeof t!="string"?"":t.replace(/<[^>]*>/g,"").replace(/\p{Cc}/gu,"").trim()}var pn=4e3,fn=100;function M(t){let e=new WeakSet,n=(o,i)=>{switch(typeof o){case"string":return w(o).slice(0,pn);case"bigint":return o.toString();case"function":case"symbol":case"undefined":return;case"number":case"boolean":return o}if(o===null)return null;if(i>=an)return v;let s=o;if(e.has(s))return"[circular]";if(e.add(s),s instanceof Date)return Number.isNaN(s.getTime())?null:s.toISOString();if(s instanceof Error)return{name:s.name,message:w(s.message)};if(Array.isArray(s))return s.slice(0,fn).map(m=>n(m,i+1)??null);let a;try{a=Object.entries(s)}catch{return"[unserializable]"}let l={},c=0;for(let[m,h]of a){if(cn.has(m))continue;if(++c>ln)break;let E=I(m)?v:n(h,i+1);E!==void 0&&(l[m]=E)}return l};if(!t||typeof t!="object")return{};let r=n(t,0);return r&&typeof r=="object"?r:{}}function hn(t){return!t||typeof t!="string"?!1:t.trim().length>=H.MIN_API_KEY_LENGTH}var mn=/[A-Z0-9._%+-]{1,64}@[A-Z0-9.-]{1,255}\.[A-Z]{2,24}/gi,_e=/[A-Z0-9._%+-]{1,64}@[A-Z0-9.-]{1,255}\.[A-Z]{2,24}/i,gn=/^[A-Za-z0-9_-]{32,}$/,vn=/\b(?:\d[ -]?){13,19}\b/g,bn=/\beyJ[\w-]+\.[\w-]+\.[\w-]+\b/g,yn=/\bBearer\s+[\w.~+/=-]+/gi,En=/https?:\/\/[^\s"'<>)]+/gi,wn=/^#!?\//;function kn(t){let e=t.toLowerCase();return e.startsWith("utm_")||tn.includes(e)?!1:en.includes(e)||I(t)}function Ae(t){for(let[e,n]of Array.from(t.entries()))(kn(e)||_e.test(n))&&t.set(e,v)}function Tn(t){return gn.test(t)&&/\d/.test(t)&&/[A-Za-z]/.test(t)}function Sn(t){return t.split("/").map(e=>{let n;try{n=decodeURIComponent(e)}catch{n=e}return _e.test(n)||Tn(n)?v:e}).join("/")}function ee(t){if(!t||!wn.test(t))return"";let e=t.indexOf("?");if(e===-1)return t;let n=new URLSearchParams(t.slice(e+1));return Ae(n),`${t.slice(0,e)}?${n.toString()}`}function d(t){if(!t)return"";let e;try{e=new URL(t,typeof location<"u"?location.href:void 0)}catch{return""}return e.protocol!=="http:"&&e.protocol!=="https:"?`${e.protocol}${v}`:(e.username="",e.password="",e.pathname=Sn(e.pathname),Ae(e.searchParams),e.hash=ee(e.hash),e.toString())}function te(t){let e=d(t);if(!e)return"";let n=new URL(e);return n.pathname+n.search}function w(t){return t?(t.length>ye?t.slice(0,ye):t).replace(En,n=>d(n)||v).replace(mn,v).replace(bn,v).replace(yn,v).replace(vn,v):""}var In=new Set(["alt","title","aria-label"]);function Me(t,e={}){let n=e.includeText!==!1,r={};for(let o of t){let i=o.name.toLowerCase();i==="value"||!n&&In.has(i)||!(nn.includes(i)||i.startsWith("data-indeks-"))||(I(o.name)?r[o.name]=v:i==="href"||i==="src"?r[o.name]=d(o.value):r[o.name]=w(o.value))}return r}var F=["click","doubleClick","contextMenu","mousePress","hover","mouseMove","wheel","touch","dragDrop","keystroke","scroll","scrollDepth","resize","fullscreen","orientation","idle","pageview","pageLoad","pageLeave","pageLifecycle","beforeUnload","hashChange","popState","visibility","windowFocus","tabFocus","session","formSubmit","inputChange","fieldFocus","formAbandon","formError","clipboard","textSelection","search","frustration","download","outboundLink","print","share","media","mediaProgress","error","resourceError","networkStatus","networkChange","performance"],Cn=["click","pageview","session","error","pageLeave","scrollDepth","outboundLink","download","performance"],_n=["keystroke","mouseMove","hover","mousePress","textSelection"];function An(t){let e=n=>t==="minimal"?Cn.includes(n):t==="full"?!0:!_n.includes(n);return Object.fromEntries(F.map(n=>[n,e(n)]))}function P(t){return Object.fromEntries(Object.entries(t??{}).filter(([,e])=>e!==void 0))}function Le(t){return{apiKey:t.apiKey,endpoint:t.endpoint,localOnly:t.localOnly===!0,debug:t.debug===!0,collectors:{...An(t.preset??N.preset),...P(t.collectors)},privacy:{...N.privacy,...P(t.privacy)},collectorOptions:{search:{...be.search,...P(t.collectorOptions?.search)},frustration:{...be.frustration,...P(t.collectorOptions?.frustration)}},debounceMs:t.debounceMs??N.debounceMs,idleTimeoutMs:t.idleTimeoutMs??N.idleTimeoutMs,scrollDepthThresholds:t.scrollDepthThresholds??N.scrollDepthThresholds}}var Mn=/^\/(?!\/)/;function Ee(t,e,n,r){n!==void 0&&(typeof n!="number"||Number.isNaN(n)?t.push(`${e} must be a number`):n<0?t.push(`${e} must be non-negative`):n>r&&t.push(`${e} should not exceed ${r/1e3} seconds`))}function Ne(t){let e=[];t.apiKey?typeof t.apiKey!="string"?e.push("API key must be a string"):hn(t.apiKey)||e.push(`API key appears to be too short (minimum ${H.MIN_API_KEY_LENGTH} characters)`):e.push("API key is required"),t.debug!==void 0&&typeof t.debug!="boolean"&&e.push("debug must be a boolean"),t.preset!==void 0&&!["minimal","standard","full"].includes(t.preset)&&e.push('preset must be "minimal", "standard" or "full"');for(let[n,r]of Object.entries(t.collectors??{}))F.includes(n)?r!==void 0&&typeof r!="boolean"&&e.push(`collectors.${n} must be a boolean`):e.push(`unknown collector "${n}"`);for(let[n,r]of Object.entries(t.privacy??{}))r!==void 0&&typeof r!="boolean"&&e.push(`privacy.${n} must be a boolean`);if(Ee(e,"debounceMs",t.debounceMs,H.MAX_DEBOUNCE_MS),Ee(e,"idleTimeoutMs",t.idleTimeoutMs,H.MAX_IDLE_TIMEOUT_MS),t.scrollDepthThresholds!==void 0){let n=t.scrollDepthThresholds;Array.isArray(n)&&n.every(o=>typeof o=="number"&&o>0&&o<=100)||e.push("scrollDepthThresholds must be an array of numbers in (0, 100]")}for(let[n,r]of Object.entries(t.collectorOptions??{})){if(n!=="search"&&n!=="frustration"){e.push(`unknown collectorOptions group "${n}"`);continue}for(let[o,i]of Object.entries(r??{})){let s=o.endsWith("Selector");i!==void 0&&typeof i!=(s?"string":"number")&&e.push(`collectorOptions.${n}.${o} must be a ${s?"string":"number"}`)}}return t.endpoint!==void 0&&(typeof t.endpoint!="string"?e.push("endpoint must be a string"):!rn(t.endpoint)&&!Mn.test(t.endpoint)&&e.push("endpoint must be an absolute URL or a path starting with /")),e}function xe(t){if(!t||typeof t!="object")return!1;let e=t;return typeof e.type=="string"&&e.type!==""&&typeof e.timestamp=="number"&&typeof e.sessionId=="string"&&e.sessionId!==""&&typeof e.userId=="string"&&e.userId!==""&&typeof e.url=="string"&&e.url!==""}function Ln(t){let e={browserName:"Unknown",browserVersion:"",browserEngine:"Unknown",browserEngineVersion:"",osName:"Unknown",osVersion:"",deviceType:"desktop",deviceVendor:"",deviceModel:"",isBot:!1};if(!t)return e;let n=t.toLowerCase(),r=["bot","crawler","spider","scraper","headless","phantom","selenium","puppeteer","playwright","googlebot","bingbot","yandexbot","duckduckbot","slurp","baiduspider","facebookexternalhit","twitterbot","linkedinbot","slackbot","discordbot","telegrambot","whatsapp","applebot","semrushbot","ahrefsbot","mj12bot","dotbot","petalbot","bytespider"];e.isBot=r.some(c=>n.includes(c));let o=[[/edg(?:e|a|ios)?\/(\d+[\d.]*)/i,"Edge"],[/opr\/(\d+[\d.]*)/i,"Opera"],[/opera.*version\/(\d+[\d.]*)/i,"Opera"],[/samsungbrowser\/(\d+[\d.]*)/i,"Samsung Browser"],[/ucbrowser\/(\d+[\d.]*)/i,"UC Browser"],[/brave\/(\d+[\d.]*)/i,"Brave"],[/vivaldi\/(\d+[\d.]*)/i,"Vivaldi"],[/yabrowser\/(\d+[\d.]*)/i,"Yandex"],[/firefox\/(\d+[\d.]*)/i,"Firefox"],[/fxios\/(\d+[\d.]*)/i,"Firefox"],[/crios\/(\d+[\d.]*)/i,"Chrome"],[/chrome\/(\d+[\d.]*)/i,"Chrome"],[/chromium\/(\d+[\d.]*)/i,"Chromium"],[/version\/(\d+[\d.]*).*safari/i,"Safari"],[/safari\/(\d+[\d.]*)/i,"Safari"],[/msie\s(\d+[\d.]*)/i,"Internet Explorer"],[/trident.*rv:(\d+[\d.]*)/i,"Internet Explorer"]];for(let[c,m]of o){let h=t.match(c);if(h){e.browserName=m,e.browserVersion=h[1]||"";break}}if(t.includes("AppleWebKit")){e.browserEngine="WebKit";let c=t.match(/applewebkit\/(\d+[\d.]*)/i);e.browserEngineVersion=c?.[1]||"",t.includes("Chrome")&&!t.includes("Edge")&&(e.browserEngine="Blink")}else if(t.includes("Gecko")){e.browserEngine="Gecko";let c=t.match(/gecko\/(\d+[\d.]*)/i);e.browserEngineVersion=c?.[1]||""}else if(t.includes("Trident")){e.browserEngine="Trident";let c=t.match(/trident\/(\d+[\d.]*)/i);e.browserEngineVersion=c?.[1]||""}else if(t.includes("Presto")){e.browserEngine="Presto";let c=t.match(/presto\/(\d+[\d.]*)/i);e.browserEngineVersion=c?.[1]||""}let i=[[/windows phone (\d+[\d.]*)/i,"Windows Phone"],[/windows nt 10\.0/i,"Windows",10],[/windows nt 6\.3/i,"Windows",8.1],[/windows nt 6\.2/i,"Windows",8],[/windows nt 6\.1/i,"Windows",7],[/windows nt 6\.0/i,"Windows",6],[/windows nt 5\.1/i,"Windows",5.1],[/iphone os (\d+[._\d]*)/i,"iOS"],[/ipad.*os (\d+[._\d]*)/i,"iPadOS"],[/mac os x (\d+[._\d]*)/i,"macOS"],[/android (\d+[\d.]*)/i,"Android"],[/cros/i,"Chrome OS"],[/linux/i,"Linux"],[/ubuntu/i,"Ubuntu"],[/fedora/i,"Fedora"],[/debian/i,"Debian"],[/freebsd/i,"FreeBSD"]];for(let[c,m,h]of i){let E=t.match(c);if(E){e.osName=m,h!==void 0?e.osVersion=String(h):E[1]&&(e.osVersion=E[1].replace(/_/g,"."));break}}let s=/android|webos|iphone|ipod|blackberry|iemobile|opera mini|mobile|phone/i;/ipad|tablet|playbook|silk|kindle|android(?!.*mobile)/i.test(t)?e.deviceType="tablet":s.test(t)?e.deviceType="mobile":e.deviceType="desktop";let l=[[/iphone/i,"Apple","iPhone"],[/ipad/i,"Apple","iPad"],[/ipod/i,"Apple","iPod"],[/macintosh/i,"Apple","Mac"],[/samsung[- ]?(gt|sm|sgh|sch|sph)-?([a-z0-9]+)/i,"Samsung"],[/samsung/i,"Samsung"],[/\b(sm-[a-z0-9]+)/i,"Samsung"],[/\bhuawei[- ]?([a-z0-9]+)/i,"Huawei"],[/\bxiaomi[- ]?([a-z0-9]+)/i,"Xiaomi"],[/\bredmi[- ]?([a-z0-9]+)/i,"Xiaomi","Redmi"],[/\boppo[- ]?([a-z0-9]+)/i,"OPPO"],[/\bvivo[- ]?([a-z0-9]+)/i,"Vivo"],[/\boneplus[- ]?([a-z0-9]+)/i,"OnePlus"],[/\bpixel[- ]?(\d+)/i,"Google","Pixel"],[/\bnexus[- ]?([a-z0-9]+)/i,"Google","Nexus"],[/\b(?:motorola|moto)[- ]?([a-z0-9]+)/i,"Motorola"],[/\blg[- ]?([a-z0-9]+)/i,"LG"],[/\bsony[- ]?([a-z0-9]+)/i,"Sony"],[/\bhtc[- ]?([a-z0-9]+)/i,"HTC"],[/\bnokia[- ]?([a-z0-9]+)/i,"Nokia"],[/surface/i,"Microsoft","Surface"],[/xbox/i,"Microsoft","Xbox"],[/playstation/i,"Sony","PlayStation"],[/kindle/i,"Amazon","Kindle"]];for(let[c,m,h]of l){let E=t.match(c);if(E){e.deviceVendor=m,h?e.deviceModel=h:E[1]&&(e.deviceModel=E[1].toUpperCase());break}}return e}function ne(){if(typeof window>"u"||typeof navigator>"u")throw new Error("getDeviceInfo must be called in browser environment");let t=navigator.userAgent,e=Ln(t),n=navigator,r=n.connection??null,o;try{o=Intl.DateTimeFormat().resolvedOptions().timeZone}catch{o="Unknown"}let i;try{i=Array.from(navigator.languages||[navigator.language])}catch{i=[navigator.language||"en"]}return{browserName:e.browserName,browserVersion:e.browserVersion,browserEngine:e.browserEngine,browserEngineVersion:e.browserEngineVersion,osName:e.osName,osVersion:e.osVersion,deviceType:e.deviceType,deviceVendor:e.deviceVendor,deviceModel:e.deviceModel,screenWidth:window.screen?.width||0,screenHeight:window.screen?.height||0,screenColorDepth:window.screen?.colorDepth||0,pixelRatio:window.devicePixelRatio||1,viewportWidth:window.innerWidth||0,viewportHeight:window.innerHeight||0,timezone:o,timezoneOffset:new Date().getTimezoneOffset(),language:navigator.language||"en",languages:i,deviceMemory:n.deviceMemory||null,hardwareConcurrency:navigator.hardwareConcurrency||null,maxTouchPoints:navigator.maxTouchPoints||0,touchSupport:"ontouchstart"in window||navigator.maxTouchPoints>0,connectionType:r?.type||null,connectionEffectiveType:r?.effectiveType||null,connectionDownlink:r?.downlink||null,connectionRtt:r?.rtt||null,platform:n.userAgentData?.platform||e.osName,cookiesEnabled:navigator.cookieEnabled,doNotTrack:navigator.doNotTrack==="1",online:navigator.onLine,isBot:e.isBot}}function Nn(t){return t instanceof DOMException&&t.name==="QuotaExceededError"}var V=class{constructor(){this.key=f.EVENTS}async store(e){this.replace([...await this.retrieve(),...e])}replace(e){let n=e.slice(-y.MAX_PERSISTED_EVENTS);for(;n.length;)try{localStorage.setItem(this.key,JSON.stringify(n));return}catch(r){if(!Nn(r))return;n=n.slice(Math.ceil(n.length/2))}this.removeKey()}async retrieve(){return this.read()}append(e){this.replace([...this.read(),...e])}read(){try{let e=localStorage.getItem(this.key),n=e?Ce(e,[]):[];return Array.isArray(n)?n:[]}catch{return[]}}async clear(){this.removeKey()}removeKey(){try{localStorage.removeItem(this.key)}catch{return}}};var xn="text/plain;charset=UTF-8",z=class extends Error{constructor(n,r){super(r);this.status=n}get retryable(){return this.status>=500||this.status===408||this.status===429}},X=class{constructor(e,n=new V){this.config=e;this.storage=n;this.batchQueue=[];this.flushTimer=null;this.flushing=!1;this.consecutiveFailures=0;this.nextRetryAt=0;this.endpointErrorLogged=!1;this.droppedEvents=0;this.closed=!1;this.epoch=0;this.listeningForOnline=!1;this.handleOnline=()=>{this.flush().catch(e=>this.logger.warn("Flush after reconnect failed:",e))};this.logger=new U({enableConsole:e.debug,level:x.INFO})}open(){this.closed=!1,this.consecutiveFailures=0,this.nextRetryAt=0}close(){this.flushSync(),this.stop()}discard(){this.batchQueue=[],this.stop()}stop(){this.closed=!0,this.epoch++,this.flushing=!1,this.cancelTimer(),this.listeningForOnline&&typeof window<"u"&&window.removeEventListener("online",this.handleOnline),this.listeningForOnline=!1}resolveEndpoint(){return this.config.endpoint?this.config.endpoint:(this.endpointErrorLogged||(this.endpointErrorLogged=!0,console.error("[Indeks] No `endpoint` configured. Indeks is self-hosted, so there is no default ingestion server: set `endpoint` to your own Indeks collect URL (e.g. https://analytics.example.com/api/v1/collect). No events will be sent until it is set.")),null)}toApiEvent(e){let{type:n,timestamp:r,url:o,userAgent:i,sessionId:s,userId:a,referrer:l,...c}=e;return{type:n,url:o,sessionId:s,userId:a,userAgent:i,referrer:l||d(document.referrer)||void 0,properties:M(c),timestamp:r}}serialize(e){let n=[];for(let r of e)try{let o=this.toApiEvent(r);JSON.stringify(o),n.push(o)}catch{this.logger.warn(`Dropping ${r.type} event that cannot be serialized`)}return n.length?JSON.stringify({apiKey:this.config.apiKey,events:n}):null}byteLength(e){return typeof TextEncoder<"u"?new TextEncoder().encode(e).length:e.length}enqueue(e,n=!1){n?this.batchQueue.unshift(...e):this.batchQueue.push(...e);let r=this.batchQueue.length-y.MAX_QUEUE_SIZE;r>0&&(this.batchQueue.splice(0,r),this.droppedEvents+=r,this.logger.warn(`Send queue exceeded ${y.MAX_QUEUE_SIZE} events; dropped ${this.droppedEvents} oldest events in total`))}backoffMs(){let e=y.RETRY_BASE_MS*2**(this.consecutiveFailures-1),n=Math.min(e,y.RETRY_MAX_MS);return Math.round(n*(.5+Math.random()*.5))}scheduleFlush(e){this.closed||(this.cancelTimer(),this.flushTimer=setTimeout(()=>{this.flushTimer=null,this.flush().catch(n=>this.logger.warn("Scheduled flush failed:",n))},e))}cancelTimer(){this.flushTimer&&(clearTimeout(this.flushTimer),this.flushTimer=null)}listenForOnline(){this.listeningForOnline||typeof window>"u"||(window.addEventListener("online",this.handleOnline),this.listeningForOnline=!0)}async send(e){if(!e.length)return;if(this.config.localOnly){this.logger.info(`Local only: skipped sending ${e.length} events`);return}let n=this.resolveEndpoint();if(!n)return;let r=this.serialize(e);if(!r)return;let o=await fetch(n,{method:"POST",body:r,keepalive:this.byteLength(r)<=y.KEEPALIVE_MAX_BODY_BYTES});if(!o.ok){let i=await o.json().catch(()=>({}));throw new z(o.status,`HTTP ${o.status}: ${i.message||o.statusText}`)}this.logger.info(`Sent ${e.length} events`)}async batch(e){if(!this.closed){if(this.listenForOnline(),this.enqueue(e),this.batchQueue.length>=y.DEFAULT_BATCH_SIZE){await this.flush().catch(n=>this.logger.warn("Flush failed:",n));return}this.flushTimer||this.scheduleFlush(y.AUTO_FLUSH_INTERVAL)}}async flush(){if(this.closed||!this.batchQueue.length||this.flushing||typeof navigator<"u"&&navigator.onLine===!1)return;let e=this.nextRetryAt-Date.now();if(e>0){this.scheduleFlush(e);return}let n=this.epoch;this.flushing=!0,this.cancelTimer();try{for(;this.batchQueue.length;){let r=this.batchQueue.splice(0,y.MAX_BATCH_SIZE);try{await this.send(r)}catch(o){if(n!==this.epoch)return;if(o instanceof z&&!o.retryable){this.logger.error(`Dropped ${r.length} events:`,o.message);continue}throw this.enqueue(r,!0),this.consecutiveFailures++,this.nextRetryAt=Date.now()+this.backoffMs(),this.scheduleFlush(this.nextRetryAt-Date.now()),o}if(n!==this.epoch)return}this.consecutiveFailures=0,this.nextRetryAt=0}finally{n===this.epoch&&(this.flushing=!1)}}flushSync(){if(!this.batchQueue.length)return;this.cancelTimer();let e=this.batchQueue.splice(0,this.batchQueue.length);if(this.config.localOnly)return;let n=this.resolveEndpoint();if(!n)return;if(typeof navigator<"u"&&navigator.onLine===!1){this.storage.append(e);return}let r=this.serialize(e);if(!r)return;let o=this.byteLength(r)<=y.KEEPALIVE_MAX_BODY_BYTES;if(o&&typeof navigator?.sendBeacon=="function")try{let i=new Blob([r],{type:xn});if(navigator.sendBeacon(n,i))return}catch{this.logger.debug("sendBeacon failed, falling back to fetch")}fetch(n,{method:"POST",body:r,keepalive:o}).catch(()=>this.storage.append(e))}async restorePersisted(){let e=await this.storage.retrieve();return e.length?(await this.storage.clear(),this.enqueue(e,!0),this.logger.info(`Restored ${e.length} events from offline buffer`),e.length):0}getBatchSize(){return this.batchQueue.length}clearBatch(){this.batchQueue=[],this.cancelTimer()}};var re=100,Dn=2e3,On=["password","hidden","email","tel","number"],Rn=["cc-","password","one-time-code"],Re="[data-indeks-mask], [data-indeks-ignore]",Pe='button, a, input, select, textarea, label, summary, details, [role="button"], [role="link"], [role="menuitem"], [role="tab"], [role="checkbox"], [role="radio"], [onclick], [data-action], [tabindex]:not([tabindex="-1"]), [contenteditable="true"], [ng-click], [data-bs-toggle], [data-toggle]';function p(t){return t?t instanceof Element?t:t instanceof Node?t.parentElement:null:null}function L(t){return typeof t.className=="string"?t.className:t.className?.baseVal||""}function g(t){return{tagName:t.tagName.toLowerCase(),className:L(t),id:t.id||""}}function _(t){let e=(t.type||"").toLowerCase();if(On.includes(e))return!0;let n=(t.getAttribute("autocomplete")||"").toLowerCase();if(Rn.some(o=>n.includes(o)))return!0;let r=t.name||"";return I(r)||!!t.id&&I(t.id)}function B(t){return I(t)?v:t}function S(t){let e=t;return B(e.name||e.id||"")}function He(t){return t.length?`[len:${t.length}]`:"[empty]"}function Ue(t){return t===" "||t==="Tab"||t==="Enter"?"whitespace":["Shift","Control","Alt","Meta","CapsLock"].includes(t)?"modifier":t.length===1?"printable":"navigation"}function b(t){return t.closest(Re)!==null}function u(t,e=re){return t?w(t.slice(0,e*4).replace(/\s+/g," ").trim()).substring(0,e):""}function De(t){return Array.from(t.childNodes).filter(e=>e.nodeType===Node.TEXT_NODE).map(e=>e.textContent?.trim()).filter(Boolean).join(" ")}function Fe(t){return(t.textContent??"").length>Dn?De(t):t.innerText||De(t)}function Pn(t,e){if(!e||b(t))return"";let n=t.getAttribute("aria-label");return u(n||Fe(t))}function oe(t){if(!t||!t.rangeCount)return!1;for(let e of Array.from(document.querySelectorAll(Re)))if(t.containsNode(e,!0))return!0;return!1}function D(t,e=!0){if(b(t))return{...g(t),textContent:"",attributes:{}};let n=Me(Array.from(t.attributes).map(h=>({name:h.name,value:h.value})),{includeText:e}),r=e,o=t.closest("a");o?.href&&(n.__href=d(o.href),r&&(n.__linkText=u(o.textContent)));let i=t.closest("form");i&&(n.__formAction=d(i.action),n.__formMethod=i.method||"",n.__formId=i.id||"");let s=t.tagName==="INPUT"&&["button","submit","reset"].includes(t.type);if((t.tagName==="BUTTON"||s)&&(n.__buttonType=t.type||""),t.tagName==="IMG"){let h=t;n.__imgSrc=d(h.src),n.__imgAlt=r?u(h.alt):""}let a=t.closest('button, a, [role="button"], [onclick]');a&&a!==t&&(n.__parentTagName=a.tagName.toLowerCase(),n.__parentId=a.id||"",n.__parentClassName=L(a));let l=t.getAttribute("aria-label")||t.closest("[aria-label]")?.getAttribute("aria-label");l&&r&&(n.__ariaLabel=u(l));let c=t.getAttribute("data-testid")||t.getAttribute("data-cy")||t.getAttribute("data-test");c&&(n.__testId=c);let m=Pn(t,e);if(r&&m.length<3){let h=t.closest("p, h1, h2, h3, h4, h5, h6, li, td, th, label, span, div, button, a");if(h&&h!==t&&!b(h)){let E=u(Fe(h));E&&(n.__parentText=E)}}return{...g(t),textContent:m,attributes:n}}function O(){let t=document.documentElement,e=document.body,n=window.scrollY||t.scrollTop||0,r=window.scrollX||t.scrollLeft||0,o=Math.max(e?.scrollHeight??0,e?.offsetHeight??0,t.clientHeight,t.scrollHeight,t.offsetHeight),i=window.innerHeight,s=o-i,a=s>0?Math.min(100,Math.max(0,Math.round(n/s*100))):0;return{scrollTop:n,scrollLeft:r,documentHeight:o,viewportHeight:i,percentage:a}}function ie(t){try{return new URL(t).hostname}catch{return""}}function Hn(t){return t.toLowerCase().replace(/^www\./,"")}var Un=new Set(["co","com","org","net","gov","edu","ac"]);function Oe(t){let e=Hn(t).split(".");if(e.length<=2||/^[\d.]+$/.test(t)||t.includes(":"))return e.join(".");let n=e[e.length-1],r=e[e.length-2],o=n.length===2&&Un.has(r)?3:2;return e.slice(-o).join(".")}function K(t,e){return Oe(t)===Oe(e)}function k(t,e){try{return window[t].getItem(e)}catch{return null}}function T(t,e,n){try{window[t].setItem(e,n)}catch{return}}function se(){return navigator.connection??null}var Ve=t=>{t.on(document,"click",e=>{let n=p(e.target);n&&t.emit({type:"click",element:D(n,t.captureText()),coordinates:{x:e.pageX,y:e.pageY,clientX:e.clientX,clientY:e.clientY}})},!0)};function ze(t,e){let{tagName:n,className:r,id:o,textContent:i}=D(e,t.captureText());return{tagName:n,className:r,id:o,textContent:i}}var Xe=t=>{t.on(document,"dblclick",e=>{let n=p(e.target);n&&t.emit({type:"dblclick",element:ze(t,n),coordinates:{x:e.pageX,y:e.pageY}})})},Be=t=>{t.on(document,"contextmenu",e=>{let n=p(e.target);n&&t.emit({type:"contextmenu",element:ze(t,n),coordinates:{x:e.pageX,y:e.pageY}})})},Ke=t=>{let e=n=>r=>{let o=p(r.target);o&&t.emit({type:n,button:r.button,buttons:r.buttons,element:g(o),coordinates:{x:r.pageX,y:r.pageY}})};t.on(document,"mousedown",e("mousedown")),t.on(document,"mouseup",e("mouseup"))},$e=t=>{let e=n=>r=>{let o=p(r.target);o&&t.emit({type:n,element:g(o),coordinates:{x:r.pageX,y:r.pageY}})};t.on(document,"mouseenter",e("mouseenter"),!0),t.on(document,"mouseleave",e("mouseleave"),!0)},Ge=t=>{let e=t.debounced(n=>{t.emit({type:"mousemove",coordinates:{x:n.pageX,y:n.pageY,clientX:n.clientX,clientY:n.clientY}})});t.on(document,"mousemove",n=>e(n),{passive:!0})},Ye=100,We=t=>{t.on(document,"wheel",t.throttled(e=>{t.emit({type:"wheel",deltaX:e.deltaX,deltaY:e.deltaY,deltaZ:e.deltaZ,deltaMode:e.deltaMode,coordinates:{x:e.pageX,y:e.pageY}})},Ye),{passive:!0})},je=t=>{for(let e of["touchstart","touchend","touchmove"]){let n=o=>{let i=p(o.target);i&&t.emit({type:e,touches:Array.from(o.touches).map(s=>({identifier:s.identifier,clientX:s.clientX,clientY:s.clientY,force:s.force})),element:g(i)})},r=e==="touchmove"?t.throttled(n,Ye):n;t.on(document,e,r,{passive:!0})}},Qe=t=>{for(let e of["dragstart","dragend","drop"])t.on(document,e,n=>{let r=p(n.target);r&&t.emit({type:e,dataTransfer:n.dataTransfer?{dropEffect:n.dataTransfer.dropEffect,effectAllowed:n.dataTransfer.effectAllowed,types:Array.from(n.dataTransfer.types)}:void 0,element:g(r),coordinates:{x:n.pageX,y:n.pageY}})})},qe=t=>{t.on(document,"keydown",e=>{let n=p(e.target);if(!n||n.tagName==="TEXTAREA"||n.isContentEditable||n.getAttribute("contenteditable")!==null||_(n)||b(n))return;let r=n.type;if(n.tagName==="INPUT"&&["search","url"].includes(r))return;let o=Ue(e.key);t.emit({type:"keystroke",keyCategory:o,key:o==="printable"?void 0:C(e.key),code:o==="printable"?void 0:e.code,ctrlKey:e.ctrlKey,shiftKey:e.shiftKey,altKey:e.altKey,metaKey:e.metaKey,target:{...g(n),type:r,name:S(n)}})})};var Ze=t=>{let e=t.debounced(()=>{let n=O();t.emit({type:"scroll",scrollPosition:{x:n.scrollLeft,y:n.scrollTop},documentHeight:n.documentHeight,viewportHeight:n.viewportHeight,scrollPercentage:n.percentage})});t.on(window,"scroll",e,{passive:!0})},Je=t=>{let e=t.debounced(()=>{let{percentage:n}=O();for(let r of t.config.scrollDepthThresholds)n<r||t.page.scrollDepthReached.has(r)||(t.page.scrollDepthReached.add(r),t.emit({type:"scroll_depth",depth:r,timeToDepth:Date.now()-t.page.startTime}))});t.on(window,"scroll",e,{passive:!0})},et=t=>{let e=t.debounced(()=>{t.emit({type:"resize",dimensions:{width:window.outerWidth,height:window.outerHeight,innerWidth:window.innerWidth,innerHeight:window.innerHeight}})});t.on(window,"resize",e)},tt=t=>{t.on(document,"fullscreenchange",()=>{let e=document.fullscreenElement;t.emit({type:"fullscreenchange",isFullscreen:!!e,element:e?g(e):void 0})})},nt=t=>{t.on(window,"orientationchange",()=>{let e=window.screen?.orientation,n=e?e.type.startsWith("landscape"):window.innerWidth>window.innerHeight;t.emit({type:"orientation_change",orientation:n?"landscape":"portrait",angle:e?.angle??0})})},rt=t=>{let e=t.config.idleTimeoutMs,n=!1,r=null,o=s=>{t.hub.cancel(r),r=t.later(i,s)},i=()=>{r=null;let s=e-(Date.now()-t.lifecycle.lastActivityTime);if(s>0){o(s);return}n||(n=!0,t.emit({type:"idle_start"}))};t.lifecycle.onActivity(s=>{n&&(n=!1,t.emit({type:"idle_end",idleDuration:Date.now()-s}),o(e))}),o(e)};var Fn=50;function $(t,e={}){let{page:n}=t;t.emit({type:"pageview",title:u(document.title,200),referrer:(n.previousUrl?d(n.previousUrl):"")||d(document.referrer),...e}),n.previousUrl=window.location.href}var st=t=>{$(t),t.lifecycle.onNavigation(()=>{t.later(()=>$(t),Fn)})};function ot(){return performance.getEntriesByType("navigation")[0]}function ae(t,e){document.readyState==="complete"?e():t.on(window,"load",e)}var at=t=>{ae(t,()=>{let n=ot();t.emit({type:"load",loadTime:Math.round(performance.now()),domInteractive:n?.domInteractive,domComplete:n?.domComplete})});let e=()=>t.emit({type:"DOMContentLoaded",loadTime:Math.round(ot()?.domContentLoadedEventEnd||performance.now())});document.readyState!=="loading"?e():t.on(document,"DOMContentLoaded",e)};function it(t){let e=t.page.timeOnPage();t.emit({type:"pageleave",timeOnPage:e,scrollDepth:t.page.maxScrollDepth,clickCount:t.page.clicks,engaged:e>1e4&&t.page.clicks>2})}var lt=t=>{t.lifecycle.onExit(()=>it(t)),t.lifecycle.onBeforeNavigation(()=>it(t))},ct=t=>{if(!("onfreeze"in document))return;let e=n=>()=>t.emit({type:n});t.on(document,"freeze",e("page_freeze")),t.on(document,"resume",e("page_resume"))},dt=t=>{t.on(window,"beforeunload",()=>{t.emit({type:"beforeunload",timeOnPage:Date.now()-t.page.startTime})})},ut=t=>{let e=n=>{try{return ee(new URL(n).hash)}catch{return""}};t.on(window,"hashchange",n=>{t.emit({type:"hashchange",oldURL:d(n.oldURL),newURL:d(n.newURL),oldHash:e(n.oldURL),newHash:e(n.newURL)})})},pt=t=>{t.on(window,"popstate",e=>{t.emit({type:"popstate",hasState:e.state!==null&&e.state!==void 0})})},ft=t=>{t.lifecycle.onVisibility(e=>{t.emit({type:"visibilitychange",visibilityState:e==="hidden"?"hidden":"visible",hidden:e==="hidden"})})},ht=t=>{let e=n=>()=>t.emit({type:n,hasFocus:n==="focus"});t.on(window,"focus",e("focus")),t.on(window,"blur",e("blur"))},mt=t=>{let e=null;t.lifecycle.onVisibility(n=>{n==="hidden"?(e=Date.now(),t.emit({type:"tab_blur"})):(t.emit({type:"tab_focus",timeAway:e?Date.now()-e:0}),e=null)})};var vt=["INPUT","TEXTAREA","SELECT"];function le(t){return t.id?t.id:`form:nth-child(${Array.from(t.parentElement?.children??[]).indexOf(t)+1})`}function ce(t){return u(C(t))}var bt=t=>{t.on(document,"submit",e=>{let n=p(e.target);if(!n)return;let r=t.config.privacy.formValues,o={},i=n.querySelectorAll("input, textarea, select");for(let s of Array.from(i)){let a=s.name||s.id;if(!a)continue;let l=typeof s.value=="string"?s.value:"",c=_(s)||b(s);o[B(a)]=c?v:r?ce(l):He(l)}t.emit({type:"form_submit",formData:o,formValuesCaptured:r,formAction:d(n.action),formMethod:n.method,element:g(n)})})},yt=t=>{let e=n=>r=>{let o=p(r.target);if(!o)return;let i=typeof o.value=="string"?o.value:"",s=_(o);if(s)return;let a=t.config.privacy.formValues&&!s&&!b(o);t.emit({type:n,element:{...g(o),type:o.type,name:B(o.name||""),value:a?ce(i):void 0,valueLength:i.length},inputType:r.inputType})};t.on(document,"input",e("input")),t.on(document,"change",e("change"))},Et=t=>{let e=(n,r)=>t.on(document,r,o=>{let i=p(o.target);!i||!vt.includes(i.tagName)||t.emit({type:n,element:{...g(i),type:i.type||"",name:S(i)}})},!0);e("field_focus","focus"),e("field_blur","blur")};function gt(t,e,n){for(let[r,o]of Array.from(e)){if(n&&o.form.isConnected)continue;e.delete(r);let i=Array.from(o.fields).filter(s=>s.value).length;i===0&&Date.now()-o.lastInteraction<5e3||t.emit({type:"form_abandon",formId:r,fieldsCompleted:i,totalFields:o.form.querySelectorAll("input, textarea, select").length,timeSpent:Date.now()-o.startTime,lastField:o.lastField||"unknown"})}}var wt=t=>{let e=new Map;t.on(document,"focusin",n=>{let r=p(n.target);if(!r||!vt.includes(r.tagName))return;let o=r.closest("form");if(!o)return;let i=le(o),s=Date.now(),a=e.get(i);a||(a={form:o,startTime:s,fields:new Set,lastInteraction:s,lastField:""},e.set(i,a)),a.fields.add(r),a.lastField=S(r),a.lastInteraction=s}),t.on(document,"submit",n=>{let r=p(n.target);r&&e.delete(le(r))}),t.lifecycle.onExit(n=>{n==="pagehide"&>(t,e,!1)}),t.lifecycle.onNavigation(()=>gt(t,e,!0))},kt=t=>{t.on(document,"invalid",e=>{let n=p(e.target),r=n?.closest("form");!n||!r||t.emit({type:"form_error",formId:le(r),field:S(n),errorType:n.validity.valueMissing?"required":n.validity.typeMismatch?"format":"validation",errorMessage:u(n.validationMessage)})},!0)},Tt=t=>{let e=n=>r=>{let o=p(r.target);if(!o)return;let i=window.getSelection(),s=i?.toString()||"",a=n!=="paste"&&t.config.privacy.clipboardText&&!_(o)&&!b(o)&&!oe(i);t.emit({type:n,element:{...g(o),type:o.type,name:S(o)},text:a?ce(s):void 0,textLength:n!=="paste"?s.length:void 0})};t.on(document,"copy",e("copy")),t.on(document,"paste",e("paste")),t.on(document,"cut",e("cut"))},St=t=>{let e=t.debounced(()=>{let n=window.getSelection(),r=n?.toString()||"";if(!n||!r.length)return;let o=n.anchorNode?.parentElement,i=t.config.privacy.clipboardText&&!(o&&(_(o)||b(o)))&&!oe(n);t.emit({type:"selectionchange",selectedText:i?u(C(r),2*re):void 0,selectedTextLength:r.length,selectionStart:n.anchorOffset,selectionEnd:n.focusOffset,element:o?{...g(o),type:o.type,name:S(o)}:void 0})});t.on(document,"selectionchange",e)};var Vn={timeout:"timeout",hidden:"tab_close",pagehide:"navigation",reset:"reset"},zn=["google.","bing.","yahoo.","duckduckgo.","baidu.","yandex.","ecosia."],Xn=["facebook.","twitter.","t.co","x.com","linkedin.","instagram.","reddit.","pinterest.","tiktok."],Bn=["facebook","twitter","linkedin","instagram","reddit","pinterest","tiktok","youtube"],Kn=["cpc","ppc","paid","paidsearch","display","retargeting"];function de(t,e){return e.some(n=>t.includes(n))}function $n(t){let e=t.get("utm_source")?.toLowerCase(),n=t.get("utm_medium")?.toLowerCase(),r=ie(document.referrer).toLowerCase();return n&&Kn.includes(n)?"paid":n==="email"||e?.includes("email")||e?.includes("newsletter")?"email":n==="social"||e&&de(e,Bn)?"social":n==="organic"?"organic":e?"other":!r||K(r,window.location.hostname)?"direct":de(r,zn)?"organic":de(r,Xn)?"social":"referral"}function It(t){let e=k("localStorage",f.LAST_VISIT),n=e?parseInt(e,10):NaN,r=!Number.isNaN(n),o=new URLSearchParams(window.location.search);t.emit({type:"session_start",device:t.device,referrer:d(document.referrer),referrerDomain:ie(document.referrer),utmSource:u(o.get("utm_source"),100)||void 0,utmMedium:u(o.get("utm_medium"),100)||void 0,utmCampaign:u(o.get("utm_campaign"),100)||void 0,trafficSource:$n(o),landingPage:te(window.location.href),isMobile:t.device.deviceType==="mobile",isTablet:t.device.deviceType==="tablet",isDesktop:t.device.deviceType==="desktop",isNewUser:!r,isReturningUser:r,daysSinceLastVisit:r?Math.floor((Date.now()-n)/864e5):void 0}),T("localStorage",f.LAST_VISIT,Date.now().toString())}function Ct(t,e){let n=t.session.data,r=Date.now()-n.startedAt,o=Math.min(n.activeMs,r);t.emit({type:"session_end",sessionDuration:r,activeTime:o,idleTime:r-o,pagesViewed:n.pageViews,totalClicks:n.clicks,totalScrolls:n.scrolls,exitPage:te(window.location.href),exitType:Vn[e],converted:n.converted,bounce:n.pageViews<=1})}var _t=t=>{t.sessionHooks.start=()=>It(t),t.sessionHooks.end=e=>Ct(t,e),t.session.consumeNew()&&It(t),t.lifecycle.onExit(e=>Ct(t,e))};var Gn=50,Yn=200,Wn=5;function ue(t){return w(jn(t)).slice(0,Yn)}function jn(t){if(t.id)return`#${t.id}`;let e=t.tagName.toLowerCase(),n=L(t).split(" ").filter(Boolean),r=n.length?`${e}.${n.join(".")}`:e,i=Array.from(t.parentElement?.children||[]).indexOf(t);return i>0?`${r}:nth-child(${i+1})`:r}function Qn(t){return t.disabled||t.getAttribute("aria-disabled")==="true"?"button_disabled":t.matches(".loading, [data-loading], .spinner")||t.querySelector(".loading, .spinner, [data-loading]")?"loading":t.closest('[aria-invalid="true"]')?"error":"no_response"}function qn(t){return t.matches('a, [role="link"]')?"navigate":t.matches('button[type="submit"], input[type="submit"], [data-action="submit"]')?"submit":t.matches(".accordion, .collapse, [data-toggle], [aria-expanded]")?"expand":t.matches('.close, [data-dismiss], [aria-label*="close"]')?"close":"other"}function Zn(t){let e=t.toLowerCase();return/validation|required|invalid/.test(e)?"validation":/network|fetch|404|500/.test(e)?"network":e.includes("timeout")?"timeout":/undefined|null|typeerror/.test(e)?"javascript":"other"}function Jn(t,e){let{rageClickCount:n,rageClickWindowMs:r}=t.config.collectorOptions.frustration;t.on(document,"click",o=>{let i=p(o.target);if(!i)return;let s=Date.now(),a=ue(i),l=e.get(a);if(l&&s-l.timestamp<r?(l.count++,l.count>=n&&(t.emit({type:"rage_click",element:a,clicksInTimeframe:l.count,timeframe:r/1e3,whyRage:Qn(i),timeOnPage:s-t.page.startTime}),l.count=0)):e.set(a,{count:1,timestamp:s}),e.size>Gn)for(let[c,m]of e)s-m.timestamp>2*r&&e.delete(c)})}function er(t,e){let n=0,{deadClickWindowMs:r,clickableSelector:o}=t.config.collectorOptions.frustration;t.on(document,"click",i=>{let s=p(i.target);if(!s||s.closest(Pe)||n>=Wn||!(window.getComputedStyle(s).cursor==="pointer"||s.closest(o)!==null))return;n++;let l=t.lifecycle.routeKey(),c=!1,m=t.hub.observe(new MutationObserver(()=>{c=!0}));m.observe(document.documentElement,{subtree:!0,childList:!0,attributes:!0,characterData:!0}),t.later(()=>{if(t.hub.release(m),n--,c||t.lifecycle.routeKey()!==l||document.visibilityState!=="visible")return;let h=ue(s);t.emit({type:"dead_click",element:h,expectedBehavior:qn(s),actualBehavior:"none",previousClicksOnElement:e.get(h)?.count??0})},r)},!0)}function tr(t){t.on(document,"click",e=>{let n=p(e.target);if(!n)return;let r=Date.now();t.later(()=>{let o=t.state.lastError;!o||o.at<r||Date.now()-o.at>=1e3||(t.state.lastError=null,t.emit({type:"error_click",element:ue(n),errorMessage:o.message,errorType:Zn(o.message),userContinued:t.lifecycle.lastActivityTime>Date.now()-5e3,timeToError:Date.now()-t.page.startTime}))},100)})}var At=t=>{let e=new Map;Jn(t,e),er(t,e),tr(t)};var nr=/\.(pdf|docx?|xlsx?|pptx?|zip|rar|exe|dmg|pkg)$/i,rr={pdf:"pdf",doc:"word",docx:"word",xls:"excel",xlsx:"excel",ppt:"powerpoint",pptx:"powerpoint",zip:"archive",rar:"archive",exe:"executable",dmg:"disk_image",pkg:"installer"},or='[data-share], .share-button, .social-share, [href*="facebook.com/sharer"], [href*="twitter.com/share"], [href*="x.com/intent"], [href*="linkedin.com/sharing"], [href*="wa.me"], [href*="whatsapp.com"]',Lt='button, a, [role="button"]',ir=1e3,Nt=t=>{t.on(document,"click",e=>{let n=p(e.target)?.closest("a");if(!n?.href)return;let r;try{r=new URL(n.href).pathname}catch{return}if(!(n.hasAttribute("download")||nr.test(r)||r.includes("/download")))return;let i=n.download||r.split("/").pop()||"unknown";try{i=decodeURIComponent(i)}catch{i=n.download||"unknown"}let s=i.split(".").pop()?.toLowerCase()||"",a=n.closest("button")?"button":n.hasAttribute("download")?"link":n.href.startsWith("blob:")||n.href.startsWith("data:")?"programmatic":"auto";t.emit({type:"file_download",fileName:u(i,200),fileType:rr[s]||"other",fileSize:0,downloadSource:a,downloadUrl:d(n.href),timeOnPageBeforeDownload:Date.now()-t.page.startTime})})},xt=t=>{t.on(document,"click",e=>{let n=p(e.target)?.closest("a");if(!n?.href)return;let r;try{r=new URL(n.href)}catch{return}/^https?:$/.test(r.protocol)&&(K(r.hostname,window.location.hostname)||t.emit({type:"outbound_link",targetUrl:d(n.href),domain:r.hostname,linkText:t.captureText()&&!b(n)?u(n.textContent):"",openInNewTab:n.target==="_blank"}))},!0)},Dt=t=>{let e=n=>{t.state.printHint={trigger:n,at:Date.now()}};t.on(document,"click",n=>{let r=p(n.target)?.closest(`${Lt}, [data-action="print"]`);(r?.matches('[data-action="print"], [onclick*="print"]')||r&&/^print\b/i.test(r.textContent?.trim()||""))&&e("button")},!0),t.on(document,"keydown",n=>{(n.ctrlKey||n.metaKey)&&n.key.toLowerCase()==="p"&&e("keyboard")}),t.on(window,"beforeprint",()=>{let n=t.state.printHint,r=n&&Date.now()-n.at<ir;t.state.printHint=null,t.emit({type:"print",pagePrinted:window.location.pathname,timeOnPageBeforePrint:Date.now()-t.page.startTime,printTrigger:r?n.trigger:"menu"})})};function pe(){let t=window.location.pathname.toLowerCase();return t.includes("/product")||t.includes("/item")?"product_page":/\/(article|blog|post)/.test(t)?"article":t.includes("/cart")||t.includes("/basket")?"cart":t.includes("/checkout")?"checkout":"other"}function sr(t){let e=[t.href||"",L(t),t.textContent||""].join(" ").toLowerCase();return e.includes("facebook")?"facebook":e.includes("twitter")||e.includes("x.com/intent")?"twitter":e.includes("linkedin")?"linkedin":e.includes("whatsapp")||e.includes("wa.me")?"whatsapp":e.includes("mailto:")||e.includes("email")?"email":e.includes("copy")?"copy_link":"other"}function ar(t,e){let n=e.getAttribute("data-url")||e.getAttribute("data-share-url"),r=e.getAttribute("data-product-id")||e.getAttribute("data-product"),o=e.href,i=e.getAttribute("data-text")||e.getAttribute("data-share-text"),s=n||o;t.emit({type:"share",shareMethod:sr(e),contentShared:n?d(n):r||d(window.location.href),shareLocation:pe(),shareText:i?u(i):void 0,shareUrl:s?d(s):void 0})}var Mt=Symbol.for("indeks.share.wrapped");function lr(t){let e=navigator.share;if(typeof e!="function"||e[Mt])return;let n=r=>e.call(navigator,r).then(()=>{t.emit({type:"share",shareMethod:"native_share",contentShared:d(r?.url||window.location.href),shareLocation:pe(),shareText:r?.text?u(r.text):void 0,shareUrl:r?.url?d(r.url):void 0})});Object.defineProperty(n,Mt,{value:!0}),navigator.share=n,t.hub.observe({disconnect:()=>{navigator.share===n&&(navigator.share=e)}})}var Ot=t=>{lr(t),t.on(document,"click",e=>{let n=p(e.target);if(!n)return;let r=n.closest(or);if(r){ar(t,r);return}let o=n.closest(`${Lt}, [data-action="copy-link"], .copy-link`);(o?.matches('[data-action="copy-link"], .copy-link')||o&&/^copy( the)? link$/i.test(o.textContent?.trim()||""))&&t.emit({type:"share",shareMethod:"copy_link",contentShared:d(window.location.href),shareLocation:pe()})})};var cr=500;function dr(t){let e=document.querySelector(t.resultsCountSelector)?.textContent,n=parseInt(e?.match(/\d+/)?.[0]||"0",10);return n>0?n:document.querySelectorAll(t.resultItemSelector).length}function ur(){if(window.innerWidth<768)return"mobile";let t;try{t=document.querySelector('form:has(input[type="search"]), form:has(input[name*="search"])')}catch{return"other"}if(!t)return"other";let e=t.getBoundingClientRect();return e.top<100?"header":e.left<100?"sidebar":"page"}function pr(t){if(!t.captureText())return;let e={};return document.querySelectorAll("[data-filter], .filter.active, .facet.active").forEach(n=>{if(b(n))return;let r=n.getAttribute("data-filter")||n.getAttribute("data-facet"),o=n.getAttribute("data-value")||n.textContent?.trim();r&&o&&(e[r]=u(o))}),Object.keys(e).length?e:void 0}function fr(t){if(t.captureText())for(let e of['select[name*="sort"]',"[data-sort]",".sort-by"]){let n=document.querySelector(e);if(n&&!b(n)){let r=n.value||n.getAttribute("data-sort")||n.textContent?.trim();return u(r)||void 0}}}function hr(){return document.activeElement?.matches("[data-autocomplete]")?"autocomplete":document.querySelector("[data-voice-search], .voice-search")?"voice":document.querySelector(".search-suggestions, .autocomplete")?"suggestion":"direct"}function mr(t,e,n){let r=t.config.privacy.searchTerms,o=k("sessionStorage",f.LAST_SEARCH);t.emit({type:"search",query:r?u(C(e)):void 0,queryLength:e.length,resultsCount:dr(t.config.collectorOptions.search),searchLocation:ur(),filtersApplied:pr(t),sortBy:fr(t),resultsClicked:0,isRefinement:o!==null&&n!==void 0,previousQuery:r?o??void 0:void 0,searchSource:hr()}),T("sessionStorage",f.LAST_SEARCH,r?e:String(e.length))}var Rt=t=>{let e=null,n=r=>{let o=Date.now();if(e?.query===r&&o-e.at<cr)return;let i=e;e={query:r,at:o},mr(t,r,i)};t.on(document,"submit",r=>{let i=p(r.target)?.querySelector(t.config.collectorOptions.search.inputSelector);i?.value.trim()&&n(i.value.trim())}),t.on(document,"click",r=>{let o=p(r.target)?.closest('[data-action="search"]');if(!o||o.closest("form"))return;let s=(o.closest("[data-search-scope]")??document).querySelector(t.config.collectorOptions.search.inputSelector);s?.value.trim()&&n(s.value.trim())})};var gr=["play","pause","volumechange","seeking","seeked","ended"],vr=[25,50,75,100],br=50;function fe(t){let e=t;return e&&["VIDEO","AUDIO"].includes(e.tagName)?e:null}var Pt=t=>{for(let e of gr)t.on(document,e,n=>{let r=fe(n.target);r&&t.emit({type:e,element:{...g(r),src:d(r.currentSrc||r.src),currentTime:r.currentTime,duration:r.duration,volume:r.volume,muted:r.muted}})},!0)},Ht=t=>{let e=new Map,n=r=>r.currentSrc||r.src;t.on(document,"timeupdate",r=>{let o=fe(r.target);if(!o)return;let i=n(o),s=e.get(i);if(!s){if(e.size>=br){let l=e.keys().next().value;l!==void 0&&e.delete(l)}s=new Set,e.set(i,s)}if(!Number.isFinite(o.duration)||o.duration<=0)return;let a=Math.round(o.currentTime/o.duration*100);for(let l of vr)a<l||s.has(l)||(s.add(l),t.emit({type:o.tagName==="VIDEO"?"video_progress":"audio_progress",progress:l,currentTime:o.currentTime,duration:o.duration,mediaUrl:d(i)}))},!0),t.on(document,"ended",r=>{let o=fe(r.target);o&&e.delete(n(o))},!0)};function yr(t){return t instanceof Error?t.message:typeof t=="string"?t:String(t)}var Ut=t=>{let e=(n,r,o,i,s)=>{let a=w(n);t.state.lastError={message:a,at:Date.now()},t.emit({type:"error",error:{message:a,filename:d(r),lineno:o,colno:i,stack:s?w(s):void 0}})};t.on(window,"error",n=>{n.target instanceof Element||e(n.message,n.filename,n.lineno,n.colno,n.error?.stack)}),t.on(window,"unhandledrejection",n=>{let r=n.reason;e(`Unhandled Promise Rejection: ${yr(n.reason)}`,"",0,0,r?.stack)})},Ft=t=>{t.on(window,"error",e=>{let n=e.target;if(!(n instanceof Element))return;let r=n.tagName.toLowerCase(),o="other",i="";if(r==="img"||r==="script")o=r,i=n.src;else if(r==="link"){let a=n;a.rel==="stylesheet"?o="style":a.as==="font"&&(o="font"),i=a.href}if(!i)return;let s=d(i);t.emit({type:"resource_error",resourceType:o,resourceUrl:s,errorMessage:`Failed to load ${o}: ${s}`})},!0)},Vt=t=>{let e=n=>()=>t.emit({type:n,isOnline:navigator.onLine,connectionType:se()?.effectiveType});t.on(window,"online",e("online")),t.on(window,"offline",e("offline"))},zt=t=>{let e=se();e&&t.on(e,"change",()=>{t.emit({type:"network_change",effectiveType:e.effectiveType||"unknown",downlink:e.downlink,rtt:e.rtt})})};function Er(t,e,n){return t<e?"good":t<n?"needs-improvement":"poor"}function R(t,e,n,r,o){t.emit({type:e,value:n,rating:Er(n,r,o)})}function G(t,e,n){try{t.hub.observe(new PerformanceObserver(o=>n(o.getEntries()))).observe(e)}catch(r){t.logger.debug(`Performance entry type unsupported: ${e.type}`,r)}}var Xt=t=>{if(typeof PerformanceObserver>"u")return;let e=!1;G(t,{type:"paint",buffered:!0},l=>{let c=l.find(m=>m.name==="first-contentful-paint");c&&!e&&(e=!0,R(t,"first_contentful_paint",c.startTime,1800,3e3))});let n=0,r=!1;G(t,{type:"largest-contentful-paint",buffered:!0},l=>{let c=l[l.length-1];c&&(n=c.startTime)});let o=0,i=-1;G(t,{type:"layout-shift",buffered:!0},l=>{for(let c of l)c.hadRecentInput||(o+=c.value)});let s=0,a=0;G(t,{type:"event",buffered:!0,durationThreshold:40},l=>{for(let c of l)c.interactionId&&(s=Math.max(s,c.duration))}),t.lifecycle.onExit(()=>{n>0&&!r&&(r=!0,R(t,"largest_contentful_paint",n,2500,4e3)),o!==i&&(o>0||i>=0)&&(i=o,R(t,"cumulative_layout_shift",o,.1,.25)),s>0&&s!==a&&(a=s,R(t,"interaction_to_next_paint",s,200,500))}),ae(t,()=>{let l=performance.getEntriesByType("navigation")[0];l&&R(t,"time_to_first_byte",l.responseStart-l.requestStart,800,1800)})};var Bt={click:Ve,doubleClick:Xe,contextMenu:Be,mousePress:Ke,hover:$e,mouseMove:Ge,wheel:We,touch:je,dragDrop:Qe,keystroke:qe,scroll:Ze,scrollDepth:Je,resize:et,fullscreen:tt,orientation:nt,idle:rt,pageview:st,pageLoad:at,pageLeave:lt,pageLifecycle:ct,beforeUnload:dt,hashChange:ut,popState:pt,visibility:ft,windowFocus:ht,tabFocus:mt,session:_t,formSubmit:bt,inputChange:yt,fieldFocus:Et,formAbandon:wt,formError:kt,clipboard:Tt,textSelection:St,search:Rt,frustration:At,download:Nt,outboundLink:xt,print:Dt,share:Ot,media:Pt,mediaProgress:Ht,error:Ut,resourceError:Ft,networkStatus:Vt,networkChange:zt,performance:Xt};var Y=class{constructor(){this.registrations=[];this.timeouts=new Set;this.cancellers=[];this.observers=[]}on(e,n,r,o){let i=r;e.addEventListener(n,i,o);let s={target:e,type:n,handler:i,options:o};return this.registrations.push(s),()=>{e.removeEventListener(n,i,o),this.registrations=this.registrations.filter(a=>a!==s)}}later(e,n){let r=window.setTimeout(()=>{this.timeouts.delete(r),e()},n);return this.timeouts.add(r),r}cancel(e){e!==null&&(clearTimeout(e),this.timeouts.delete(e))}debounced(e,n){let r=Ie(e,n);return this.cancellers.push(r.cancel),r}throttled(e,n){let r=0;return((...o)=>{let i=Date.now();i-r<n||(r=i,e(...o))})}observe(e){return this.observers.push(e),e}release(e){e.disconnect(),this.observers=this.observers.filter(n=>n!==e)}dispose(){for(let e of this.cancellers)e();for(let e of this.timeouts)clearTimeout(e);for(let{target:e,type:n,handler:r,options:o}of this.registrations)e.removeEventListener(n,r,o);for(let e of this.observers)try{e.disconnect()}catch{continue}this.cancellers=[],this.timeouts.clear(),this.registrations=[],this.observers=[]}};var wr=["mousedown","mousemove","keydown","touchstart","wheel"];function he(){return typeof document>"u"||document.visibilityState!=="hidden"}var W=class{constructor(){this.startTime=Date.now();this.clicks=0;this.maxScrollDepth=0;this.previousUrl=null;this.scrollDepthReached=new Set;this.visibleMs=0;this.visibleSince=he()?Date.now():null}reset(){this.startTime=Date.now(),this.clicks=0,this.maxScrollDepth=0,this.scrollDepthReached.clear(),this.visibleMs=0,this.visibleSince=he()?this.startTime:null}setVisible(e,n=Date.now()){!e&&this.visibleSince!==null?(this.visibleMs+=n-this.visibleSince,this.visibleSince=null):e&&this.visibleSince===null&&(this.visibleSince=n)}timeOnPage(e=Date.now()){return this.visibleMs+(this.visibleSince===null?0:e-this.visibleSince)}},j=class{constructor(e,n,r,o,i){this.hub=e;this.session=n;this.page=r;this.idleTimeoutMs=o;this.debounceMs=i;this.lastActivityTime=Date.now();this.active=!1;this.exiting=!1;this.exitHandlers=[];this.beforeNavigationHandlers=[];this.navigationHandlers=[];this.activityHandlers=[];this.visibilityHandlers=[];this.lastKnownUrl="";this.patched={}}onExit(e){this.exitHandlers.push(e)}onBeforeNavigation(e){this.beforeNavigationHandlers.push(e)}onNavigation(e){this.navigationHandlers.push(e)}onActivity(e){this.activityHandlers.push(e)}onVisibility(e){this.visibilityHandlers.push(e)}routeKey(){return d(window.location.href)}start(){this.active=!0,this.lastKnownUrl=this.routeKey(),this.page.reset(),this.patchHistory(),this.listenForActivity(),this.listenForExit()}stop(){this.active=!1;for(let e of["pushState","replaceState"]){let n=this.patched[e];n&&history[e]===n.wrapper&&(history[e]=n.original)}this.patched={},this.exitHandlers=[],this.beforeNavigationHandlers=[],this.navigationHandlers=[],this.activityHandlers=[],this.visibilityHandlers=[],this.exiting=!1,this.lastActivityTime=Date.now()}run(e){for(let n of e)try{n()}catch{continue}}recordActivity(){let e=Date.now(),n=this.lastActivityTime,r=e-n;r<this.idleTimeoutMs()&&this.session.addActive(r),this.lastActivityTime=e,this.session.isExpired()||this.session.touch();for(let o of this.activityHandlers)o(n)}handleUrlChange(){if(!this.active)return;let e=this.routeKey();e!==this.lastKnownUrl&&(this.lastKnownUrl=e,this.page.reset(),this.run(this.navigationHandlers))}willChangeRoute(e){if(e==null)return!1;try{return d(new URL(String(e),window.location.href).href)!==this.lastKnownUrl}catch{return!1}}patchHistory(){for(let n of["pushState","replaceState"]){let r=history[n],o=a=>{this.active&&this.willChangeRoute(a)&&this.run(this.beforeNavigationHandlers)},i=()=>this.handleUrlChange(),s=function(...a){o(a[2]);let l=r.apply(this,a);return i(),l};history[n]=s,this.patched[n]={original:r,wrapper:s}}let e=()=>this.handleUrlChange();this.hub.on(window,"popstate",e),this.hub.on(window,"hashchange",e)}listenForActivity(){for(let n of wr)this.hub.on(document,n,()=>this.recordActivity(),{passive:!0,capture:!0});this.hub.on(document,"click",()=>{this.recordActivity(),this.session.addClick(),this.page.clicks++},!0);let e=this.hub.debounced(()=>{this.session.addScroll(),this.page.maxScrollDepth=Math.max(this.page.maxScrollDepth,O().percentage)},this.debounceMs());this.hub.on(window,"scroll",()=>{this.recordActivity(),e()},{passive:!0})}listenForExit(){let e=n=>{if(!this.exiting){this.exiting=!0;for(let r of this.exitHandlers)try{r(n)}catch{continue}this.session.touch(!0)}};this.hub.on(window,"pagehide",()=>{this.page.setVisible(!1),e("pagehide")}),this.hub.on(window,"pageshow",()=>{this.exiting=!1,this.page.setVisible(he())}),this.hub.on(document,"visibilitychange",()=>{let n=document.visibilityState;this.page.setVisible(n!=="hidden");for(let r of this.visibilityHandlers)try{r(n)}catch{continue}n==="hidden"?e("hidden"):this.exiting=!1})}};var kr=1e3,Q=class{constructor(){this.lastPersist=0;let e=this.read();this.fresh=!e,this.record=e??this.create()}get id(){return this.record.id}get data(){return this.record}consumeNew(){let e=this.fresh;return this.fresh=!1,e}isExpired(e=Date.now()){return e-this.record.lastSeen>q}restart(){this.record=this.create(),this.fresh=!0,this.write()}touch(e=!1){this.record.lastSeen=Date.now(),(e||this.record.lastSeen-this.lastPersist>=kr)&&this.write()}addActive(e){this.record.activeMs+=e}addClick(){this.record.clicks++}addScroll(){this.record.scrolls++}addPageView(){this.record.pageViews++}markConverted(){this.record.converted=!0}read(){let e=k("sessionStorage",f.SESSION_ID);if(!e)return null;try{let n=JSON.parse(e);return!n?.id||typeof n.lastSeen!="number"||Date.now()-n.lastSeen>=q?null:{id:n.id,startedAt:n.startedAt??Date.now(),lastSeen:Date.now(),pageViews:n.pageViews??0,clicks:n.clicks??0,scrolls:n.scrolls??0,activeMs:n.activeMs??0,converted:n.converted===!0}}catch{return null}}create(){let e=Date.now();return this.lastPersist=0,{id:Z("indeks"),startedAt:e,lastSeen:e,pageViews:0,clicks:0,scrolls:0,activeMs:0,converted:!1}}write(e=this.record){this.lastPersist=Date.now(),T("sessionStorage",f.SESSION_ID,JSON.stringify(e))}};var Tr=100,A=200,Sr=256,Ir=["elementText","formValues","clipboardText","searchTerms","fingerprint"],Kt=()=>{};function Cr(){return[...F].sort((t,e)=>+(e==="session")-+(t==="session"))}var me=class{constructor(e){this.hub=new Y;this.session=new Q;this.pageState=new W;this.state={lastError:null,printHint:null};this.sessionHooks={};this.device=null;this.eventQueue=[];this.pending=[];this.initPromise=null;this.isInitialized=!1;this.active=!1;this.accepting=!0;this.generation=0;this.rotatingSession=!1;let n=Ne(e);if(n.length)throw new Error(`Indeks: invalid configuration - ${n.join("; ")}`);this.config=Le(e),this.initialPrivacy={...this.config.privacy},this.logger=new U({enableConsole:this.config.debug,level:x.INFO}),this.analytics=new X(this.config),this.userId=this.resolveUserId(),this.externalUserId=k("localStorage",f.EXTERNAL_ID),this.lifecycle=new j(this.hub,this.session,this.pageState,()=>this.config.idleTimeoutMs,()=>this.config.debounceMs),this.context=this.createContext(),this.config.localOnly&&this.logger.info("Local only mode: events are tracked but not sent")}createContext(){let e={logger:this.logger,hub:this.hub,lifecycle:this.lifecycle,page:this.pageState,session:this.session,state:this.state,sessionHooks:this.sessionHooks,on:((...n)=>this.hub.on(...n)),later:(n,r)=>this.hub.later(n,r),debounced:n=>this.hub.debounced(n,this.config.debounceMs),throttled:(n,r)=>this.hub.throttled(n,r),emit:n=>this.emit(n),captureText:()=>this.config.privacy.elementText};return Object.defineProperties(e,{config:{get:()=>this.config,enumerable:!0},device:{get:()=>this.device??ne(),enumerable:!0}}),e}resolveUserId(){try{let e=localStorage.getItem(f.USER_ID);if(e)return e;let n=J();return localStorage.setItem(f.USER_ID,n),n}catch{return J()}}async useFingerprint(){try{let{Thumbmark:e}=await import("@thumbmarkjs/thumbmarkjs"),n=await new e({logging:!1}).get();n.thumbmark&&(this.userId=n.thumbmark)}catch(e){this.logger.warn("Failed to generate fingerprint, keeping first-party userId:",e)}}hasOptedOut(){if(k("localStorage",f.OPT_OUT)==="1")return!0;if(!this.config.privacy.respectDoNotTrack)return!1;let e=navigator;return e.doNotTrack==="1"||e.globalPrivacyControl===!0}emit(e,n){if(!this.active)return;this.rotateSessionIfExpired();let r=d(document.referrer)||void 0,o={timestamp:n??Date.now(),url:d(window.location.href)||window.location.pathname,userAgent:navigator.userAgent,sessionId:this.session.id,userId:this.userId,externalUserId:this.externalUserId??void 0,referrer:r,...e};if(!xe(o)){this.logger.warn(`Dropping malformed event: ${o?.type||"unknown"}`);return}o.type==="custom"&&o.eventName.includes("convert")&&this.session.markConverted(),this.eventQueue.push(o),this.eventQueue.length>y.MAX_EVENT_QUEUE_SIZE&&this.eventQueue.shift(),this.session.touch(),this.logger.info(`Event: ${o.type}`,o),this.analytics.batch([o]).catch(i=>{this.logger.warn("Failed to queue event for sending:",i)})}rotateSessionIfExpired(){if(!(this.rotatingSession||!this.session.isExpired())){this.rotatingSession=!0;try{this.sessionHooks.end?.("timeout"),this.session.restart(),this.pageState.reset(),this.sessionHooks.start?.()}finally{this.rotatingSession=!1}}}whenReady(e){let n=Date.now();if(this.isInitialized)return e(n)??Kt;if(!this.accepting||this.pending.length>=Tr)return Kt;let r=!1,o;return this.pending.push(()=>{r||(o=e(n))}),()=>{r=!0,o?.()}}init(){if(this.initPromise)return this.initPromise;this.accepting=!0;let e=this.runInit(this.generation).then(n=>{!n&&this.initPromise===e&&(this.initPromise=null)},n=>{throw this.initPromise===e&&(this.initPromise=null),n});return this.initPromise=e,e}async runInit(e){if(typeof window>"u")return this.logger.warn("Cannot initialize in non-browser environment"),!1;if(await Promise.resolve(),e!==this.generation)return!1;if(this.hasOptedOut())return this.logger.info("Tracking disabled: opt-out, Do Not Track or Global Privacy Control is active"),this.pending=[],this.accepting=!1,!1;if(this.config.privacy.fingerprint&&(await this.useFingerprint(),e!==this.generation))return!1;try{this.device=ne()}catch(n){this.logger.warn("Failed to read device info:",n)}this.active=!0,this.analytics.open(),this.lifecycle.start(),this.session.addPageView(),this.lifecycle.onNavigation(()=>this.session.addPageView());for(let n of Cr())if(this.config.collectors[n])try{Bt[n](this.context)}catch(r){this.logger.warn(`Collector "${n}" failed to start:`,r)}if(this.lifecycle.onExit(()=>this.analytics.flushSync()),this.watchOptOut(),await this.analytics.restorePersisted().catch(n=>{this.logger.warn("Failed to restore offline buffer:",n)}),e!==this.generation)return!1;for(;this.pending.length;){let n=this.pending;this.pending=[];for(let r of n)r()}return this.isInitialized=!0,this.logger.info("Tracker initialized"),!0}watchOptOut(){this.hub.on(window,"storage",n=>{n.key===f.OPT_OUT&&n.newValue==="1"&&this.applyOptOut()});let e=()=>{this.hasOptedOut()&&this.applyOptOut()};this.hub.on(window,"pageshow",e),this.hub.on(document,"visibilitychange",()=>{document.visibilityState==="visible"&&e()})}track(e,n={},r={}){this.whenReady(o=>{this.emit({type:"custom",eventName:u(e,A),properties:M(n),category:r.category?u(r.category,A):void 0,label:r.label?u(r.label,A):void 0,value:Number.isFinite(r.value)?r.value:void 0},o)})}trackElements(e){return this.whenReady(()=>{let n=e.eventType||"click";return this.hub.on(document,n,r=>{let o=p(r.target);if(o)for(let i of e.selectors){let s=o.closest(i);if(s){this.emit({type:"custom",eventName:u(e.eventName||`manual_${n}`,A),properties:{...e.properties,selector:i,element:D(s,this.config.privacy.elementText)},category:e.category?u(e.category,A):void 0,value:Number.isFinite(e.value)?e.value:void 0,label:e.label?u(e.label,A):void 0});return}}})})}page(e,n){this.whenReady(()=>{this.config.collectors.pageview||this.session.addPageView(),$(this.context,{name:e?u(e,A):void 0,properties:n?M(n):void 0})})}identify(e,n={}){if(!e||typeof e!="string"){this.logger.warn("identify() requires a non-empty string id");return}if(this.hasOptedOut()){this.logger.info("identify() ignored: tracking is opted out");return}let r=e.slice(0,Sr);this.externalUserId=r,T("localStorage",f.EXTERNAL_ID,r),this.whenReady(o=>{this.emit({type:"identify",traits:M(n)},o)})}reset(){this.sessionHooks.end?.("reset"),this.externalUserId=null;try{localStorage.removeItem(f.EXTERNAL_ID),localStorage.removeItem(f.USER_ID),sessionStorage.removeItem(f.LAST_SEARCH)}catch{this.logger.debug("Could not clear stored identity")}this.userId=this.resolveUserId(),this.session.restart(),this.pageState.reset(),this.active&&this.session.addPageView(),this.sessionHooks.start?.()}clearStoredData(){for(let e of[f.EVENTS,f.USER_ID,f.EXTERNAL_ID,f.LAST_VISIT])try{localStorage.removeItem(e)}catch{this.logger.debug(`Could not clear ${e}`)}for(let e of[f.SESSION_ID,f.LAST_SEARCH])try{sessionStorage.removeItem(e)}catch{this.logger.debug(`Could not clear ${e}`)}}async applyOptOut(){this.analytics.discard(),this.teardown(),this.externalUserId=null,this.clearStoredData()}async optOut(){T("localStorage",f.OPT_OUT,"1"),await this.applyOptOut()}async optIn(){try{localStorage.removeItem(f.OPT_OUT)}catch{this.logger.debug("Could not clear opt-out flag")}this.userId=this.resolveUserId(),this.externalUserId=null,this.session.restart(),await this.init()}isOptedOut(){return this.hasOptedOut()}updateConfig(e){e.collectors&&(Object.entries(e.collectors).filter(([r,o])=>o===!0&&we.includes(r)).length&&this.logger.warn("Privacy-sensitive collectors cannot be enabled at runtime"),this.logger.warn("Collector changes take effect on the next tracker instance"));for(let n of Ir){let r=e.privacy?.[n];if(r!==void 0){if(r===!0&&this.initialPrivacy[n]!==!0){this.logger.warn(`Refusing to enable privacy.${n} at runtime: privacy can only become stricter.`);continue}this.config={...this.config,privacy:{...this.config.privacy,[n]:r}}}}e.privacy?.respectDoNotTrack===!0&&(this.config={...this.config,privacy:{...this.config.privacy,respectDoNotTrack:!0}}),e.debug!==void 0&&(this.config={...this.config,debug:e.debug},this.logger.setConsoleEnabled(e.debug))}getEvents(){return[...this.eventQueue]}clearEvents(){this.eventQueue=[]}getSessionId(){return this.session.id}getUserId(){return this.userId}getExternalUserId(){return this.externalUserId}getDeviceInfo(){return this.device}async flush(){await this.analytics.flush()}getBatchSize(){return this.analytics.getBatchSize()}teardown(){this.generation++,this.accepting=!1,this.active=!1,this.initPromise=null,this.hub.dispose(),this.lifecycle.stop(),this.eventQueue=[],this.pending=[],this.state.lastError=null,this.state.printHint=null,this.sessionHooks.start=void 0,this.sessionHooks.end=void 0,this.pageState.previousUrl=null,this.pageState.reset(),this.isInitialized=!1}async destroy(){this.active&&this.session.touch(!0),this.analytics.close(),this.teardown()}},ge=me;function $t(t,e={}){let n=new ge({...e,apiKey:t});if(typeof window<"u"){let r=()=>n.init().catch(console.error);document.readyState==="loading"?document.addEventListener("DOMContentLoaded",r,{once:!0}):r()}return n}var Yo=$t;function _r(){typeof window>"u"||(window.indeks=$t,window.IndeksTracker=ge)}typeof document<"u"&&document.currentScript?.hasAttribute("data-indeks-global")&&_r();})();
|