@privatrak/tracker 1.1.0 → 1.2.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/CHANGELOG.md CHANGED
@@ -12,6 +12,109 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
12
12
 
13
13
  ## [Unreleased]
14
14
 
15
+ ## [1.2.0] - 2026-10-05
16
+
17
+ ### Added
18
+
19
+ - The Element Picker shows feature rules with an "or" group ("any of"
20
+ conditions) on the page like any other rule. Their button in **Show rules and
21
+ tags on this page** says **View** instead of **Edit** and opens the rule
22
+ read-only, because such a rule can only be edited in the dashboard.
23
+
24
+ ### Changed
25
+
26
+ - The Element Picker creates a rule in one step. Pick an element, give it a
27
+ name and press **Create rule**: the rule is saved right away, and **Undo**
28
+ takes it back for a few seconds. The separate step for choosing conditions
29
+ is gone. To count only some of the matching elements, open **Narrow it
30
+ down** and limit the rule to the element's text or to the current page. The
31
+ picker shows how many elements on the page the rule matches ("Matches 3
32
+ elements on this page") as you go.
33
+
34
+ ### Fixed
35
+
36
+ - The Element Picker understands pages with IDs in the address. On a page like
37
+ `/orders/123` it limits a rule to `/orders/:id`, the address the tracker
38
+ records, and it shows rules saved for `/orders/:id` on every such page.
39
+ Before, a rule limited to the page never counted anything there.
40
+
41
+ - Element Picker labels no longer cover each other. When several rules or tags
42
+ name elements that sit side by side, or the same element, each label finds
43
+ its own spot next to its element and stays inside the window.
44
+
45
+ - A trait longer than 64 characters, or more than 50 traits, no longer loses
46
+ the events they were sent with. The tracker now leaves out only the traits
47
+ over the limits (and empty ones, or values that are not text), keeps the
48
+ first 50, and names what it left out in a warning in the browser console.
49
+ Before, the whole batch of events was refused without a message.
50
+
51
+ - When `init()` is called without an `apiKey`, the console message now also
52
+ says that later `init()` calls are ignored. A later `init()` call, which is
53
+ ignored, now says in its warning when the first call had no key and tracking
54
+ is therefore off for the page load.
55
+
56
+ ## [1.1.1] - 2026-10-04
57
+
58
+ ### Fixed
59
+
60
+ - The exact selector (`element_selector`) no longer records the position of
61
+ `<body>`'s direct children, so it no longer changes with what else sits in
62
+ `<body>`, such as browser extensions, menus, dialogs and toasts:
63
+ `body > div:nth-of-type(3) > aside` is now `body > div > aside`. Selectors
64
+ longer than 200 characters are cut from the front after that position is
65
+ dropped. The generalized selector (`element_selector_generalized`) is now
66
+ always sent, also when it is the same as the exact one.
67
+
68
+ - Clicks on buttons that open a menu as they are pressed, such as the "⋯"
69
+ actions button of a shadcn or Radix `DropdownMenu`, a `Select`, or a modal
70
+ `Popover`, are now counted. Those widgets make the browser send the click to
71
+ the page itself rather than the button, so they were missing from click
72
+ counts, features and click problems. A press dragged off the button and
73
+ released elsewhere still does not count.
74
+
75
+ - A page whose events briefly hit the API's rate limit, which is shared by
76
+ everyone behind the same office or mobile network address, no longer stops
77
+ tracking for the rest of the visit and loses what it had collected. It now
78
+ keeps the events and tries again after a short wait, 1 to 2 seconds at
79
+ first and growing to at most a minute while the API keeps refusing, then
80
+ sends them once the API accepts them again. That includes events sent as
81
+ the visitor switches tabs or minimises the window, which used to be lost
82
+ if refused. The same applies when the API is briefly unavailable. Tracking
83
+ is still switched off, as before, when a project is over its plan's monthly
84
+ event limit. A batch also never carries more than the 100 events the API
85
+ accepts at once.
86
+
87
+ - Links in single-page apps are now checked for dead and slow clicks. Next.js
88
+ `<Link>`, React Router, Vue Router, SvelteKit and similar routers render an
89
+ ordinary link but change the view themselves instead of letting the browser
90
+ load a new page, and every click on such a link used to be taken for leaving
91
+ the page, so it could never be dead or slow. Now a link is only treated that
92
+ way when the browser actually follows it. A router link whose new address
93
+ appears more than a second after the click sends a `slow_click`, and one
94
+ that does nothing at all sends a `dead_click`. Only the new address, or a
95
+ change inside the link itself such as a loading spinner, counts as the
96
+ link's answer: a menu or a mobile sidebar closing around the link while the
97
+ visitor waits for the page does not hide the wait, and a link in a menu
98
+ that closes and never leads anywhere is a `dead_click`. Routers built on
99
+ the browser's Navigation API, which change the address at once, are judged
100
+ by when the new view finishes loading. Links the browser
101
+ follows, including ones opened in a new tab or with a modifier key and
102
+ downloads, are unchanged and are never dead or slow, and so is a link to the
103
+ page that is already open, such as the current item in a navigation menu,
104
+ where seeing nothing new is what the visitor expects.
105
+
106
+ - Page views are now recorded for single-page apps whose router is built on
107
+ the browser's Navigation API, which change the address without
108
+ `history.pushState`. They used to record only the first page. Each change of
109
+ address still counts once, including Back and Forward and routers that use
110
+ `pushState`.
111
+
112
+ - Changes in the page's `<head>` that visitors never see (scripts, the tab's
113
+ title, metadata, icons, preloads) no longer count as a click doing
114
+ something, so a click whose only effect was one of those is now a
115
+ `dead_click`, as it should be. Stylesheets still count: a theme switch that
116
+ swaps one changes the whole page.
117
+
15
118
  ## [1.1.0] - 2026-10-03
16
119
 
17
120
  ### Added
package/README.md CHANGED
@@ -131,7 +131,8 @@ tracking; nothing else is affected.
131
131
 
132
132
  Starts the tracker: applies the configuration, records the first pageview, and
133
133
  attaches the delegated `click` and `submit` listeners plus the History API
134
- patches that detect SPA navigation. Calling it twice logs a warning and does
134
+ patches (and, where the browser has it, a Navigation API listener) that detect
135
+ SPA navigation. Calling it twice logs a warning and does
135
136
  nothing the second time. Returns immediately; the first batch leaves once the
136
137
  project's settings have loaded.
137
138
 
@@ -150,8 +151,9 @@ track('invite-sent', { role: 'editor' });
150
151
  Labels the current session with developer-chosen strings — `['paid', 'trial']`,
151
152
  `['plan:pro']`, a feature-flag bucket — which every subsequent event carries and
152
153
  which the dashboard can filter and break down by. Traits are your own labels,
153
- not personal data: at most 50 per batch, 64 characters each. Call it whenever
154
- what you know about the session changes.
154
+ not personal data: at most 50 per batch, 64 characters each. A trait over
155
+ those limits is left out, with a warning in the browser console, and the rest
156
+ are sent as usual. Call it whenever what you know about the session changes.
155
157
 
156
158
  ### `version: string`
157
159
 
@@ -166,17 +168,34 @@ as types.
166
168
 
167
169
  ## What gets captured
168
170
 
169
- **Pageview** — on load and on every SPA navigation (`pushState`,
170
- `replaceState`, `popstate`). Navigations to the same URL are not recorded twice.
171
+ **Pageview** — on load and on every SPA navigation: `pushState`,
172
+ `replaceState`, `popstate`, and, in browsers with the Navigation API, a router
173
+ that intercepts `navigate` instead of calling `pushState`. Each change of
174
+ address is recorded once, however many of those report it, and navigations to
175
+ the same URL are not recorded twice.
171
176
  Fields: `page_url`, `referrer`, `timestamp`.
172
177
 
173
178
  **Click** — on anything in `autocaptureElements`, or anything carrying
174
179
  `data-track`, via a single delegated listener on `document`. A click on a
175
180
  non-interactive child walks up to `walkDepth` ancestors to find the real target.
181
+ A button that opens a modal menu as it is pressed — a shadcn/Radix
182
+ `DropdownMenu`, `Select` or modal `Popover` trigger — makes the browser send
183
+ its click to the page itself rather than the button; that click is counted on
184
+ the button, as long as the pointer was released on it. A press dragged off the
185
+ button and released elsewhere is not counted.
176
186
  Fields: `element_tag`, `element_selector`, `element_selector_generalized`,
177
187
  `element_text` (truncated), `data_track`, `data_track_attrs`, plus `page_url`
178
188
  and `timestamp`.
179
189
 
190
+ `element_selector` is the element's exact path from `<body>`, each level as its
191
+ tag, `[type=…]` and `[role=…]`, and its position among same-tagged siblings
192
+ (`:nth-of-type(N)`) when it has any — except directly under `<body>`, where
193
+ menus, toasts and browser extensions come and go, so the same element always
194
+ gets the same selector: `body > div > aside > a:nth-of-type(2)`. A path longer
195
+ than 200 characters is cut from the front, after that position is dropped.
196
+ `element_selector_generalized` is the same path without any positions, and is
197
+ always sent, even when it is the same as `element_selector`.
198
+
180
199
  **Form submit** — on submit, with the form's own identity and labels. Field
181
200
  values are never read. Fields: `element_tag`, `element_selector`,
182
201
  `element_selector_generalized`, `data_track`, `data_track_attrs`, `page_url`,
@@ -196,20 +215,34 @@ and fields, and for elements that only look clickable — a `cursor: pointer`
196
215
  element, an image, an icon, underlined text — which never send a click of their
197
216
  own. Clicks on plain text or empty space, clicks that select text, and clicks
198
217
  on canvas, video, audio, form fields and editable content are ignored, and
199
- anything ambiguous counts as something having happened. Links to other pages
200
- are never dead. If the visitor clicks or types somewhere else, scrolls, or
201
- leaves the page before the five seconds are up, the click is decided there and
202
- then: dead if nothing had happened for over a second, and otherwise not. Parts
203
- of the page that were already changing on their own before the click, such as
204
- a carousel, a clock or a list that refreshes itself, are not taken for the
205
- click's effect. Same fields as a click.
218
+ anything ambiguous counts as something having happened. A link the browser
219
+ follows to another page is never dead, and neither is a link to the page
220
+ already shown (the active item of a navigation). Any other link a single-page
221
+ app's router handles itself (Next.js `<Link>`, React Router, Vue Router,
222
+ SvelteKit and the like, which cancel the browser's navigation and change the
223
+ view in place) is judged by its new address: slow if it appears more than a
224
+ second after the click, dead if it never does. A change inside the link
225
+ itself, such as a loading spinner, counts as its answer too. A menu or drawer
226
+ closing around the link does not: if the link went away with it, no new
227
+ address came and nothing new appeared (such as a dialog), the click is dead.
228
+ If the link is still on screen and something else on the page changed, the
229
+ click is not reported. Routers built on the browser's Navigation API, which
230
+ let the address change at once, are judged by when the new view finishes
231
+ loading instead. If the visitor clicks or types
232
+ somewhere else, scrolls, or leaves the page before the five seconds are up,
233
+ the click is decided there and then: dead if nothing had happened for over a
234
+ second, and otherwise not. Parts of the page that were already changing on
235
+ their own before the click, such as a carousel, a clock or a list that
236
+ refreshes itself, are not taken for the click's effect. Same fields as a
237
+ click.
206
238
 
207
239
  **Slow click** (`slow_click`) — a click that did work, but whose first visible
208
240
  effect came more than a second after it, while the visitor was still waiting.
209
241
  Only effects the click plausibly caused count: a change to the clicked element,
210
- to something inside it or close around it, a URL change, focus moving, a
211
- scroll, or a dialog or popover opening. Anything else changing on the page
212
- makes the click neither slow nor dead. `response_ms` is the time from the click
242
+ to something inside it or close around it, a URL change (such as a router link
243
+ whose new view arrives late), focus moving, a scroll, or a dialog or popover
244
+ opening. Anything else changing on the page makes the click neither slow nor
245
+ dead. `response_ms` is the time from the click
213
246
  to that first effect. Same fields as a click.
214
247
 
215
248
  **Error click** (`error_click`) — a click followed, within the same five
package/dist/index.mjs CHANGED
@@ -1 +1 @@
1
- var config={flush_interval_ms:5e3,max_queue_size:10,walk_depth:3,max_text_length:100,autocapture_pageviews:!0,autocapture:!0,autocapture_elements:["a","button","input[type=submit]","[role=button]","[role=link]","[role=menuitem]","[role=menuitemcheckbox]","[role=menuitemradio]","[role=option]","[role=tab]","[role=switch]","[role=checkbox]","[role=radio]","[role=combobox]"],pii_url_params:["email","token","key","password","secret"],normalize_path_ids:!0,pii_path_patterns:[],excluded_urls:[],capture_dead_clicks:!0,capture_rage_clicks:!0,capture_error_clicks:!0,capture_slow_clicks:!0,dead_click_window_ms:1e3,slow_click_threshold_ms:1e3,dead_click_wait_ms:5e3,rage_click_threshold:3,rage_click_window_ms:1e3},apiBase="",apiKey="",configLoaded=!1,trackingDisabled=!1,traits=[];function setApiBase(value){apiBase=value}function setApiKey(value){apiKey=value}function setConfigLoaded(value){configLoaded=value}function setTrackingDisabled(value){trackingDisabled=value}function setTraits(value){traits=value}function applyServerConfig(server){if(typeof server!="object"||server===null)return;let s=server;if(typeof s.flush_interval_ms=="number"&&(config.flush_interval_ms=s.flush_interval_ms),typeof s.max_queue_size=="number"&&(config.max_queue_size=s.max_queue_size),typeof s.walk_depth=="number"&&(config.walk_depth=s.walk_depth),typeof s.max_text_length=="number"&&(config.max_text_length=s.max_text_length),typeof s.autocapture_pageviews=="boolean"&&(config.autocapture_pageviews=s.autocapture_pageviews),typeof s.autocapture=="boolean"&&(config.autocapture=s.autocapture),Array.isArray(s.autocapture_elements)&&(config.autocapture_elements=s.autocapture_elements),Array.isArray(s.pii_url_params)&&(config.pii_url_params=s.pii_url_params),typeof s.normalize_path_ids=="boolean"&&(config.normalize_path_ids=s.normalize_path_ids),Array.isArray(s.pii_path_patterns)&&(config.pii_path_patterns=s.pii_path_patterns),Array.isArray(s.excluded_urls)&&(config.excluded_urls=s.excluded_urls),typeof s.capture_dead_clicks=="boolean"&&(config.capture_dead_clicks=s.capture_dead_clicks),typeof s.capture_rage_clicks=="boolean"&&(config.capture_rage_clicks=s.capture_rage_clicks),typeof s.capture_error_clicks=="boolean"&&(config.capture_error_clicks=s.capture_error_clicks),typeof s.capture_slow_clicks=="boolean"&&(config.capture_slow_clicks=s.capture_slow_clicks),typeof s.dead_click_window_ms=="number"){let w=s.dead_click_window_ms;config.dead_click_window_ms=w,config.slow_click_threshold_ms=w,config.dead_click_wait_ms=Math.max(w,5e3)}typeof s.slow_click_threshold_ms=="number"&&(config.slow_click_threshold_ms=s.slow_click_threshold_ms),typeof s.dead_click_wait_ms=="number"&&(config.dead_click_wait_ms=s.dead_click_wait_ms),typeof s.rage_click_threshold=="number"&&(config.rage_click_threshold=s.rage_click_threshold),typeof s.rage_click_window_ms=="number"&&(config.rage_click_window_ms=s.rage_click_window_ms)}var CONFIG_FETCH_ATTEMPTS=5,CONFIG_RETRY_DELAYS_MS=[500,1e3,2e3,4e3],CONFIG_FETCH_TIMEOUT_MS=3e3;function isRetryableStatus(status){return status===408||status===429||status>=500}function delay(ms){return new Promise(resolve2=>setTimeout(resolve2,ms))}async function attemptConfigFetch(){let controller=new AbortController,timer2=setTimeout(()=>{controller.abort()},CONFIG_FETCH_TIMEOUT_MS);try{let response=await fetch(`${apiBase}/api/config`,{headers:{"X-API-Key":apiKey},credentials:"omit",signal:controller.signal});if(!response.ok)return isRetryableStatus(response.status)?{kind:"retry",status:response.status}:{kind:"permanent",status:response.status};let data=await response.json();return applyServerConfig(data),{kind:"ok"}}catch{return{kind:"retry"}}finally{clearTimeout(timer2)}}async function fetchConfig(){let status;for(let attempt=0;attempt<CONFIG_FETCH_ATTEMPTS;attempt++){let outcome=await attemptConfigFetch();if(outcome.kind==="ok")return{loaded:!0,attempts:attempt+1};if(outcome.kind==="permanent")return{loaded:!1,attempts:attempt+1,status:outcome.status};status=outcome.status;let wait=CONFIG_RETRY_DELAYS_MS[attempt];if(wait===void 0)break;await delay(wait)}return{loaded:!1,attempts:CONFIG_FETCH_ATTEMPTS,...status!==void 0&&{status}}}var CONFIG_FAILURE_REASONS={401:"the API key is missing or not valid",403:"this site's origin is not in the project's allowed domains"};function describeConfigFailure(result){let attempts=result.attempts===1?"1 attempt":`${String(result.attempts)} attempts`;if(result.status===void 0)return`no response after ${attempts} (network error or timeout)`;let reason=CONFIG_FAILURE_REASONS[result.status],http=`HTTP ${String(result.status)}`;return reason===void 0?`${http} after ${attempts}`:`${http} after ${attempts} (${reason})`}function applyInitConfig(initConfig){initConfig.apiKey!==void 0&&(apiKey=initConfig.apiKey),initConfig.apiHost!==void 0&&(apiBase=initConfig.apiHost),initConfig.flushIntervalMs!==void 0&&(config.flush_interval_ms=initConfig.flushIntervalMs),initConfig.maxQueueSize!==void 0&&(config.max_queue_size=initConfig.maxQueueSize),initConfig.walkDepth!==void 0&&(config.walk_depth=initConfig.walkDepth),initConfig.maxTextLength!==void 0&&(config.max_text_length=initConfig.maxTextLength),initConfig.autocapturePageviews!==void 0&&(config.autocapture_pageviews=initConfig.autocapturePageviews),initConfig.autocapture!==void 0&&(config.autocapture=initConfig.autocapture),initConfig.autocaptureElements!==void 0&&(config.autocapture_elements=initConfig.autocaptureElements),initConfig.piiUrlParams!==void 0&&(config.pii_url_params=initConfig.piiUrlParams),typeof initConfig.normalizePathIds=="boolean"&&(config.normalize_path_ids=initConfig.normalizePathIds),Array.isArray(initConfig.piiPathPatterns)&&(config.pii_path_patterns=initConfig.piiPathPatterns),initConfig.excludedUrls!==void 0&&(config.excluded_urls=initConfig.excludedUrls),initConfig.traits!==void 0&&(traits=initConfig.traits)}var ID_PATTERNS=[/^\d+$/,/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i,/^[0-9a-f]{8,}$/i];function isIdSegment(segment){return ID_PATTERNS.some(p=>p.test(segment))}function buildPiiPattern(){if(config.pii_url_params.length===0)return null;let escaped=config.pii_url_params.map(p=>p.replace(/[.*+?^${}()|[\]\\]/g,"\\$&"));return new RegExp("("+escaped.join("|")+")","i")}function buildPiiPathPattern(){if(config.pii_path_patterns.length===0)return null;try{return new RegExp("^("+config.pii_path_patterns.join("|")+")$","i")}catch{return null}}function sanitizeUrl(url){try{let u=new URL(url),segments=u.pathname.split("/"),piiPathRegex=buildPiiPathPattern(),pathChanged=!1;for(let i=0;i<segments.length;i++){let seg=segments[i];if(seg){if(config.normalize_path_ids&&isIdSegment(seg)){segments[i]=":id",pathChanged=!0;continue}piiPathRegex?.test(seg)&&(segments[i]=":redacted",pathChanged=!0)}}pathChanged&&(u.pathname=segments.join("/"));let paramPattern=buildPiiPattern();if(paramPattern){let toRedact=[];u.searchParams.forEach((_v,k)=>{paramPattern.test(k)&&toRedact.push(k)});for(let k of toRedact)u.searchParams.set(k,":redacted")}return u.toString()}catch{return url}}function matchGlob(pattern,url){try{let path=new URL(url).pathname,escaped=pattern.replace(/[.+^${}()|[\]\\]/g,"\\$&");return new RegExp("^"+escaped.replace(/\*/g,".*")+"$").test(path)}catch{return!1}}function isExcludedUrl(url){return config.excluded_urls.some(pattern=>matchGlob(pattern,url))}function disableTracking(queue2){setTrackingDisabled(!0),queue2.length=0,config.autocapture_pageviews=!1,config.autocapture=!1}function extractText(el){let raw=el.textContent;if(!raw)return;let trimmed=raw.trim().replace(/\s+/g," ");if(trimmed.length!==0)return trimmed.length>config.max_text_length?trimmed.slice(0,config.max_text_length):trimmed}function extractDataTrack(el){let current=el;for(let i=0;i<=config.walk_depth&&current;i++){let trackValue=current.getAttribute("data-track");if(trackValue!==null){let attrs={};for(let attr of current.attributes)if(attr.name.startsWith("data-track-")){let key=attr.name.slice(11);attrs[key]=attr.value}return{dataTrack:trackValue||void 0,dataTrackAttrs:Object.keys(attrs).length>0?attrs:void 0}}current=current.parentElement}return{dataTrack:void 0,dataTrackAttrs:void 0}}function getSegment(el){let seg=el.tagName.toLowerCase();el instanceof HTMLInputElement&&el.type&&(seg+='[type="'+CSS.escape(el.type)+'"]');let role=el.getAttribute("role");role&&(seg+='[role="'+CSS.escape(role)+'"]');let parent=el.parentElement;if(parent){let tag=el.tagName,siblings=parent.children,sameTag=0,idx=0;for(let i=0;i<siblings.length;i++){let sib=siblings[i];sib&&sib.tagName===tag&&(sameTag++,sib===el&&(idx=sameTag))}sameTag>1&&(seg+=":nth-of-type("+String(idx)+")")}return seg}function computeSelector(target){let parts=[],el=target;for(;el&&el!==document.documentElement;)parts.unshift(getSegment(el)),el=el.parentElement;let result=parts.join(" > ");for(;result.length>200&&parts.length>1;)parts.shift(),result=parts.join(" > ");return result}function getGenericSegment(el){let seg=el.tagName.toLowerCase();el instanceof HTMLInputElement&&el.type&&(seg+='[type="'+CSS.escape(el.type)+'"]');let role=el.getAttribute("role");return role&&(seg+='[role="'+CSS.escape(role)+'"]'),seg}function computeGenericSelector(target){let parts=[],el=target;for(;el&&el!==document.documentElement;)parts.unshift(getGenericSegment(el)),el=el.parentElement;let result=parts.join(" > ");for(;result.length>200&&parts.length>1;)parts.shift(),result=parts.join(" > ");let specific=computeSelector(target);return result===specific?null:result}function createPageviewEvent(referrer){return{event_type:"pageview",page_url:window.location.href,referrer:referrer===""?void 0:referrer,timestamp:new Date().toISOString()}}function createClickEvent(el){return createElementEvent(el,"click")}function createElementEvent(el,type){let{dataTrack,dataTrackAttrs}=extractDataTrack(el);return{event_type:type,page_url:window.location.href,element_tag:el.tagName.toLowerCase(),element_selector:computeSelector(el),element_selector_generalized:computeGenericSelector(el)??void 0,element_text:extractText(el),data_track:dataTrack,data_track_attrs:dataTrackAttrs,timestamp:new Date().toISOString()}}function createFormSubmitEvent(form){let{dataTrack,dataTrackAttrs}=extractDataTrack(form);return{event_type:"form_submit",page_url:window.location.href,element_tag:form.tagName.toLowerCase(),element_selector:computeSelector(form),element_selector_generalized:computeGenericSelector(form)??void 0,data_track:dataTrack,data_track_attrs:dataTrackAttrs,timestamp:new Date().toISOString()}}var pickerActive=!1,pickerDashboardOrigin=null;function setPickerActive(value){pickerActive=value}function setPickerDashboardOrigin(value){pickerDashboardOrigin=value}var REJECTION_REASONS={401:"the API key is missing or not valid",403:"this site's origin is not in the project's allowed domains",429:"the project is over its event limit"},queue=[],lastUrl="",isFlushing=!1;function setLastUrl(value){lastUrl=value}function sanitizeEvent(event){let pageUrl=sanitizeUrl(event.page_url),referrer=event.referrer===void 0?void 0:sanitizeUrl(event.referrer);return pageUrl===event.page_url&&referrer===event.referrer?event:{...event,page_url:pageUrl,...referrer!==void 0&&{referrer}}}function prepareEvents(events){return filterEvents(events.map(sanitizeEvent))}function filterEvents(events){return events.filter(event=>!(isExcludedUrl(event.page_url)||event.event_type==="pageview"&&!config.autocapture_pageviews||(event.event_type==="click"||event.event_type==="form_submit")&&!config.autocapture&&!event.data_track||event.event_type==="dead_click"&&!(config.autocapture&&config.capture_dead_clicks)||event.event_type==="rage_click"&&!(config.autocapture&&config.capture_rage_clicks)||event.event_type==="error_click"&&!(config.autocapture&&config.capture_error_clicks)||event.event_type==="slow_click"&&!(config.autocapture&&config.capture_slow_clicks)))}function enqueue(event){trackingDisabled||pickerActive||apiKey&&(queue.length>=100||(queue.push(event),configLoaded&&queue.length>=config.max_queue_size&&flush()))}async function flush(){if(trackingDisabled||pickerActive||!configLoaded||isFlushing||queue.length===0)return;isFlushing=!0;let events=prepareEvents(queue.splice(0));if(events.length===0){isFlushing=!1;return}let body={events,...traits.length>0&&{traits}},headers={"Content-Type":"application/json"};apiKey&&(headers["X-API-Key"]=apiKey);try{let response=await fetch(`${apiBase}/api/events`,{method:"POST",headers,body:JSON.stringify(body),keepalive:!0,credentials:"omit"});if(!response.ok){let status=response.status;status===401||status===403||status===429?(console.warn(`[tracker] The API rejected events with HTTP ${String(status)} \u2014 ${REJECTION_REASONS[status]??"the request was refused"}. Tracking is now off for this page.`),disableTracking(queue)):status>=500&&queue.unshift(...events)}}catch{queue.unshift(...events)}finally{isFlushing=!1}}function flushBeacon(){if(trackingDisabled||!configLoaded||queue.length===0)return;let events=prepareEvents(queue.splice(0));if(events.length===0)return;let body={events,...traits.length>0&&{traits}};apiKey&&(body.api_key=apiKey);let headers={"Content-Type":"application/json"};apiKey&&(headers["X-API-Key"]=apiKey),fetch(`${apiBase}/api/events`,{method:"POST",headers,body:JSON.stringify(body),keepalive:!0,credentials:"omit"}).catch(()=>{})}function isSensitive(el){if(el instanceof HTMLInputElement){let t=el.type.toLowerCase();if(t==="password"||t==="hidden")return!0}let ac=el.getAttribute("autocomplete");return!!(ac&&ac.toLowerCase().startsWith("cc-"))}function isInteractive(el){if(el.hasAttribute("data-track"))return!0;if(!config.autocapture)return!1;for(let selector of config.autocapture_elements)try{if(el.matches(selector))return!0}catch{}return!1}function findInteractiveAncestor(target){let el=target;for(let i=0;i<=config.walk_depth&&el;i++){if(isInteractive(el))return el;el=el.parentElement}return null}function isPickerTarget(el){return isInteractive(el)||el.matches("form")}function findPickerTarget(target){let el=target;for(let i=0;i<=config.walk_depth&&el;i++){if(isPickerTarget(el))return el;el=el.parentElement}return null}function trackableElements(){let selectors=["[data-track]"];config.autocapture&&selectors.push("form",...config.autocapture_elements);let seen2=new Set;for(let selector of selectors){let found;try{found=document.querySelectorAll(selector)}catch{continue}for(let el of found)seen2.add(el)}let result=[];for(let el of seen2)isSensitive(el)||result.push(el);return result}var PICKER_HANDOFF_KEY="__stPickerHandoff";var PICKER_FILE="tracker-picker.js",picker=null,loading=!1,failed=!1,pendingOptions=null,pickerHostApi={setActive:setPickerActive,setDashboardOrigin:setPickerDashboardOrigin,clearQueue:()=>{queue.length=0},computeSelector,computeGenericSelector,extractText,extractDataTrack,findPickerTarget,trackableElements,sanitizeUrl};function pickerScriptUrl(){for(let script of document.querySelectorAll("script[src]")){let src=script.getAttribute("src");if(src?.includes("tracker.js"))try{return new URL(PICKER_FILE,new URL(src,document.baseURI)).toString()}catch{}}return apiBase?apiBase.replace(/\/+$/,"")+"/"+PICKER_FILE:"/"+PICKER_FILE}function registerPicker(module){if(picker=module,loading=!1,pendingOptions){let options=pendingOptions;pendingOptions=null,activate(module,options)}}function activate(module,options){module.activate({...options,dashboardOrigin:pickerDashboardOrigin})}function abandonLoad(url){loading=!1,failed=!0,pendingOptions=null,setPickerActive(!1),console.warn(`[tracker] Could not load the Element Picker from ${url}. Tracking is unaffected.`)}function loadPicker(){let url=pickerScriptUrl(),script=document.createElement("script");script.src=url,script.async=!0,script[PICKER_HANDOFF_KEY]={host:pickerHostApi,register:registerPicker},script.addEventListener("load",()=>{script.remove(),picker||abandonLoad(url)}),script.addEventListener("error",()=>{script.remove(),abandonLoad(url)}),document.head.appendChild(script)}function requestPicker(options){if(picker){activate(picker,options??{});return}failed||(setPickerActive(!0),queue.length=0,pendingOptions=options??{},!loading&&(loading=!0,loadPicker()))}function onPickerNavigation(){picker?.onNavigation()}function onPickerWindowMessage(e){if(picker){picker.handleMessage(e);return}if(typeof e.data!="object"||e.data===null)return;let data=e.data;data.type==="st-picker-activate"&&(pickerDashboardOrigin&&e.origin!==pickerDashboardOrigin||pickerActive||!window.opener||requestPicker(data.mode==="click-map"?{mode:"click-map"}:void 0))}function parsePickerHash(hash){let m=/^#st-picker=([^&]+)(?:&(.*))?$/.exec(hash),raw=m?.[1];if(!m||!raw)return null;let origin;try{origin=decodeURIComponent(raw)}catch{return null}let mode="rules";for(let pair of(m[2]??"").split("&"))pair==="mode=click-map"&&(mode="click-map");return{origin,mode}}function findLooksClickable(target,depth,parent,look2){let el=target;for(let i=0;i<=depth&&el;i++){let f=look2(el);if(f&12)return null;if(f&1){let top=el,up=parent(el);for(;up;i++){let g=look2(up);if(!(g&1))return top;if(g&8||i>=depth)return null;top=up,up=parent(up)}return top}if(f&2)return el;el=parent(el)}return null}function walkUp(target,depth,parent,pred){let el=target;for(let i=0;i<=depth&&el;i++){if(pred(el))return el;el=parent(el)}return null}function leavesDocument(href,page){try{let u=new URL(href,page);if(u.protocol==="javascript:")return!1;if(!href.includes("#"))return!0;let p=new URL(page);return u.hash="",p.hash="",u.href!==p.href}catch{return!0}}function elementKey(ev){return JSON.stringify([ev.element_selector_generalized??null,ev.element_text??null,ev.element_tag??null])}var MAX_REPORTED=100;function claim(seen2,key){return seen2.has(key)||seen2.size>=MAX_REPORTED?!1:(seen2.add(key),!0)}function nextBurst(burst2,key,first,now,windowMs){return burst2?.key===key&&now-burst2.last<=windowMs?(burst2.count++,burst2.last=now,burst2):{key,first,count:1,last:now}}var MAX_CLICK_COUNT=1e3;function rageCount(count,threshold,selected=!1){return count>=Math.max(selected?4:3,threshold)?Math.min(count,MAX_CLICK_COUNT):null}function selectionIsEffect(current,made,touchesMade=!1){return current!==null&&!touchesMade&&!(made&&made.anchor===current.anchor&&made.anchorOffset===current.anchorOffset&&made.focus===current.focus&&made.focusOffset===current.focusOffset)}var MAX_PENDING=8;function openWindow(pending2,seen2,p){if(seen2.every(s=>s.has(p.key))||pending2.length>=MAX_PENDING)return!1;for(let q of pending2)if(q.key===p.key)return!1;return pending2.push(p),!0}var IGNORE=0,LIVE=1,CAUSED=2,SUSPECT=3;function classify(related,noisy2,global=!1,ticking=!1){return noisy2?related?LIVE:IGNORE:related||global?CAUSED:ticking?SUSPECT:LIVE}function isRelated(node,el,depth,parent,contains2){return contains2(el,node)||walkUp(el,depth,parent,n=>n===node)!==null}var NOISE_GAP_MS=6e3,NOISE_REPEAT_MS=250;function noteStreak(s,t){return s?(t-s.last>NOISE_GAP_MS?(s.start=s.beatAt=t,s.since=1/0,s.beats=1):(s.since===1/0&&t-s.start>=NOISE_REPEAT_MS&&(s.since=t),t-s.beatAt>=NOISE_REPEAT_MS&&(s.beats++,s.beatAt=t)),s.last=t,s):{start:t,last:t,since:1/0,beats:1,beatAt:t}}function noisyAt(s,at){return s!==void 0&&s.since<at}function tickingAt(s,at,t){return s!==void 0&&s.start<at&&t-s.last<=NOISE_GAP_MS}var MAX_DOUBTS=8;function addDoubt(doubts,node,t,beats){for(let d of doubts)if(d.node===node)return!0;return doubts.length>=MAX_DOUBTS?!1:(doubts.push({node,t,beats}),!0)}function judgeDoubts(doubts,at,now,streakOf2){let open=!1;for(let d of doubts){let s=streakOf2(d.node);if(!s||s.start>=at||now-s.last>NOISE_GAP_MS)return"live";s.beats-d.beats<2&&(open=!0)}return open?"open":"noise"}var NONE=0,DROP=1,SLOW=2,DOUBT=3;function effectOn(p,kind,t){return kind===IGNORE?NONE:kind===SUSPECT?DOUBT:kind===LIVE||t<p.slowAt||t>=p.due?DROP:SLOW}function moveOn(pending2,now,el){for(let p of pending2)p.el!==el&&!p.verdict&&(p.due=Math.max(p.slowAt,Math.min(p.due,now)))}var MAX_RESPONSE_MS=6e4;function responseMs(at,t){return Math.min(MAX_RESPONSE_MS,Math.max(0,Math.round(t-at)))}function errorEventCounts(trusted,rejection){return trusted||rejection}var ERROR_NAME=/^[A-Za-z_$][A-Za-z0-9_$.]{0,63}$/;function errorType(err,rejection){if(!(err instanceof Error))return rejection?"UnhandledRejection":"Error";let name;try{name=err.name}catch{return"Error"}return typeof name=="string"&&ERROR_NAME.test(name)?name:"Error"}function ambientError(last,at,windowMs){return last!==void 0&&last<at&&at-last<=windowMs}function takeSettled(pending2,now,final,streakOf2){let out=[];for(let i=0;i<pending2.length;i++){let p=pending2[i];if(!p)continue;if(!p.verdict){if(p.due>now)continue;p.verdict="dead"}let j=judgeDoubts(p.doubts,p.at,now,streakOf2);if(j==="open"&&!final){p.due<=now&&(p.due=now+NOISE_REPEAT_MS);continue}pending2.splice(i--,1),j==="noise"&&out.push(p)}return out}function nextDue(pending2){let next=1/0;for(let p of pending2)p.due<next&&(next=p.due);return next}function holdsClick(prev,key,now,windowMs,detail){return detail!==0&&prev?.key===key&&now-prev.at<=windowMs}var MAX_HELD=32;function openHeld(held2,el,at,due,live2){if(held2.length>=MAX_HELD)return null;let h={ev:null,el,at,due,live:live2};return held2.push(h),h}function attachHeld(held2,h,ev){let i=held2.indexOf(h);return i<0?!1:h.live?(held2.splice(i,1),!1):(h.ev=ev,!0)}function releaseHeld(held2,did=()=>!0){let out=[];for(let i=0;i<held2.length;i++){let h=held2[i];!h||h.live||!did(h)||(h.ev!==null?(out.push(h.ev),held2.splice(i--,1)):h.live=!0)}return out}function takeDueHeld(held2,now){let out=[];for(let i=0;i<held2.length;i++){let h=held2[i];h&&h.due<=now&&(h.ev!==null&&!h.live&&out.push(h.ev),held2.splice(i--,1))}return out}function heldWaiting(held2){for(let h of held2)if(!h.live)return!0;return!1}var PRESS_MS=5e3,STALL_MS=250,MAX_ERROR_TYPES=32;function newSeen(){return{dead:new Set,rage:new Set,slow:new Set,error:new Set}}var seen=newSeen(),pending=[],burst=null,lastKey="",madeSel=null,madeEl=null,lastClick=null,held=[],holding=null,holdTarget=null,errClick=null,errorTimes=new Map,streaks=new WeakMap,pressTarget=null,pressEl=null,pressAt=0,pressUntil=0,pressEffect=!1,pressDoubts=[],inTask=!1,observer=null,observing=!1,listening=!1,timer,timerDue=0,live=()=>LIVE,caused=()=>CAUSED;function parentOf(el){return el.parentElement}function nearParent(n){let p=n.parentNode;return p instanceof Element&&p!==document.body&&p!==document.documentElement?p:null}function contains(outer,inner){return outer.contains(inner)}function noisy(node,at){return walkUp(node,config.walk_depth,nearParent,n=>noisyAt(streaks.get(n),at))!==null}function tickingNode(node,at,t){let found=null,n=node;for(let i=0;i<=config.walk_depth&&n;i++)tickingAt(streaks.get(n),at,t)&&(found=n),n=nearParent(n);return found}function streakOf(n){return streaks.get(n)}function note(node,t){let s=streaks.get(node),n=noteStreak(s,t);s||streaks.set(node,n)}function isDisabled(el){return el.matches(":is(button,input,select,textarea):disabled")||el.getAttribute("aria-disabled")==="true"&&isInteractive(el)}function isEditable(el){return el instanceof HTMLInputElement?!/^(button|submit|image)$/.test(el.type):/^(TEXTAREA|SELECT)$/.test(el.tagName)||el.isContentEditable}function look(el){if(/^(canvas|video|audio|input|textarea|select)$/i.test(el.tagName)||isEditable(el))return 4;let s=getComputedStyle(el),f=s.cursor==="pointer"?1:0;return el===document.body||el===document.documentElement?f|8:el.tagName==="IMG"||el.tagName==="svg"||s.textDecorationLine.includes("underline")?f|2:f}function active(){return!pickerActive&&!trackingDisabled&&config.autocapture&&(config.capture_dead_clicks||config.capture_rage_clicks||config.capture_slow_clicks||config.capture_error_clicks)}function rolling(){return active()&&(config.capture_dead_clicks||config.capture_slow_clicks)}function idle(){return pending.length===0&&(pressEffect||!pressTarget)&&!heldWaiting(held)}function resolve(target){if(target.closest("#st-picker-host"))return null;let control=findInteractiveAncestor(target);if(control)return isSensitive(control)||isEditable(control)?null:control;let t=target;for(;t instanceof SVGElement&&t.ownerSVGElement;)t=t.ownerSVGElement;let el=findLooksClickable(t,config.walk_depth,parentOf,look);return el&&!isSensitive(el)?el:null}function selection(){let s=getSelection();return s&&!s.isCollapsed?{anchor:s.anchorNode,anchorOffset:s.anchorOffset,focus:s.focusNode,focusOffset:s.focusOffset}:null}function selectionEffect(){let s=getSelection();return selectionIsEffect(selection(),madeSel,!!madeEl&&!!s&&s.containsNode(madeEl,!0))}function startTask(){inTask||(inTask=!0,setTimeout(()=>{inTask=!1},0))}function report(el,now,detail,dead,target,doubts,disabled=!1){let ev=createElementEvent(el,"dead_click"),key=elementKey(ev),rage=detail!==0,threshold=config.slow_click_threshold_ms,wait=Math.max(threshold,config.dead_click_wait_ms),multi=detail>=2&&key===lastKey;if(madeSel=multi?selection():null,madeEl=multi?el:null,lastKey=key,holding=null,holdTarget=target,rage&&(holdsClick(lastClick,key,now,config.rage_click_window_ms,detail)&&(holding=openHeld(held,el,now,now+threshold,!dead)),lastClick={key,at:now}),rage&&config.capture_rage_clicks){let next=nextBurst(burst,key,ev,now,config.rage_click_window_ms);next!==burst&&endBurst(),burst=next;let s=getSelection();next.selected=!!s&&!s.isCollapsed&&s.containsNode(el,!0)}errClick=config.capture_error_clicks&&!seen.error.has(key)?{key,ev,el,at:now,due:now+wait}:null;let link=el.closest("a[href]");if(dead&&!(link&&leavesDocument(link.getAttribute("href")??"",location.href))&&!el.closest("label")){let kinds=[];config.capture_dead_clicks&&kinds.push(seen.dead),config.capture_slow_clicks&&!disabled&&kinds.push(seen.slow);let slowAt=now+threshold;openWindow(pending,kinds,{key,ev,el,at:now,slowAt,due:disabled?slowAt:now+wait,doubts:doubts.slice(),seen})}sync()}function endBurst(){let b=burst;burst=null;let n=b&&rageCount(b.count,config.rage_click_threshold,b.selected);b&&n&&claim(seen.rage,b.key)&&enqueue({...b.first,event_type:"rage_click",click_count:n})}function happen(kindAt,suspect){let t=Date.now(),doubt=(doubts,at)=>{let n=suspect?.(at),s=n?streaks.get(n):void 0;return!!n&&!!s&&addDoubt(doubts,n,t,s.beats)};if(pressTarget&&!pressEffect){let k=inTask||!pressEl?LIVE:kindAt(pressEl,pressAt);k!==IGNORE&&!(k===SUSPECT&&doubt(pressDoubts,pressAt))&&(pressEffect=!0)}for(let i=0;i<pending.length;i++){let p=pending[i];if(!p||p.verdict)continue;let r=effectOn(p,inTask?LIVE:kindAt(p.el,p.at),t);r===NONE||r===DOUBT&&doubt(p.doubts,p.at)||(r===SLOW?(p.verdict="slow",p.answeredAt=t):pending.splice(i--,1))}let did=h=>{let k=inTask?LIVE:kindAt(h.el,h.at);return k!==IGNORE&&k!==SUSPECT};for(let ev of releaseHeld(held,did))enqueue(ev)}function markLive(){idle()||(happen(live),sync())}function markCaused(){idle()||(happen(caused),sync())}function markHistory(changed){changed?markCaused():markLive()}function settle(now,final){for(let p of takeSettled(pending,now,final,streakOf))p.verdict==="slow"?config.capture_slow_clicks&&claim(p.seen.slow,p.key)&&enqueue({...p.ev,event_type:"slow_click",response_ms:responseMs(p.at,p.answeredAt??now)}):config.capture_dead_clicks&&claim(p.seen.dead,p.key)&&enqueue(p.ev)}function movedOn(now,el,errors){if(errors&&errClick&&errClick.el!==el&&(errClick=null),pending.length===0)return;let records=observer?.takeRecords();records?.length&&onMutations(records),selectionEffect()&&happen(live),moveOn(pending,now,el),settle(now,!1)}function onMutations(records){let t=Date.now();for(let r of records)note(r.target,t);for(let r of records){if(idle())break;let node=r.target;happen(r.attributeName==="open"&&/^(DIALOG|DETAILS)$/.test(node.nodeName)?caused:(el,at)=>classify(isRelated(node,el,config.walk_depth,nearParent,contains),noisy(node,at),!1,tickingNode(node,at,t)!==null),at=>tickingNode(node,at,t))}sync()}function holdClick(e,ev){let h=holding;return holding=null,!!h&&e.isTrusted&&e.detail!==0&&e.target===holdTarget&&attachHeld(held,h,ev)}function onFocusIn(e){let f=e.target;pressTarget&&f instanceof Node&&f.contains(pressTarget)||markCaused()}function onScroll(e){let node=e.target instanceof Node?e.target:document;note(node,Date.now()),!idle()&&(happen((el,at)=>classify(node.contains(el),noisyAt(streaks.get(node),at),!0)),sync())}function onKeyDown(e){if(!e.isTrusted||pending.length===0&&!errClick)return;let t=e.target;movedOn(Date.now(),(e.key==="Enter"||e.key===" ")&&t instanceof Element?t:null,!0),sync()}function onWheel(e){!e.isTrusted||pending.length===0||(movedOn(Date.now(),null,!1),sync())}function onLeave(){movedOn(Date.now(),null,!1),markLive(),sync()}function noteError(type){let now=Date.now(),last=errorTimes.get(type);last===void 0&&errorTimes.size>=MAX_ERROR_TYPES&&errorTimes.clear(),errorTimes.set(type,now);let c=errClick;!c||now>c.due||!active()||!config.capture_error_clicks||!inTask&&ambientError(last,c.at,NOISE_GAP_MS)||(errClick=null,claim(seen.error,c.key)&&enqueue({...c.ev,event_type:"error_click",error_type:type}))}function onError(e){e instanceof ErrorEvent&&errorEventCounts(e.isTrusted,!1)&&noteError(errorType(e.error,!1))}function onRejection(e){errorEventCounts(e.isTrusted,!0)&&noteError(errorType(e.reason,!0))}function sync(){settle(Date.now(),!1);let watch=!idle(),observe=watch||rolling();observe!==observing&&(observe?(typeof MutationObserver=="function"&&(observer??=new MutationObserver(onMutations)),observer?.observe(document,{subtree:!0,childList:!0,attributes:!0,characterData:!0})):observer?.disconnect(),observing=observe),watch!==listening&&(listening=watch,watch?window.addEventListener("beforeunload",onLeave):window.removeEventListener("beforeunload",onLeave));let next=Math.min(nextDue(pending),nextDue(held),burst?burst.last+config.rage_click_window_ms+1:1/0,pressTarget?pressUntil:1/0);clearTimeout(timer),timer=void 0,next<1/0&&(timerDue=next,timer=setTimeout(tick,Math.max(0,next-Date.now())))}function tick(){let now=Date.now(),late=now-timerDue>STALL_MS,records=observer?.takeRecords();records?.length&&onMutations(records),(late||selectionEffect())&&happen(live),settle(now,!1);for(let ev of takeDueHeld(held,now))active()||enqueue(ev);burst&&now-burst.last>config.rage_click_window_ms&&endBurst(),pressTarget&&now>=pressUntil&&(pressTarget=pressEl=null),sync()}function onPointerDown(e){if(!e.isTrusted)return;let target=e.target,now=Date.now();if(!(target instanceof Element)||e.button!==0||!active()){movedOn(now,null,!0),sync();return}let disabled=walkUp(target,config.walk_depth,parentOf,isDisabled),el=disabled??resolve(target);if(movedOn(now,el,!0),startTask(),holding=null,pressTarget=target,pressEffect=!1,pressDoubts=[],pressAt=now,pressUntil=now+PRESS_MS,disabled){pressEl=null,pressEffect=!0,!isSensitive(disabled)&&!target.closest("#st-picker-host")?report(disabled,now,1,!0,target,[],!0):sync();return}pressEl=el,pressEl||(pressTarget=null),sync()}function onClick(e){if(!e.isTrusted||!active())return;let target=e.target;if(!(target instanceof Element))return;startTask();let press=pressTarget,effect=press!==null&&pressEffect,el=press===target?pressEl:resolve(target);pressTarget=pressEl=null;let multi=e.detail>=2;el&&!walkUp(target,config.walk_depth,parentOf,isDisabled)&&(isInteractive(el)||multi||getSelection()?.isCollapsed!==!1)?report(el,Date.now(),e.detail,!effect,target,press?pressDoubts:[]):sync()}function onFrustrationHide(){onLeave(),settle(Date.now(),!0),endBurst()}function resetFrustration(){movedOn(Date.now(),null,!1),markLive(),endBurst(),lastClick=null,lastKey="",madeSel=null,madeEl=null,seen=newSeen()}function startFrustration(){let capture={capture:!0,passive:!0};window.addEventListener("pointerdown",onPointerDown,capture),window.addEventListener("click",onClick,capture),window.addEventListener("focusin",onFocusIn,capture),window.addEventListener("keydown",onKeyDown,capture),window.addEventListener("wheel",onWheel,capture),window.addEventListener("error",onError),window.addEventListener("unhandledrejection",onRejection);for(let type of["blur","pagehide","popstate","hashchange"])window.addEventListener(type,onLeave);document.addEventListener("scroll",onScroll,capture),document.addEventListener("toggle",markCaused,capture);for(let type of["submit","invalid","change","play","copy"])document.addEventListener(type,markLive,capture);sync()}function onClickCapture(e){if(pickerActive)return;let target=e.target;if(!(target instanceof Element))return;let interactive=findInteractiveAncestor(target);if(!interactive||isSensitive(interactive))return;let ev=createClickEvent(interactive);holdClick(e,ev)||enqueue(ev)}function onSubmitCapture(e){if(pickerActive)return;let form=e.target;form instanceof HTMLFormElement&&(isSensitive(form)||!config.autocapture&&!extractDataTrack(form).dataTrack||enqueue(createFormSubmitEvent(form)))}function onSpaNavigation(){if(pickerActive){onPickerNavigation();return}if(!config.autocapture_pageviews)return;let currentUrl=window.location.href;if(currentUrl===lastUrl)return;let referrer=lastUrl;setLastUrl(currentUrl),resetFrustration(),enqueue(createPageviewEvent(referrer))}function patchHistory(){let origPushState=history.pushState.bind(history),origReplaceState=history.replaceState.bind(history);history.pushState=function(...args){let before=location.href;origPushState(...args),markHistory(location.href!==before),onSpaNavigation()},history.replaceState=function(...args){let before=location.href;origReplaceState(...args),markHistory(location.href!==before),onSpaNavigation()}}var version="1.1.0",initialized=!1,storedInitConfig={};function init(initConfig){if(typeof window>"u")return;if(initialized){console.warn("[tracker] Already initialized. Ignoring duplicate init() call.");return}if(initialized=!0,storedInitConfig=initConfig??{},storedInitConfig.apiKey!==void 0&&setApiKey(storedInitConfig.apiKey),storedInitConfig.apiHost!==void 0&&setApiBase(storedInitConfig.apiHost),!apiKey){console.error("[tracker] Missing apiKey. Events will not be sent.");return}applyInitConfig(storedInitConfig),setLastUrl(window.location.href),config.autocapture_pageviews&&enqueue(createPageviewEvent(document.referrer)),patchHistory(),window.addEventListener("popstate",onSpaNavigation),document.addEventListener("click",onClickCapture,{capture:!0}),document.addEventListener("submit",onSubmitCapture,{capture:!0}),startFrustration(),window.addEventListener("message",onPickerWindowMessage);let pickerHash=parsePickerHash(window.location.hash);if(pickerHash){let{origin,mode}=pickerHash;setPickerDashboardOrigin(origin);let clickMap=mode==="click-map";try{sessionStorage.setItem("st-picker",JSON.stringify({active:!0,origin,...clickMap&&{mode}}))}catch{}history.replaceState(null,"",window.location.pathname+window.location.search),window.opener&&requestPicker(clickMap?{mode}:void 0)}else try{let stored=sessionStorage.getItem("st-picker");if(stored&&window.opener){let parsed=JSON.parse(stored);if(typeof parsed=="object"&&parsed!==null&&"active"in parsed&&"origin"in parsed){let obj=parsed;if(obj.active&&typeof obj.origin=="string"){setPickerDashboardOrigin(obj.origin);let storedScan="scanEnabled"in obj&&obj.scanEnabled===!0,storedNav="navigateMode"in obj&&obj.navigateMode===!0,rawMode="selectorMode"in obj?obj.selectorMode:null;requestPicker({scanEnabled:storedScan,navigateMode:storedNav,selectorMode:rawMode==="generic"||rawMode==="exact"?rawMode:null,..."mode"in obj&&obj.mode==="click-map"&&{mode:"click-map"}})}}}}catch{}document.addEventListener("visibilitychange",()=>{document.visibilityState==="hidden"&&(onFrustrationHide(),flushBeacon())}),fetchConfig().then(result=>{if(!result.loaded){failClosed(result);return}applyInitConfig(storedInitConfig),!trackingDisabled&&(setConfigLoaded(!0),setInterval(()=>{flush()},config.flush_interval_ms),flush())})}function failClosed(result){console.warn(`[tracker] Could not load this project's settings from ${apiBase}/api/config \u2014 ${describeConfigFailure(result)}. No events were sent from this page load: without those settings the tracker cannot apply the project's URL redaction rules, and sending unredacted URLs would be worse than sending nothing.`),disableTracking(queue)}function track(name,attrs){typeof window>"u"||trackingDisabled||name&&enqueue({event_type:"custom",page_url:window.location.href,data_track:name,data_track_attrs:attrs,timestamp:new Date().toISOString()})}function setTraits2(newTraits){typeof window>"u"||setTraits(newTraits)}export{init,setTraits2 as setTraits,track,version};
1
+ function codePointLength(value){let n=0;for(let _ of value)n++;return n}function quote(value){let shown="",n=0;for(let ch of value){if(n===20)return`${JSON.stringify(shown)}\u2026`;shown+=ch,n++}return JSON.stringify(shown)}function describeNonString(value){return typeof value=="number"||typeof value=="boolean"?String(value):value===null?"null":`a value of type ${typeof value}`}function cleanTraits(value){if(!Array.isArray(value))return{traits:[],dropped:[`${describeNonString(value)} (not a list of traits)`]};let traits2=[],dropped=[],seen2=new Set,overLimit=[];for(let raw of value){if(typeof raw!="string"){dropped.push(`${describeNonString(raw)} (not a string)`);continue}let trait=raw.trim();if(trait===""){dropped.push(`${JSON.stringify(raw)} (empty)`);continue}if(codePointLength(trait)>64){dropped.push(`${quote(trait)} (longer than ${String(64)} characters)`);continue}seen2.has(trait)||(seen2.add(trait),traits2.length<50?traits2.push(trait):overLimit.push(quote(trait)))}if(overLimit.length>0){let extra=overLimit.length-10,names=overLimit.slice(0,10).join(", "),tail=extra>0?` and ${String(extra)} more`:"";dropped.push(`${names}${tail} (over the limit of ${String(50)} traits)`)}return{traits:traits2,dropped}}function describeDroppedTraits(source,dropped){let named=dropped.slice(0,10).join("; "),rest=dropped.length-10,more=rest>0?`; and ${String(rest)} more`:"";return`[tracker] ${source} left out traits the API would refuse: ${named}${more}. The other traits are sent as usual.`}function acceptTraits(value,source){let{traits:traits2,dropped}=cleanTraits(value);return dropped.length>0&&console.warn(describeDroppedTraits(source,dropped)),traits2}var LEGACY_DEAD_CLICK_WAIT_MS=5e3,MAX_QUEUE_CAP=100,config={flush_interval_ms:5e3,max_queue_size:10,walk_depth:3,max_text_length:100,autocapture_pageviews:!0,autocapture:!0,autocapture_elements:["a","button","input[type=submit]","[role=button]","[role=link]","[role=menuitem]","[role=menuitemcheckbox]","[role=menuitemradio]","[role=option]","[role=tab]","[role=switch]","[role=checkbox]","[role=radio]","[role=combobox]"],pii_url_params:["email","token","key","password","secret"],normalize_path_ids:!0,pii_path_patterns:[],excluded_urls:[],capture_dead_clicks:!0,capture_rage_clicks:!0,capture_error_clicks:!0,capture_slow_clicks:!0,dead_click_window_ms:1e3,slow_click_threshold_ms:1e3,dead_click_wait_ms:5e3,rage_click_threshold:3,rage_click_window_ms:1e3},apiBase="",apiKey="",configLoaded=!1,trackingDisabled=!1,traits=[];function setApiBase(value){apiBase=value}function setApiKey(value){apiKey=value}function setConfigLoaded(value){configLoaded=value}function setTrackingDisabled(value){trackingDisabled=value}function setTraits(value,source="setTraits()"){traits=acceptTraits(value,source)}function applyServerConfig(server){if(typeof server!="object"||server===null)return;let s=server;if(typeof s.flush_interval_ms=="number"&&(config.flush_interval_ms=s.flush_interval_ms),typeof s.max_queue_size=="number"&&(config.max_queue_size=s.max_queue_size),typeof s.walk_depth=="number"&&(config.walk_depth=s.walk_depth),typeof s.max_text_length=="number"&&(config.max_text_length=s.max_text_length),typeof s.autocapture_pageviews=="boolean"&&(config.autocapture_pageviews=s.autocapture_pageviews),typeof s.autocapture=="boolean"&&(config.autocapture=s.autocapture),Array.isArray(s.autocapture_elements)&&(config.autocapture_elements=s.autocapture_elements),Array.isArray(s.pii_url_params)&&(config.pii_url_params=s.pii_url_params),typeof s.normalize_path_ids=="boolean"&&(config.normalize_path_ids=s.normalize_path_ids),Array.isArray(s.pii_path_patterns)&&(config.pii_path_patterns=s.pii_path_patterns),Array.isArray(s.excluded_urls)&&(config.excluded_urls=s.excluded_urls),typeof s.capture_dead_clicks=="boolean"&&(config.capture_dead_clicks=s.capture_dead_clicks),typeof s.capture_rage_clicks=="boolean"&&(config.capture_rage_clicks=s.capture_rage_clicks),typeof s.capture_error_clicks=="boolean"&&(config.capture_error_clicks=s.capture_error_clicks),typeof s.capture_slow_clicks=="boolean"&&(config.capture_slow_clicks=s.capture_slow_clicks),typeof s.dead_click_window_ms=="number"){let w=s.dead_click_window_ms;config.dead_click_window_ms=w,config.slow_click_threshold_ms=w,config.dead_click_wait_ms=Math.max(w,LEGACY_DEAD_CLICK_WAIT_MS)}typeof s.slow_click_threshold_ms=="number"&&(config.slow_click_threshold_ms=s.slow_click_threshold_ms),typeof s.dead_click_wait_ms=="number"&&(config.dead_click_wait_ms=s.dead_click_wait_ms),typeof s.rage_click_threshold=="number"&&(config.rage_click_threshold=s.rage_click_threshold),typeof s.rage_click_window_ms=="number"&&(config.rage_click_window_ms=s.rage_click_window_ms)}var CONFIG_FETCH_ATTEMPTS=5,CONFIG_RETRY_DELAYS_MS=[500,1e3,2e3,4e3],CONFIG_FETCH_TIMEOUT_MS=3e3;function isRetryableStatus(status){return status===408||status===429||status>=500}function delay(ms){return new Promise(resolve2=>setTimeout(resolve2,ms))}async function attemptConfigFetch(){let controller=new AbortController,timer2=setTimeout(()=>{controller.abort()},CONFIG_FETCH_TIMEOUT_MS);try{let response=await fetch(`${apiBase}/api/config`,{headers:{"X-API-Key":apiKey},credentials:"omit",signal:controller.signal});if(!response.ok)return isRetryableStatus(response.status)?{kind:"retry",status:response.status}:{kind:"permanent",status:response.status};let data=await response.json();return applyServerConfig(data),{kind:"ok"}}catch{return{kind:"retry"}}finally{clearTimeout(timer2)}}async function fetchConfig(){let status;for(let attempt=0;attempt<CONFIG_FETCH_ATTEMPTS;attempt++){let outcome=await attemptConfigFetch();if(outcome.kind==="ok")return{loaded:!0,attempts:attempt+1};if(outcome.kind==="permanent")return{loaded:!1,attempts:attempt+1,status:outcome.status};status=outcome.status;let wait=CONFIG_RETRY_DELAYS_MS[attempt];if(wait===void 0)break;await delay(wait)}return{loaded:!1,attempts:CONFIG_FETCH_ATTEMPTS,...status!==void 0&&{status}}}var CONFIG_FAILURE_REASONS={401:"the API key is missing or not valid",403:"this site's origin is not in the project's allowed domains"};function describeConfigFailure(result){let attempts=result.attempts===1?"1 attempt":`${String(result.attempts)} attempts`;if(result.status===void 0)return`no response after ${attempts} (network error or timeout)`;let reason=CONFIG_FAILURE_REASONS[result.status],http=`HTTP ${String(result.status)}`;return reason===void 0?`${http} after ${attempts}`:`${http} after ${attempts} (${reason})`}function applyInitConfig(initConfig){initConfig.apiKey!==void 0&&(apiKey=initConfig.apiKey),initConfig.apiHost!==void 0&&(apiBase=initConfig.apiHost),initConfig.flushIntervalMs!==void 0&&(config.flush_interval_ms=initConfig.flushIntervalMs),initConfig.maxQueueSize!==void 0&&(config.max_queue_size=initConfig.maxQueueSize),initConfig.walkDepth!==void 0&&(config.walk_depth=initConfig.walkDepth),initConfig.maxTextLength!==void 0&&(config.max_text_length=initConfig.maxTextLength),initConfig.autocapturePageviews!==void 0&&(config.autocapture_pageviews=initConfig.autocapturePageviews),initConfig.autocapture!==void 0&&(config.autocapture=initConfig.autocapture),initConfig.autocaptureElements!==void 0&&(config.autocapture_elements=initConfig.autocaptureElements),initConfig.piiUrlParams!==void 0&&(config.pii_url_params=initConfig.piiUrlParams),typeof initConfig.normalizePathIds=="boolean"&&(config.normalize_path_ids=initConfig.normalizePathIds),Array.isArray(initConfig.piiPathPatterns)&&(config.pii_path_patterns=initConfig.piiPathPatterns),initConfig.excludedUrls!==void 0&&(config.excluded_urls=initConfig.excludedUrls),initConfig.traits!==void 0&&setTraits(initConfig.traits,"The traits setting")}var ID_PATTERNS=[/^\d+$/,/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i,/^[0-9a-f]{8,}$/i];function isIdSegment(segment){return ID_PATTERNS.some(p=>p.test(segment))}function buildPiiPattern(){if(config.pii_url_params.length===0)return null;let escaped=config.pii_url_params.map(p=>p.replace(/[.*+?^${}()|[\]\\]/g,"\\$&"));return new RegExp("("+escaped.join("|")+")","i")}function buildPiiPathPattern(){if(config.pii_path_patterns.length===0)return null;try{return new RegExp("^("+config.pii_path_patterns.join("|")+")$","i")}catch{return null}}function sanitizeUrl(url){try{let u=new URL(url),segments=u.pathname.split("/"),piiPathRegex=buildPiiPathPattern(),pathChanged=!1;for(let i=0;i<segments.length;i++){let seg=segments[i];if(seg){if(config.normalize_path_ids&&isIdSegment(seg)){segments[i]=":id",pathChanged=!0;continue}piiPathRegex?.test(seg)&&(segments[i]=":redacted",pathChanged=!0)}}pathChanged&&(u.pathname=segments.join("/"));let paramPattern=buildPiiPattern();if(paramPattern){let toRedact=[];u.searchParams.forEach((_v,k)=>{paramPattern.test(k)&&toRedact.push(k)});for(let k of toRedact)u.searchParams.set(k,":redacted")}return u.toString()}catch{return url}}function matchGlob(pattern,url){try{let path=new URL(url).pathname,escaped=pattern.replace(/[.+^${}()|[\]\\]/g,"\\$&");return new RegExp("^"+escaped.replace(/\*/g,".*")+"$").test(path)}catch{return!1}}function isExcludedUrl(url){return config.excluded_urls.some(pattern=>matchGlob(pattern,url))}function disableTracking(queue2){setTrackingDisabled(!0),queue2.length=0,config.autocapture_pageviews=!1,config.autocapture=!1}function extractText(el){let raw=el.textContent;if(!raw)return;let trimmed=raw.trim().replace(/\s+/g," ");if(trimmed.length!==0)return trimmed.length>config.max_text_length?trimmed.slice(0,config.max_text_length):trimmed}function extractDataTrack(el){let current=el;for(let i=0;i<=config.walk_depth&&current;i++){let trackValue=current.getAttribute("data-track");if(trackValue!==null){let attrs={};for(let attr of current.attributes)if(attr.name.startsWith("data-track-")){let key=attr.name.slice(11);attrs[key]=attr.value}return{dataTrack:trackValue||void 0,dataTrackAttrs:Object.keys(attrs).length>0?attrs:void 0}}current=current.parentElement}return{dataTrack:void 0,dataTrackAttrs:void 0}}function getSegment(el){let seg=el.tagName.toLowerCase();el instanceof HTMLInputElement&&el.type&&(seg+='[type="'+CSS.escape(el.type)+'"]');let role=el.getAttribute("role");role&&(seg+='[role="'+CSS.escape(role)+'"]');let parent=el.parentElement;if(parent){let tag=el.tagName,siblings=parent.children,sameTag=0,idx=0;for(let i=0;i<siblings.length;i++){let sib=siblings[i];sib&&sib.tagName===tag&&(sameTag++,sib===el&&(idx=sameTag))}sameTag>1&&(seg+=":nth-of-type("+String(idx)+")")}return seg}var BODY="body > ",SEPARATOR=" > ",NTH_OF_TYPE=":nth-of-type(";function normalizeSelector(s){if(!s.startsWith(BODY))return s;let rest=s.slice(BODY.length),i=rest.indexOf(SEPARATOR),first=i>=0?rest.slice(0,i):rest,tail=i>=0?rest.slice(i):"";return BODY+withoutPosition(first)+tail}function withoutPosition(seg){if(!seg.endsWith(")"))return seg;let open=seg.lastIndexOf(NTH_OF_TYPE);if(open<0)return seg;let index=seg.slice(open+NTH_OF_TYPE.length,seg.length-1);if(index==="")return seg;for(let k=0;k<index.length;k++){let c=index[k];if(c===void 0||c<"0"||c>"9")return seg}return seg.slice(0,open)}function capped(parts){let result=parts.join(SEPARATOR);for(;result.length>200&&parts.length>1;)parts.shift(),result=parts.join(SEPARATOR);return result}function computeSelector(target){let parts=[],el=target;for(;el&&el!==document.documentElement;)parts.unshift(getSegment(el)),el=el.parentElement;return capped(normalizeSelector(parts.join(SEPARATOR)).split(SEPARATOR))}function getGenericSegment(el){let seg=el.tagName.toLowerCase();el instanceof HTMLInputElement&&el.type&&(seg+='[type="'+CSS.escape(el.type)+'"]');let role=el.getAttribute("role");return role&&(seg+='[role="'+CSS.escape(role)+'"]'),seg}function computeGenericSelector(target){let parts=[],el=target;for(;el&&el!==document.documentElement;)parts.unshift(getGenericSegment(el)),el=el.parentElement;return capped(parts)}function createPageviewEvent(referrer){return{event_type:"pageview",page_url:window.location.href,referrer:referrer===""?void 0:referrer,timestamp:new Date().toISOString()}}function createClickEvent(el){return createElementEvent(el,"click")}function createElementEvent(el,type){let{dataTrack,dataTrackAttrs}=extractDataTrack(el);return{event_type:type,page_url:window.location.href,element_tag:el.tagName.toLowerCase(),element_selector:computeSelector(el),element_selector_generalized:computeGenericSelector(el),element_text:extractText(el),data_track:dataTrack,data_track_attrs:dataTrackAttrs,timestamp:new Date().toISOString()}}function createFormSubmitEvent(form){let{dataTrack,dataTrackAttrs}=extractDataTrack(form);return{event_type:"form_submit",page_url:window.location.href,element_tag:form.tagName.toLowerCase(),element_selector:computeSelector(form),element_selector_generalized:computeGenericSelector(form),data_track:dataTrack,data_track_attrs:dataTrackAttrs,timestamp:new Date().toISOString()}}var pickerActive=!1,pickerDashboardOrigin=null;function setPickerActive(value){pickerActive=value}function setPickerDashboardOrigin(value){pickerDashboardOrigin=value}function backoffMs(attempt,random){let base=Math.min(6e4,2e3*2**Math.max(0,attempt-1));return Math.round(base/2+base/2*Math.min(1,Math.max(0,random)))}function retryAfterMs(value,now){if(value===null)return null;let v=value.trim(),ms;if(/^\d+$/.test(v))ms=Number(v)*1e3;else{let at=Date.parse(v);if(Number.isNaN(at))return null;ms=at-now}return Math.min(6e5,Math.max(0,ms))}function waitMs(attempt,retryAfter,random){return retryAfter===null?backoffMs(attempt,random):Math.max(retryAfter,backoffMs(1,random))}var REJECTION_REASONS={401:"the API key is missing or not valid",403:"this site's origin is not in the project's allowed domains",429:"the project is over its plan's monthly event limit"},MONTHLY_LIMIT="limit_events_per_month",MAX_BATCH=100,backoff={until:0,attempts:0,noted:!1},queue=[],lastUrl="",isFlushing=!1;function setLastUrl(value){lastUrl=value}function sanitizeEvent(event){let pageUrl=sanitizeUrl(event.page_url),referrer=event.referrer===void 0?void 0:sanitizeUrl(event.referrer);return pageUrl===event.page_url&&referrer===event.referrer?event:{...event,page_url:pageUrl,...referrer!==void 0&&{referrer}}}function prepareEvents(events){return filterEvents(events.map(sanitizeEvent))}function filterEvents(events){return events.filter(event=>!(isExcludedUrl(event.page_url)||event.event_type==="pageview"&&!config.autocapture_pageviews||(event.event_type==="click"||event.event_type==="form_submit")&&!config.autocapture&&!event.data_track||event.event_type==="dead_click"&&!(config.autocapture&&config.capture_dead_clicks)||event.event_type==="rage_click"&&!(config.autocapture&&config.capture_rage_clicks)||event.event_type==="error_click"&&!(config.autocapture&&config.capture_error_clicks)||event.event_type==="slow_click"&&!(config.autocapture&&config.capture_slow_clicks)))}function enqueue(event){trackingDisabled||pickerActive||apiKey&&(queue.length>=MAX_QUEUE_CAP||(queue.push(event),configLoaded&&queue.length>=config.max_queue_size&&flush()))}var flushing=null;async function flush(){if(trackingDisabled||pickerActive||!configLoaded||isFlushing||queue.length===0||Date.now()<backoff.until)return;isFlushing=!0;let events=prepareEvents(queue.splice(0,MAX_BATCH));if(events.length===0){isFlushing=!1;return}let sent=send(events,!1,null);flushing=sent;try{await sent}finally{flushing=null,isFlushing=!1}}async function send(events,beacon,before){let body={events,...traits.length>0&&{traits}};beacon&&apiKey&&(body.api_key=apiKey);let headers={"Content-Type":"application/json"};apiKey&&(headers["X-API-Key"]=apiKey);let response;try{response=await fetch(`${apiBase}/api/events`,{method:"POST",headers,body:JSON.stringify(body),keepalive:!0,credentials:"omit"})}catch{return putBack(events,null,before)}if(response.ok)return backoff.until=0,backoff.attempts=0,0;let status=response.status;return status===401||status===403||status===429&&await errorCode(response)===MONTHLY_LIMIT?(trackingDisabled||console.warn(`[tracker] The API rejected events with HTTP ${String(status)} \u2014 ${REJECTION_REASONS[status]??"the request was refused"}. Tracking is now off for this page.`),disableTracking(queue),0):status===429||status>=500?(status===429&&!backoff.noted&&(backoff.noted=!0,console.info("[tracker] The API asked to slow down (HTTP 429). Events are kept and sent again shortly.")),putBack(events,response,before)):0}async function errorCode(response){try{let body=await response.json(),code=typeof body=="object"&&body!==null?body.error_code:void 0;return typeof code=="string"?code:void 0}catch{return}}async function putBack(events,response,before){let at=before?await before:0;return trackingDisabled?0:(queue.splice(Math.min(at,queue.length),0,...events),queue.length>MAX_QUEUE_CAP&&(queue.length=MAX_QUEUE_CAP),backOff(response),events.length)}function backOff(response){backoff.attempts++;let now=Date.now(),told=response?retryAfterMs(response.headers.get("Retry-After"),now):null;backoff.until=now+waitMs(backoff.attempts,told,Math.random())}function flushBeacon(){if(trackingDisabled||!configLoaded||queue.length===0)return;let events=prepareEvents(queue.splice(0,MAX_BATCH));events.length!==0&&send(events,!0,flushing)}function isSensitive(el){if(el instanceof HTMLInputElement){let t=el.type.toLowerCase();if(t==="password"||t==="hidden")return!0}let ac=el.getAttribute("autocomplete");return!!(ac&&ac.toLowerCase().startsWith("cc-"))}function isInteractive(el){if(el.hasAttribute("data-track"))return!0;if(!config.autocapture)return!1;for(let selector of config.autocapture_elements)try{if(el.matches(selector))return!0}catch{}return!1}function findInteractiveAncestor(target){let el=target;for(let i=0;i<=config.walk_depth&&el;i++){if(isInteractive(el))return el;el=el.parentElement}return null}function isPickerTarget(el){return isInteractive(el)||el.matches("form")}function findPickerTarget(target){let el=target;for(let i=0;i<=config.walk_depth&&el;i++){if(isPickerTarget(el))return el;el=el.parentElement}return null}function trackableElements(){let selectors=["[data-track]"];config.autocapture&&selectors.push("form",...config.autocapture_elements);let seen2=new Set;for(let selector of selectors){let found;try{found=document.querySelectorAll(selector)}catch{continue}for(let el of found)seen2.add(el)}let result=[];for(let el of seen2)isSensitive(el)||result.push(el);return result}var PICKER_HANDOFF_KEY="__stPickerHandoff";var PICKER_FILE="tracker-picker.js",picker=null,loading=!1,failed=!1,pendingOptions=null,pickerHostApi={setActive:setPickerActive,setDashboardOrigin:setPickerDashboardOrigin,clearQueue:()=>{queue.length=0},computeSelector,computeGenericSelector,extractText,extractDataTrack,findPickerTarget,trackableElements,sanitizeUrl};function pickerScriptUrl(){for(let script of document.querySelectorAll("script[src]")){let src=script.getAttribute("src");if(src?.includes("tracker.js"))try{return new URL(PICKER_FILE,new URL(src,document.baseURI)).toString()}catch{}}return apiBase?apiBase.replace(/\/+$/,"")+"/"+PICKER_FILE:"/"+PICKER_FILE}function registerPicker(module){if(picker=module,loading=!1,pendingOptions){let options=pendingOptions;pendingOptions=null,activate(module,options)}}function activate(module,options){module.activate({...options,dashboardOrigin:pickerDashboardOrigin})}function abandonLoad(url){loading=!1,failed=!0,pendingOptions=null,setPickerActive(!1),console.warn(`[tracker] Could not load the Element Picker from ${url}. Tracking is unaffected.`)}function loadPicker(){let url=pickerScriptUrl(),script=document.createElement("script");script.src=url,script.async=!0,script[PICKER_HANDOFF_KEY]={host:pickerHostApi,register:registerPicker},script.addEventListener("load",()=>{script.remove(),picker||abandonLoad(url)}),script.addEventListener("error",()=>{script.remove(),abandonLoad(url)}),document.head.appendChild(script)}function requestPicker(options){if(picker){activate(picker,options??{});return}failed||(setPickerActive(!0),queue.length=0,pendingOptions=options??{},!loading&&(loading=!0,loadPicker()))}function onPickerNavigation(){picker?.onNavigation()}function onPickerWindowMessage(e){if(picker){picker.handleMessage(e);return}if(typeof e.data!="object"||e.data===null)return;let data=e.data;data.type==="st-picker-activate"&&(pickerDashboardOrigin&&e.origin!==pickerDashboardOrigin||pickerActive||!window.opener||requestPicker(data.mode==="click-map"?{mode:"click-map"}:void 0))}function parsePickerHash(hash){let m=/^#st-picker=([^&]+)(?:&(.*))?$/.exec(hash),raw=m?.[1];if(!m||!raw)return null;let origin;try{origin=decodeURIComponent(raw)}catch{return null}let mode="rules";for(let pair of(m[2]??"").split("&"))pair==="mode=click-map"&&(mode="click-map");return{origin,mode}}var PRESS_MS=5e3,press=null;function disabled(el){return el.matches(":is(button,input,select,textarea):disabled")||el.getAttribute("aria-disabled")==="true"}function notePress(e){if(press=null,!e.isTrusted||e.button!==0)return;let target=e.target;if(!(target instanceof Element))return;let control=findInteractiveAncestor(target);!control||isSensitive(control)||disabled(control)||(press={id:e.pointerId,control,rect:control.getBoundingClientRect(),at:Date.now(),click:null,target:null})}function inside(r,x,y){return x>=r.left&&x<=r.right&&y>=r.top&&y<=r.bottom}function clickTarget(e){let target=e.target,p=press;if(!p||!e.isTrusted||e.detail===0)return target;if(p.click===e)return p.target??target;if(p.click!==null||(p.click=e,!(target instanceof Element)||findInteractiveAncestor(target)!==null||Date.now()-p.at>PRESS_MS||!p.control.isConnected))return target;let id=e.pointerId;if(typeof id=="number"&&id!==-1&&id!==p.id)return target;let x=e.clientX,y=e.clientY;return!inside(p.rect,x,y)&&!inside(p.control.getBoundingClientRect(),x,y)?target:(p.target=p.control,p.control)}function findLooksClickable(target,depth,parent,look2){let el=target;for(let i=0;i<=depth&&el;i++){let f=look2(el);if(f&12)return null;if(f&1){let top=el,up=parent(el);for(;up;i++){let g=look2(up);if(!(g&1))return top;if(g&8||i>=depth)return null;top=up,up=parent(up)}return top}if(f&2)return el;el=parent(el)}return null}function walkUp(target,depth,parent,pred){let el=target;for(let i=0;i<=depth&&el;i++){if(pred(el))return el;el=parent(el)}return null}function leavesDocument(href,page){try{let u=new URL(href,page);if(u.protocol==="javascript:")return!1;if(!href.includes("#"))return!0;let p=new URL(page);return u.hash="",p.hash="",u.href!==p.href}catch{return!0}}function reloadsDocument(href,page){try{let u=new URL(href,page);if(u.protocol==="javascript:")return!1;let p=new URL(page);return u.hash="",p.hash="",u.href===p.href}catch{return!1}}var UNDECIDED=0,FOLLOWED=1,CANCELLED=2,INTERCEPTED=3;function linkFate(dispatching,prevented){return prevented?CANCELLED:dispatching?UNDECIDED:FOLLOWED}function navFate(dispatching,done,inFlight){return dispatching?UNDECIDED:done?FOLLOWED:inFlight?INTERCEPTED:FOLLOWED}function abortMeans(navigationType,userInitiated){return navigationType==="traverse"||userInitiated?"moved-on":"live"}function decideLinks(pending2,fate){for(let i=0;i<pending2.length;i++){let p=pending2[i];if(p?.link===void 0)continue;let f=fate(p);f===FOLLOWED?pending2.splice(i--,1):f!==UNDECIDED&&delete p.link}}function elementKey(ev){return JSON.stringify([ev.element_selector_generalized??null,ev.element_text??null,ev.element_tag??null])}var MAX_REPORTED=100;function claim(seen2,key){return seen2.has(key)||seen2.size>=MAX_REPORTED?!1:(seen2.add(key),!0)}function nextBurst(burst2,key,first,now,windowMs){return burst2?.key===key&&now-burst2.last<=windowMs?(burst2.count++,burst2.last=now,burst2):{key,first,count:1,last:now}}var MAX_CLICK_COUNT=1e3;function rageCount(count,threshold,selected=!1){return count>=Math.max(selected?4:3,threshold)?Math.min(count,MAX_CLICK_COUNT):null}function selectionIsEffect(current,made,touchesMade=!1){return current!==null&&!touchesMade&&!(made&&made.anchor===current.anchor&&made.anchorOffset===current.anchorOffset&&made.focus===current.focus&&made.focusOffset===current.focusOffset)}var MAX_PENDING=8;function openWindow(pending2,seen2,p){if(seen2.every(s=>s.has(p.key))||pending2.length>=MAX_PENDING)return!1;for(let q of pending2)if(q.key===p.key)return!1;return pending2.push(p),!0}var IGNORE=0,LIVE=1,CAUSED=2,SUSPECT=3;function classify(related,noisy2,global=!1,ticking=!1){return noisy2?related?LIVE:IGNORE:related||global?CAUSED:ticking?SUSPECT:LIVE}function isRelated(node,el,depth,parent,contains2){return contains2(el,node)||walkUp(el,depth,parent,n=>n===node)!==null}function inHead(node,head,contains2){return head!==null&&contains2(head,node)}var DRAWS_NOTHING=/^(script|title|meta|base|noscript|template)$/;function drawsNothing(tag,rel){return tag==="link"?!/(^|\s)stylesheet(\s|$)/i.test(rel??""):DRAWS_NOTHING.test(tag)}function unseenMutation(type,target,attribute,added,removed,read){let silent=el=>{let tag=el===null?null:read.tag(el);return el!==null&&tag!==null&&drawsNothing(tag,read.rel(el))};if(type==="attributes"&&attribute==="rel"&&read.tag(target)==="link")return!1;if(type!=="childList")return silent(read.tag(target)===null?read.parent(target):target);for(let nodes of[added,removed])for(let i=0;i<nodes.length;i++){let n=nodes[i];if(read.tag(n)!==null?!silent(n):!read.blank(n)&&!silent(target))return!1}return!0}var NOISE_GAP_MS=6e3,NOISE_REPEAT_MS=250;function noteStreak(s,t){return s?(t-s.last>NOISE_GAP_MS?(s.start=s.beatAt=t,s.since=1/0,s.beats=1):(s.since===1/0&&t-s.start>=NOISE_REPEAT_MS&&(s.since=t),t-s.beatAt>=NOISE_REPEAT_MS&&(s.beats++,s.beatAt=t)),s.last=t,s):{start:t,last:t,since:1/0,beats:1,beatAt:t}}function noisyAt(s,at){return s!==void 0&&s.since<at}function tickingAt(s,at,t){return s!==void 0&&s.start<at&&t-s.last<=NOISE_GAP_MS}var MAX_DOUBTS=8;function addDoubt(doubts,node,t,beats){for(let d of doubts)if(d.node===node)return!0;return doubts.length>=MAX_DOUBTS?!1:(doubts.push({node,t,beats}),!0)}function judgeDoubts(doubts,at,now,streakOf2){let open=!1;for(let d of doubts){let s=streakOf2(d.node);if(!s||s.start>=at||now-s.last>NOISE_GAP_MS)return"live";s.beats-d.beats<2&&(open=!0)}return open?"open":"noise"}var NONE=0,DROP=1,SLOW=2,DOUBT=3;function effectOn(p,kind,t){return kind===IGNORE?NONE:kind===SUSPECT?DOUBT:kind===LIVE||t<p.slowAt||t>=p.due?DROP:SLOW}function effectOnRoute(p,answers,kind,t){return kind===IGNORE?NONE:!answers||kind===SUSPECT?(p.stirred=!0,NONE):effectOn(p,kind,t)===SLOW?SLOW:DROP}function moveOn(pending2,now,el){for(let p of pending2)p.el!==el&&!p.verdict&&(p.due=Math.max(p.slowAt,Math.min(p.due,now)))}var MAX_RESPONSE_MS=6e4;function responseMs(at,t){return Math.min(MAX_RESPONSE_MS,Math.max(0,Math.round(t-at)))}function errorEventCounts(trusted,rejection){return trusted||rejection}var ERROR_NAME=/^[A-Za-z_$][A-Za-z0-9_$.]{0,63}$/;function errorType(err,rejection){if(!(err instanceof Error))return rejection?"UnhandledRejection":"Error";let name;try{name=err.name}catch{return"Error"}return typeof name=="string"&&ERROR_NAME.test(name)?name:"Error"}function ambientError(last,at,windowMs){return last!==void 0&&last<at&&at-last<=windowMs}function takeSettled(pending2,now,final,streakOf2,gone2=()=>!1){let out=[];for(let i=0;i<pending2.length;i++){let p=pending2[i];if(!p)continue;if(!p.verdict){if(p.due>now)continue;if(p.stirred&&(p.appeared||!gone2(p))){pending2.splice(i--,1);continue}p.verdict="dead"}let j=judgeDoubts(p.doubts,p.at,now,streakOf2);if(j==="open"&&!final){p.due<=now&&(p.due=now+NOISE_REPEAT_MS);continue}pending2.splice(i--,1),j==="noise"&&out.push(p)}return out}function nextDue(pending2){let next=1/0;for(let p of pending2)p.due<next&&(next=p.due);return next}function holdsClick(prev,key,now,windowMs,detail){return detail!==0&&prev?.key===key&&now-prev.at<=windowMs}var MAX_HELD=32;function openHeld(held2,el,at,due,live2){if(held2.length>=MAX_HELD)return null;let h={ev:null,el,at,due,live:live2};return held2.push(h),h}function attachHeld(held2,h,ev){let i=held2.indexOf(h);return i<0?!1:h.live?(held2.splice(i,1),!1):(h.ev=ev,!0)}function releaseHeld(held2,did=()=>!0){let out=[];for(let i=0;i<held2.length;i++){let h=held2[i];!h||h.live||!did(h)||(h.ev!==null?(out.push(h.ev),held2.splice(i--,1)):h.live=!0)}return out}function takeDueHeld(held2,now){let out=[];for(let i=0;i<held2.length;i++){let h=held2[i];h&&h.due<=now&&(h.ev!==null&&!h.live&&out.push(h.ev),held2.splice(i--,1))}return out}function heldWaiting(held2){for(let h of held2)if(!h.live)return!0;return!1}var PRESS_MS2=5e3,STALL_MS=250,MAX_ERROR_TYPES=32;function newSeen(){return{dead:new Set,rage:new Set,slow:new Set,error:new Set}}var seen=newSeen(),nav=null,aborted=null,pending=[],burst=null,lastKey="",madeSel=null,madeEl=null,lastClick=null,held=[],holding=null,holdTarget=null,errClick=null,errorTimes=new Map,streaks=new WeakMap,pressTarget=null,pressEl=null,pressAt=0,pressUntil=0,pressEffect=!1,pressDoubts=[],inTask=!1,observer=null,observing=!1,listening=!1,timer,timerDue=0,live=()=>LIVE,caused=()=>CAUSED,notNav=p=>!p.nav;function parentOf(el){return el.parentElement}function nearParent(n){let p=n.parentNode;return p instanceof Element&&p!==document.body&&p!==document.documentElement?p:null}function contains(outer,inner){return outer.contains(inner)}function noisy(node,at){return walkUp(node,config.walk_depth,nearParent,n=>noisyAt(streaks.get(n),at))!==null}function tickingNode(node,at,t){let found=null,n=node;for(let i=0;i<=config.walk_depth&&n;i++)tickingAt(streaks.get(n),at,t)&&(found=n),n=nearParent(n);return found}function streakOf(n){return streaks.get(n)}function note(node,t){let s=streaks.get(node),n=noteStreak(s,t);s||streaks.set(node,n)}function isDisabled(el){return el.matches(":is(button,input,select,textarea):disabled")||el.getAttribute("aria-disabled")==="true"&&isInteractive(el)}function isEditable(el){return el instanceof HTMLInputElement?!/^(button|submit|image)$/.test(el.type):/^(TEXTAREA|SELECT)$/.test(el.tagName)||el.isContentEditable}function look(el){if(/^(canvas|video|audio|input|textarea|select)$/i.test(el.tagName)||isEditable(el))return 4;let s=getComputedStyle(el),f=s.cursor==="pointer"?1:0;return el===document.body||el===document.documentElement?f|8:el.tagName==="IMG"||el.tagName==="svg"||s.textDecorationLine.includes("underline")?f|2:f}function active(){return!pickerActive&&!trackingDisabled&&config.autocapture&&(config.capture_dead_clicks||config.capture_rage_clicks||config.capture_slow_clicks||config.capture_error_clicks)}function rolling(){return active()&&(config.capture_dead_clicks||config.capture_slow_clicks)}function idle(links=!0){return(links?pending.length===0:pending.every(p=>p.link))&&(pressEffect||!pressTarget)&&!heldWaiting(held)}function fateOf(p){let e=p.link;if(!e)return FOLLOWED;let f=linkFate(e.eventPhase!==0,e.defaultPrevented);if(f!==FOLLOWED||!p.nav)return f;let n=navigation();return navFate(p.nav.e.eventPhase!==0,p.nav.done,!!n&&n.transition!==null)}function navigation(){return window.navigation??null}function gone(p){let a=p.route;if(!a)return!1;if(!a.isConnected)return!0;if(a.getClientRects().length>0)return!1;if(getComputedStyle(a).display!=="contents")return!0;for(let i=0;i<a.children.length;i++)if((a.children[i]?.getClientRects().length??0)>0)return!1;return!0}function decide(){decideLinks(pending,fateOf)}function resolve(target){if(target.closest("#st-picker-host"))return null;let control=findInteractiveAncestor(target);if(control)return isSensitive(control)||isEditable(control)?null:control;let t=target;for(;t instanceof SVGElement&&t.ownerSVGElement;)t=t.ownerSVGElement;let el=findLooksClickable(t,config.walk_depth,parentOf,look);return el&&!isSensitive(el)?el:null}function selection(){let s=getSelection();return s&&!s.isCollapsed?{anchor:s.anchorNode,anchorOffset:s.anchorOffset,focus:s.focusNode,focusOffset:s.focusOffset}:null}function selectionEffect(){let s=getSelection();return selectionIsEffect(selection(),madeSel,!!madeEl&&!!s&&s.containsNode(madeEl,!0))}function startTask(){inTask||(inTask=!0,setTimeout(()=>{inTask=!1},0))}function report(el,now,detail,dead,target,doubts,disabled2=!1,click){let ev=createElementEvent(el,"dead_click"),key=elementKey(ev),rage=detail!==0,threshold=config.slow_click_threshold_ms,wait=Math.max(threshold,config.dead_click_wait_ms),multi=detail>=2&&key===lastKey;if(madeSel=multi?selection():null,madeEl=multi?el:null,lastKey=key,holding=null,holdTarget=target,rage&&(holdsClick(lastClick,key,now,config.rage_click_window_ms,detail)&&(holding=openHeld(held,el,now,now+threshold,!dead)),lastClick={key,at:now}),rage&&config.capture_rage_clicks){let next=nextBurst(burst,key,ev,now,config.rage_click_window_ms);next!==burst&&endBurst(),burst=next;let s=getSelection();next.selected=!!s&&!s.isCollapsed&&s.containsNode(el,!0)}errClick=config.capture_error_clicks&&!seen.error.has(key)?{key,ev,el,at:now,due:now+wait}:null;let link=el.closest("a[href]"),href=link?.getAttribute("href")??"",leaves=!!link&&leavesDocument(href,location.href),reloads=leaves&&reloadsDocument(href,location.href),route=leaves&&click&&!reloads?link:null;if((dead||route)&&!(leaves&&(!click||reloads))&&!el.closest("label")){let kinds=[];config.capture_dead_clicks&&kinds.push(seen.dead),config.capture_slow_clicks&&!disabled2&&kinds.push(seen.slow);let slowAt=now+threshold,p={key,ev,el,at:now,slowAt,due:disabled2?slowAt:now+wait,doubts:route?[]:doubts.slice(),seen};route&&(p.link=click,p.route=route,(!dead||doubts.length>0)&&(p.stirred=!0)),openWindow(pending,kinds,p)&&route&&setTimeout(sync,0)}sync()}function endBurst(){let b=burst;burst=null;let n=b&&rageCount(b.count,config.rage_click_threshold,b.selected);b&&n&&claim(seen.rage,b.key)&&enqueue({...b.first,event_type:"rage_click",click_count:n})}function happen(kindAt,suspect,answers,appears=!1){let t=Date.now();decide();let doubt=(doubts,at)=>{let n=suspect?.(at),s=n?streaks.get(n):void 0;return!!n&&!!s&&addDoubt(doubts,n,t,s.beats)};if(pressTarget&&!pressEffect){let k=inTask||!pressEl?LIVE:kindAt(pressEl,pressAt);k!==IGNORE&&!(k===SUSPECT&&doubt(pressDoubts,pressAt))&&(pressEffect=!0)}for(let i=0;i<pending.length;i++){let p=pending[i];if(!p||p.verdict)continue;if(p.route){let k=inTask?LIVE:kindAt(p.el,p.at),r2=effectOnRoute(p,answers?.(p)??!1,k,t);r2===NONE&&appears&&k!==IGNORE&&(p.appeared=!0),r2===SLOW?(p.verdict="slow",p.answeredAt=t):r2!==NONE&&pending.splice(i--,1);continue}let r=effectOn(p,inTask?LIVE:kindAt(p.el,p.at),t);r===NONE||r===DOUBT&&doubt(p.doubts,p.at)||(r===SLOW?(p.verdict="slow",p.answeredAt=t):pending.splice(i--,1))}let did=h=>{let k=inTask?LIVE:kindAt(h.el,h.at);return k!==IGNORE&&k!==SUSPECT};for(let ev of releaseHeld(held,did))enqueue(ev)}function markLive(){idle()||(happen(live),sync())}function markCaused(){idle()||(happen(caused),sync())}function onToggle(e){idle()||(happen(caused,void 0,void 0,e.newState!=="closed"),sync())}function markHistory(changed){changed?idle()||(happen(caused,void 0,notNav),sync()):markLive()}function settle(now,final){decide();for(let p of takeSettled(pending,now,final,streakOf,gone))p.verdict==="slow"?config.capture_slow_clicks&&claim(p.seen.slow,p.key)&&enqueue({...p.ev,event_type:"slow_click",response_ms:responseMs(p.at,p.answeredAt??now)}):config.capture_dead_clicks&&claim(p.seen.dead,p.key)&&enqueue(p.ev)}function movedOn(now,el,errors){if(errors&&errClick&&errClick.el!==el&&(errClick=null),pending.length===0)return;let records=observer?.takeRecords();records?.length&&onMutations(records),selectionEffect()&&happen(live),moveOn(pending,now,el),settle(now,!1)}var reader={tag:n=>n instanceof Element?n.tagName.toLowerCase():null,rel:n=>n instanceof Element?n.getAttribute("rel"):null,blank:n=>n.nodeType===8||!n.textContent?.trim(),parent:n=>n.parentNode};function unseen(r,head){return inHead(r.target,head,contains)&&unseenMutation(r.type,r.target,r.attributeName,r.addedNodes,r.removedNodes,reader)}function adds(r,head){if(r.type!=="childList"||inHead(r.target,head,contains))return!1;for(let i=0;i<r.addedNodes.length;i++){let n=r.addedNodes[i];if(n&&(n instanceof Element||!reader.blank(n)))return!0}return!1}function onMutations(records){let t=Date.now(),head=document.head,shown=records;for(let r of records)if(unseen(r,head)){shown=records.filter(q=>!unseen(q,head));break}for(let r of shown)note(r.target,t);for(let r of shown){if(idle())break;let node=r.target,dialog=r.attributeName==="open"&&/^(DIALOG|DETAILS)$/.test(node.nodeName);happen(dialog?caused:(el,at)=>classify(isRelated(node,el,config.walk_depth,nearParent,contains),noisy(node,at),!1,tickingNode(node,at,t)!==null),at=>tickingNode(node,at,t),p=>!!p.route&&p.route.contains(node)&&(node!==p.route||r.type!=="attributes"||r.attributeName==="aria-busy"),dialog&&node instanceof Element&&node.hasAttribute("open")||adds(r,head))}sync()}function holdClick(e,ev){let h=holding;return holding=null,!!h&&e.isTrusted&&e.detail!==0&&clickTarget(e)===holdTarget&&attachHeld(held,h,ev)}function onFocusIn(e){let f=e.target;pressTarget&&f instanceof Node&&f.contains(pressTarget)||markCaused()}function onScroll(e){let node=e.target instanceof Node?e.target:document;note(node,Date.now()),!idle()&&(happen((el,at)=>classify(node.contains(el),noisyAt(streaks.get(node),at),!0)),sync())}function onKeyDown(e){if(!e.isTrusted||pending.length===0&&!errClick)return;let t=e.target;movedOn(Date.now(),(e.key==="Enter"||e.key===" ")&&t instanceof Element?t:null,!0),sync()}function onWheel(e){!e.isTrusted||pending.length===0||(movedOn(Date.now(),null,!1),sync())}function onLeave(){movedOn(Date.now(),null,!1),markLive(),sync()}function onNavigate(e){let prev=aborted??(nav&&!nav.done?nav:null);if(aborted=null,prev){prev.done=!0;let ne=e;abortMeans(ne.navigationType??"",ne.userInitiated===!0)==="moved-on"?navMovedOn(prev):navAnswer(prev,!1)}let n={e,done:!1};nav=n;for(let p of pending){let c=p.link;c&&c.eventPhase===0&&!c.defaultPrevented&&!p.nav&&(p.nav=n)}}function navDone(ok){let n=nav;!n||n.done||(n.done=!0,navAnswer(n,ok))}function onNavigateError(e){let n=nav,err=e.error;if(!(typeof err=="object"&&err!==null&&err.name==="AbortError")||!n||n.done){navDone(!1);return}n.done=!0,aborted=n,setTimeout(()=>{aborted===n&&(aborted=null,navAnswer(n,!1))},0)}function navMovedOn(n){decide();let now=Date.now();for(let p of pending)p.nav===n&&!p.link&&!p.verdict&&(p.due=Math.max(p.slowAt,Math.min(p.due,now)));sync()}function navAnswer(n,ok){if(pending.length===0)return;let t=Date.now();decide();for(let i=0;i<pending.length;i++){let p=pending[i];if(!p||p.nav!==n||p.link||p.verdict)continue;let r=effectOnRoute(p,!0,ok?CAUSED:LIVE,t);r===SLOW?(p.verdict="slow",p.answeredAt=t):r!==NONE&&pending.splice(i--,1)}sync()}function noteError(type){let now=Date.now(),last=errorTimes.get(type);last===void 0&&errorTimes.size>=MAX_ERROR_TYPES&&errorTimes.clear(),errorTimes.set(type,now);let c=errClick;!c||now>c.due||!active()||!config.capture_error_clicks||!inTask&&ambientError(last,c.at,NOISE_GAP_MS)||(errClick=null,claim(seen.error,c.key)&&enqueue({...c.ev,event_type:"error_click",error_type:type}))}function onError(e){e instanceof ErrorEvent&&errorEventCounts(e.isTrusted,!1)&&noteError(errorType(e.error,!1))}function onRejection(e){errorEventCounts(e.isTrusted,!0)&&noteError(errorType(e.reason,!0))}function sync(){settle(Date.now(),!1);let watch=!idle(),observe=watch||rolling();observe!==observing&&(observe?(typeof MutationObserver=="function"&&(observer??=new MutationObserver(onMutations)),observer?.observe(document,{subtree:!0,childList:!0,attributes:!0,characterData:!0})):observer?.disconnect(),observing=observe);let leave=watch&&!idle(!1);leave!==listening&&(listening=leave,leave?window.addEventListener("beforeunload",onLeave):window.removeEventListener("beforeunload",onLeave));let next=Math.min(nextDue(pending),nextDue(held),burst?burst.last+config.rage_click_window_ms+1:1/0,pressTarget?pressUntil:1/0);clearTimeout(timer),timer=void 0,next<1/0&&(timerDue=next,timer=setTimeout(tick,Math.max(0,next-Date.now())))}function tick(){let now=Date.now(),late=now-timerDue>STALL_MS,records=observer?.takeRecords();records?.length&&onMutations(records),(late||selectionEffect())&&happen(live),settle(now,!1);for(let ev of takeDueHeld(held,now))active()||enqueue(ev);burst&&now-burst.last>config.rage_click_window_ms&&endBurst(),pressTarget&&now>=pressUntil&&(pressTarget=pressEl=null),sync()}function onPointerDown(e){if(!e.isTrusted)return;let target=e.target,now=Date.now();if(!(target instanceof Element)||e.button!==0||!active()){movedOn(now,null,!0),sync();return}let disabled2=walkUp(target,config.walk_depth,parentOf,isDisabled),el=disabled2??resolve(target);if(movedOn(now,el,!0),startTask(),holding=null,pressTarget=target,pressEffect=!1,pressDoubts=[],pressAt=now,pressUntil=now+PRESS_MS2,disabled2){pressEl=null,pressEffect=!0,!isSensitive(disabled2)&&!target.closest("#st-picker-host")?report(disabled2,now,1,!0,target,[],!0):sync();return}pressEl=el,pressEl||(pressTarget=null),sync()}function onClick(e){if(!e.isTrusted||!active())return;let target=clickTarget(e);if(!(target instanceof Element))return;startTask();let press2=pressTarget,effect=press2!==null&&pressEffect,el=press2===target?pressEl:resolve(target);pressTarget=pressEl=null;let multi=e.detail>=2;el&&!walkUp(target,config.walk_depth,parentOf,isDisabled)&&(isInteractive(el)||multi||getSelection()?.isCollapsed!==!1)?report(el,Date.now(),e.detail,!effect,target,press2?pressDoubts:[],!1,e):sync()}function onFrustrationHide(){onLeave(),settle(Date.now(),!0),endBurst()}function resetFrustration(){let own=nav&&!nav.done?nav:null,waiting=own?pending.filter(p=>p.nav===own):[];for(let p of waiting)pending.splice(pending.indexOf(p),1);movedOn(Date.now(),null,!1),markLive();for(let p of waiting)pending.push(p);waiting.length>0&&sync(),endBurst(),lastClick=null,lastKey="",madeSel=null,madeEl=null,seen=newSeen()}function startFrustration(){let capture={capture:!0,passive:!0};window.addEventListener("pointerdown",onPointerDown,capture),window.addEventListener("click",onClick,capture),window.addEventListener("focusin",onFocusIn,capture),window.addEventListener("keydown",onKeyDown,capture),window.addEventListener("wheel",onWheel,capture),window.addEventListener("error",onError),window.addEventListener("unhandledrejection",onRejection);for(let type of["blur","pagehide","popstate","hashchange"])window.addEventListener(type,onLeave);let n=navigation();n&&(n.addEventListener("navigate",onNavigate),n.addEventListener("navigatesuccess",()=>{navDone(!0)}),n.addEventListener("navigateerror",onNavigateError)),document.addEventListener("scroll",onScroll,capture),document.addEventListener("toggle",onToggle,capture);for(let type of["submit","invalid","change","play","copy"])document.addEventListener(type,markLive,capture);sync()}function onClickCapture(e){if(pickerActive)return;let target=clickTarget(e);if(!(target instanceof Element))return;let interactive=findInteractiveAncestor(target);if(!interactive||isSensitive(interactive))return;let ev=createClickEvent(interactive);holdClick(e,ev)||enqueue(ev)}function onSubmitCapture(e){if(pickerActive)return;let form=e.target;form instanceof HTMLFormElement&&(isSensitive(form)||!config.autocapture&&!extractDataTrack(form).dataTrack||enqueue(createFormSubmitEvent(form)))}function onSpaNavigation(){if(pickerActive){onPickerNavigation();return}if(!config.autocapture_pageviews)return;let currentUrl=window.location.href;if(currentUrl===lastUrl)return;let referrer=lastUrl;setLastUrl(currentUrl),resetFrustration(),enqueue(createPageviewEvent(referrer))}var inHistoryCall=!1;function patchHistory(){let origPushState=history.pushState.bind(history),origReplaceState=history.replaceState.bind(history);history.pushState=function(...args){let before=location.href;inHistoryCall=!0;try{origPushState(...args)}finally{inHistoryCall=!1}markHistory(location.href!==before),onSpaNavigation()},history.replaceState=function(...args){let before=location.href;inHistoryCall=!0;try{origReplaceState(...args)}finally{inHistoryCall=!1}markHistory(location.href!==before),onSpaNavigation()}}function listenNavigation(){window.navigation?.addEventListener("currententrychange",()=>{inHistoryCall||onSpaNavigation()})}var version="1.2.0",initialized=!1,storedInitConfig={};function init(initConfig){if(typeof window>"u")return;if(initialized){console.warn("[tracker] Already initialized. Ignoring duplicate init() call."+(apiKey?"":" The first init() call had no apiKey, so tracking stays off for this page load."));return}if(initialized=!0,storedInitConfig=initConfig??{},storedInitConfig.apiKey!==void 0&&setApiKey(storedInitConfig.apiKey),storedInitConfig.apiHost!==void 0&&setApiBase(storedInitConfig.apiHost),!apiKey){console.error("[tracker] Missing apiKey. Events will not be sent. Later init() calls are ignored, so call init() once, with the key.");return}storedInitConfig.traits!==void 0&&(storedInitConfig={...storedInitConfig,traits:acceptTraits(storedInitConfig.traits,"The traits setting")}),applyInitConfig(storedInitConfig),setLastUrl(window.location.href),config.autocapture_pageviews&&enqueue(createPageviewEvent(document.referrer)),patchHistory(),window.addEventListener("popstate",onSpaNavigation),listenNavigation(),window.addEventListener("pointerdown",notePress,{capture:!0,passive:!0}),document.addEventListener("click",onClickCapture,{capture:!0}),document.addEventListener("submit",onSubmitCapture,{capture:!0}),startFrustration(),window.addEventListener("message",onPickerWindowMessage);let pickerHash=parsePickerHash(window.location.hash);if(pickerHash){let{origin,mode}=pickerHash;setPickerDashboardOrigin(origin);let clickMap=mode==="click-map";try{sessionStorage.setItem("st-picker",JSON.stringify({active:!0,origin,...clickMap&&{mode}}))}catch{}history.replaceState(null,"",window.location.pathname+window.location.search),window.opener&&requestPicker(clickMap?{mode}:void 0)}else try{let stored=sessionStorage.getItem("st-picker");if(stored&&window.opener){let parsed=JSON.parse(stored);if(typeof parsed=="object"&&parsed!==null&&"active"in parsed&&"origin"in parsed){let obj=parsed;if(obj.active&&typeof obj.origin=="string"){setPickerDashboardOrigin(obj.origin);let storedScan="scanEnabled"in obj&&obj.scanEnabled===!0,storedNav="navigateMode"in obj&&obj.navigateMode===!0,rawMode="selectorMode"in obj?obj.selectorMode:null;requestPicker({scanEnabled:storedScan,navigateMode:storedNav,selectorMode:rawMode==="generic"||rawMode==="exact"?rawMode:null,..."mode"in obj&&obj.mode==="click-map"&&{mode:"click-map"}})}}}}catch{}document.addEventListener("visibilitychange",()=>{document.visibilityState==="hidden"&&(onFrustrationHide(),flushBeacon())}),fetchConfig().then(result=>{if(!result.loaded){failClosed(result);return}applyInitConfig(storedInitConfig),!trackingDisabled&&(setConfigLoaded(!0),setInterval(()=>{flush()},config.flush_interval_ms),flush())})}function failClosed(result){console.warn(`[tracker] Could not load this project's settings from ${apiBase}/api/config \u2014 ${describeConfigFailure(result)}. No events were sent from this page load: without those settings the tracker cannot apply the project's URL redaction rules, and sending unredacted URLs would be worse than sending nothing.`),disableTracking(queue)}function track(name,attrs){typeof window>"u"||trackingDisabled||name&&enqueue({event_type:"custom",page_url:window.location.href,data_track:name,data_track_attrs:attrs,timestamp:new Date().toISOString()})}function setTraits2(newTraits){typeof window>"u"||setTraits(newTraits)}export{init,setTraits2 as setTraits,track,version};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@privatrak/tracker",
3
- "version": "1.1.0",
3
+ "version": "1.2.0",
4
4
  "description": "Cookieless, privacy-first analytics tracker: auto-captures pageviews, clicks and form submissions with no cookies, no localStorage, no PII and no consent banner.",
5
5
  "keywords": [
6
6
  "analytics",