@tracelog/lib 0.11.1 → 0.11.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +7 -0
- package/dist/browser/tracelog.esm.js +92 -86
- package/dist/browser/tracelog.esm.js.map +1 -1
- package/dist/browser/tracelog.js +2 -2
- package/dist/browser/tracelog.js.map +1 -1
- package/dist/cjs/api.d.ts.map +1 -1
- package/dist/cjs/api.js +17 -2
- package/dist/cjs/api.js.map +1 -1
- package/dist/esm/api.d.ts.map +1 -1
- package/dist/esm/api.js +17 -2
- package/dist/esm/api.js.map +1 -1
- package/package.json +1 -1
package/dist/browser/tracelog.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
(function(h){"use strict";const A="data-tlog",Ue=["button","a",'input[type="button"]','input[type="submit"]','input[type="reset"]','input[type="checkbox"]','input[type="radio"]',"select","textarea",'[role="button"]','[role="link"]','[role="tab"]','[role="menuitem"]','[role="option"]','[role="checkbox"]','[role="radio"]','[role="switch"]',"[routerLink]","[ng-click]","[data-action]","[data-click]","[data-navigate]","[data-toggle]","[onclick]",".btn",".button",".clickable",".nav-link",".menu-item","[data-testid]",'[tabindex="0"]'],He=["utm_source","utm_medium","utm_campaign","utm_term","utm_content"],Fe=["token","auth","key","session","reset","password","api_key","apikey","secret","access_token","refresh_token","verification","code","otp"],E={INVALID_SESSION_TIMEOUT:"Session timeout must be between 30000ms (30 seconds) and 86400000ms (24 hours)",INVALID_SAMPLING_RATE:"Sampling rate must be between 0 and 1",INVALID_ERROR_SAMPLING_RATE:"Error sampling must be between 0 and 1",INVALID_TRACELOG_PROJECT_ID:"TraceLog project ID is required when integration is enabled",INVALID_CUSTOM_API_URL:"Custom API URL is required when integration is enabled",INVALID_GOOGLE_ANALYTICS_ID:"Google Analytics measurement ID is required when integration is enabled",INVALID_GLOBAL_METADATA:"Global metadata must be an object",INVALID_SENSITIVE_QUERY_PARAMS:"Sensitive query params must be an array of strings",INVALID_PRIMARY_SCROLL_SELECTOR:"Primary scroll selector must be a non-empty string",INVALID_PRIMARY_SCROLL_SELECTOR_SYNTAX:"Invalid CSS selector syntax for primaryScrollSelector",INVALID_PAGE_VIEW_THROTTLE:"Page view throttle must be a non-negative number",INVALID_CLICK_THROTTLE:"Click throttle must be a non-negative number",INVALID_MAX_SAME_EVENT_PER_MINUTE:"Max same event per minute must be a positive number",INVALID_VIEWPORT_CONFIG:"Viewport config must be an object",INVALID_VIEWPORT_ELEMENTS:"Viewport elements must be a non-empty array",INVALID_VIEWPORT_ELEMENT:"Each viewport element must have a valid selector string",INVALID_VIEWPORT_ELEMENT_ID:"Viewport element id must be a non-empty string",INVALID_VIEWPORT_ELEMENT_NAME:"Viewport element name must be a non-empty string",INVALID_VIEWPORT_THRESHOLD:"Viewport threshold must be a number between 0 and 1",INVALID_VIEWPORT_MIN_DWELL_TIME:"Viewport minDwellTime must be a non-negative number",INVALID_VIEWPORT_COOLDOWN_PERIOD:"Viewport cooldownPeriod must be a non-negative number",INVALID_VIEWPORT_MAX_TRACKED_ELEMENTS:"Viewport maxTrackedElements must be a positive number"},Ge=[/<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi,/javascript:/gi,/on\w+\s*=/gi,/<iframe\b[^<]*(?:(?!<\/iframe>)<[^<]*)*<\/iframe>/gi,/<embed\b[^>]*>/gi,/<object\b[^<]*(?:(?!<\/object>)<[^<]*)*<\/object>/gi];var F=(n=>(n.Localhost="localhost:8080",n.Fail="localhost:9999",n))(F||{}),w=(n=>(n.Mobile="mobile",n.Tablet="tablet",n.Desktop="desktop",n.Unknown="unknown",n))(w||{}),G=(n=>(n.EVENT="event",n.QUEUE="queue",n))(G||{});class L extends Error{constructor(e,t){super(e),this.statusCode=t,this.name="PermanentError",Error.captureStackTrace&&Error.captureStackTrace(this,L)}}var u=(n=>(n.PAGE_VIEW="page_view",n.CLICK="click",n.SCROLL="scroll",n.SESSION_START="session_start",n.SESSION_END="session_end",n.CUSTOM="custom",n.WEB_VITALS="web_vitals",n.ERROR="error",n.VIEWPORT_VISIBLE="viewport_visible",n))(u||{}),U=(n=>(n.UP="up",n.DOWN="down",n))(U||{}),C=(n=>(n.JS_ERROR="js_error",n.PROMISE_REJECTION="promise_rejection",n))(C||{}),b=(n=>(n.QA="qa",n))(b||{});function xe(n){return n.type===u.SCROLL&&"scroll_data"in n&&n.scroll_data.is_primary===!0}function We(n){return n.type===u.SCROLL&&"scroll_data"in n&&n.scroll_data.is_primary===!1}class P extends Error{constructor(e,t,r){super(e),this.errorCode=t,this.layer=r,this.name=this.constructor.name,Error.captureStackTrace&&Error.captureStackTrace(this,this.constructor)}}class f extends P{constructor(e,t="config"){super(e,"APP_CONFIG_INVALID",t)}}class fe extends P{constructor(e,t="config"){super(e,"SESSION_TIMEOUT_INVALID",t)}}class j extends P{constructor(e,t="config"){super(e,"SAMPLING_RATE_INVALID",t)}}class M extends P{constructor(e,t="config"){super(e,"INTEGRATION_INVALID",t)}}class Xe extends P{constructor(e,t,r="runtime"){super(e,"INITIALIZATION_TIMEOUT",r),this.timeoutMs=t}}const Be=(n,e)=>{if(e){if(e instanceof Error){const t=e.message.replace(/\s+at\s+.*$/gm,"").replace(/\(.*?:\d+:\d+\)/g,"");return`[TraceLog] ${n}: ${t}`}return`[TraceLog] ${n}: ${e instanceof Error?e.message:"Unknown error"}`}return`[TraceLog] ${n}`},a=(n,e,t)=>{const{error:r,data:s,showToClient:i=!1}=t??{},o=r?Be(e,r):`[TraceLog] ${e}`,l=n==="error"?"error":n==="warn"?"warn":"log";if(!(n==="debug"||n==="info"&&!i))if(s!==void 0){const c=$e(s);console[l](o,c)}else s!==void 0?console[l](o,s):console[l](o)},$e=n=>{const e={},t=["token","password","secret","key","apikey","api_key","sessionid","session_id"];for(const[r,s]of Object.entries(n)){const i=r.toLowerCase();t.some(o=>i.includes(o))?e[r]="[REDACTED]":e[r]=s}return e};let K,ge;const ze=()=>{typeof window<"u"&&!K&&(K=window.matchMedia("(pointer: coarse)"),ge=window.matchMedia("(hover: none)"))},Ye=()=>{try{const n=navigator;if(n.userAgentData&&typeof n.userAgentData.mobile=="boolean")return n.userAgentData.platform&&/ipad|tablet/i.test(n.userAgentData.platform)?w.Tablet:n.userAgentData.mobile?w.Mobile:w.Desktop;ze();const e=window.innerWidth,t=K?.matches??!1,r=ge?.matches??!1,s="ontouchstart"in window||navigator.maxTouchPoints>0,i=navigator.userAgent.toLowerCase(),o=/mobile|android|iphone|ipod|blackberry|iemobile|opera mini/.test(i),l=/tablet|ipad|android(?!.*mobile)/.test(i);return e<=767||o&&s?w.Mobile:e>=768&&e<=1024||l||t&&r&&s?w.Tablet:w.Desktop}catch(n){return a("warn","Device detection failed, defaulting to desktop",{error:n}),w.Desktop}},N="tlog",me=`${N}:qa_mode`,Qe=`${N}:uid`,je=n=>n?`${N}:${n}:queue`:`${N}:queue`,Ke=n=>n?`${N}:${n}:session`:`${N}:session`,qe=n=>n?`${N}:${n}:broadcast`:`${N}:broadcast`,Se={LCP:4e3,FCP:1800,CLS:.25,INP:200,TTFB:800,LONG_TASK:50},Ze=1e3,q=[/\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Z|a-z]{2,}\b/gi,/\b\d{3}[-.]?\d{3}[-.]?\d{4}\b/g,/\b\d{4}[-\s]?\d{4}[-\s]?\d{4}[-\s]?\d{4}\b/g,/\b[A-Z]{2}\d{2}[-\s]?\d{4}[-\s]?\d{4}[-\s]?\d{4}[-\s]?\d{4}[-\s]?\d{4}\b/gi,/\b[sp]k_(test|live)_[a-zA-Z0-9]{10,}\b/gi,/Bearer\s+[A-Za-z0-9_-]+(?:\.[A-Za-z0-9_-]+)?(?:\.[A-Za-z0-9_-]+)?/gi,/:\/\/[^:/]+:([^@]+)@/gi],_e=500,Te=5e3,x=50,Je=x*2,Ie=1,et=1e3,tt=10,pe=5e3,rt=6e4,ve="tlog_mode",nt="qa",st=()=>{if(sessionStorage.getItem(me)==="true")return!0;const e=new URLSearchParams(window.location.search),r=e.get(ve)===nt;if(r){sessionStorage.setItem(me,"true"),e.delete(ve);const s=e.toString(),i=`${window.location.pathname}${s?"?"+s:""}${window.location.hash}`;try{window.history.replaceState({},"",i)}catch(o){a("warn","History API not available, cannot replace URL",{error:o})}console.log("%c[TraceLog] QA Mode ACTIVE","background: #ff9800; color: white; font-weight: bold; padding: 2px 8px; border-radius: 3px;")}return r},Ae=()=>{const n=new URLSearchParams(window.location.search),e={};return He.forEach(r=>{const s=n.get(r);if(s){const i=r.split("utm_")[1];e[i]=s}}),Object.keys(e).length?e:void 0},it=()=>typeof crypto<"u"&&crypto.randomUUID?crypto.randomUUID():"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g,n=>{const e=Math.random()*16|0;return(n==="x"?e:e&3|8).toString(16)}),ot=()=>{const n=Date.now();let e="";try{if(typeof crypto<"u"&&crypto.getRandomValues){const t=crypto.getRandomValues(new Uint8Array(4));t&&(e=Array.from(t,r=>r.toString(16).padStart(2,"0")).join(""))}}catch{}return e||(e=Math.floor(Math.random()*4294967295).toString(16).padStart(8,"0")),`${n}-${e}`},we=(n,e=!1)=>{try{const t=new URL(n),r=t.protocol==="https:",s=t.protocol==="http:";return r||e&&s}catch{return!1}},at=n=>{if(n.integrations?.tracelog?.projectId){const s=new URL(window.location.href).hostname.split(".");if(s.length===0)throw new Error("Invalid URL");const i=n.integrations.tracelog.projectId,o=s.slice(-2).join("."),l=`https://${i}.${o}/collect`;if(!we(l))throw new Error("Invalid URL");return l}const e=n.integrations?.custom?.collectApiUrl;if(e){const t=n.integrations?.custom?.allowHttp??!1;if(!we(e,t))throw new Error("Invalid URL");return e}return""},Z=(n,e=[])=>{try{const t=new URL(n),r=t.searchParams,s=[...new Set([...Fe,...e])];let i=!1;const o=[];return s.forEach(c=>{r.has(c)&&(r.delete(c),i=!0,o.push(c))}),!i&&n.includes("?")?n:(t.search=r.toString(),t.toString())}catch(t){return a("warn","URL normalization failed, returning original",{error:t,data:{url:n.slice(0,100)}}),n}},Me=n=>{if(!n||typeof n!="string"||n.trim().length===0)return"";let e=n;n.length>1e3&&(e=n.slice(0,Math.max(0,1e3)));let t=0;for(const s of Ge){const i=e;e=e.replace(s,""),i!==e&&t++}return t>0&&a("warn","XSS patterns detected and removed",{data:{patternMatches:t,originalValue:n.slice(0,100)}}),e=e.replaceAll("&","&").replaceAll("<","<").replaceAll(">",">").replaceAll('"',""").replaceAll("'","'").replaceAll("/","/"),e.trim()},J=(n,e=0)=>{if(e>3||n==null)return null;if(typeof n=="string")return Me(n);if(typeof n=="number")return!Number.isFinite(n)||n<-Number.MAX_SAFE_INTEGER||n>Number.MAX_SAFE_INTEGER?0:n;if(typeof n=="boolean")return n;if(Array.isArray(n))return n.slice(0,100).map(s=>J(s,e+1)).filter(s=>s!==null);if(typeof n=="object"){const t={},s=Object.entries(n).slice(0,20);for(const[i,o]of s){const l=Me(i);if(l){const c=J(o,e+1);c!==null&&(t[l]=c)}}return t}return null},lt=n=>{if(typeof n!="object"||n===null)return{};try{const e=J(n);return typeof e=="object"&&e!==null?e:{}}catch(e){const t=e instanceof Error?e.message:String(e);throw new Error(`[TraceLog] Metadata sanitization failed: ${t}`)}},ct=n=>{if(n!==void 0&&(n===null||typeof n!="object"))throw new f("Configuration must be an object","config");if(n){if(n.sessionTimeout!==void 0&&(typeof n.sessionTimeout!="number"||n.sessionTimeout<3e4||n.sessionTimeout>864e5))throw new fe(E.INVALID_SESSION_TIMEOUT,"config");if(n.globalMetadata!==void 0&&(typeof n.globalMetadata!="object"||n.globalMetadata===null))throw new f(E.INVALID_GLOBAL_METADATA,"config");if(n.integrations&&dt(n.integrations),n.sensitiveQueryParams!==void 0){if(!Array.isArray(n.sensitiveQueryParams))throw new f(E.INVALID_SENSITIVE_QUERY_PARAMS,"config");for(const e of n.sensitiveQueryParams)if(typeof e!="string")throw new f("All sensitive query params must be strings","config")}if(n.errorSampling!==void 0&&(typeof n.errorSampling!="number"||n.errorSampling<0||n.errorSampling>1))throw new j(E.INVALID_ERROR_SAMPLING_RATE,"config");if(n.samplingRate!==void 0&&(typeof n.samplingRate!="number"||n.samplingRate<0||n.samplingRate>1))throw new j(E.INVALID_SAMPLING_RATE,"config");if(n.primaryScrollSelector!==void 0){if(typeof n.primaryScrollSelector!="string"||!n.primaryScrollSelector.trim())throw new f(E.INVALID_PRIMARY_SCROLL_SELECTOR,"config");if(n.primaryScrollSelector!=="window")try{document.querySelector(n.primaryScrollSelector)}catch{throw new f(`${E.INVALID_PRIMARY_SCROLL_SELECTOR_SYNTAX}: "${n.primaryScrollSelector}"`,"config")}}if(n.pageViewThrottleMs!==void 0&&(typeof n.pageViewThrottleMs!="number"||n.pageViewThrottleMs<0))throw new f(E.INVALID_PAGE_VIEW_THROTTLE,"config");if(n.clickThrottleMs!==void 0&&(typeof n.clickThrottleMs!="number"||n.clickThrottleMs<0))throw new f(E.INVALID_CLICK_THROTTLE,"config");if(n.maxSameEventPerMinute!==void 0&&(typeof n.maxSameEventPerMinute!="number"||n.maxSameEventPerMinute<=0))throw new f(E.INVALID_MAX_SAME_EVENT_PER_MINUTE,"config");n.viewport!==void 0&&ut(n.viewport)}},ut=n=>{if(typeof n!="object"||n===null)throw new f(E.INVALID_VIEWPORT_CONFIG,"config");if(!n.elements||!Array.isArray(n.elements))throw new f(E.INVALID_VIEWPORT_ELEMENTS,"config");if(n.elements.length===0)throw new f(E.INVALID_VIEWPORT_ELEMENTS,"config");const e=new Set;for(const t of n.elements){if(!t.selector||typeof t.selector!="string"||!t.selector.trim())throw new f(E.INVALID_VIEWPORT_ELEMENT,"config");const r=t.selector.trim();if(e.has(r))throw new f(`Duplicate viewport selector found: "${r}". Each selector should appear only once.`,"config");if(e.add(r),t.id!==void 0&&(typeof t.id!="string"||!t.id.trim()))throw new f(E.INVALID_VIEWPORT_ELEMENT_ID,"config");if(t.name!==void 0&&(typeof t.name!="string"||!t.name.trim()))throw new f(E.INVALID_VIEWPORT_ELEMENT_NAME,"config")}if(n.threshold!==void 0&&(typeof n.threshold!="number"||n.threshold<0||n.threshold>1))throw new f(E.INVALID_VIEWPORT_THRESHOLD,"config");if(n.minDwellTime!==void 0&&(typeof n.minDwellTime!="number"||n.minDwellTime<0))throw new f(E.INVALID_VIEWPORT_MIN_DWELL_TIME,"config");if(n.cooldownPeriod!==void 0&&(typeof n.cooldownPeriod!="number"||n.cooldownPeriod<0))throw new f(E.INVALID_VIEWPORT_COOLDOWN_PERIOD,"config");if(n.maxTrackedElements!==void 0&&(typeof n.maxTrackedElements!="number"||n.maxTrackedElements<=0))throw new f(E.INVALID_VIEWPORT_MAX_TRACKED_ELEMENTS,"config")},dt=n=>{if(n){if(n.tracelog&&(!n.tracelog.projectId||typeof n.tracelog.projectId!="string"||n.tracelog.projectId.trim()===""))throw new M(E.INVALID_TRACELOG_PROJECT_ID,"config");if(n.custom){if(!n.custom.collectApiUrl||typeof n.custom.collectApiUrl!="string"||n.custom.collectApiUrl.trim()==="")throw new M(E.INVALID_CUSTOM_API_URL,"config");if(n.custom.allowHttp!==void 0&&typeof n.custom.allowHttp!="boolean")throw new M("allowHttp must be a boolean","config");const e=n.custom.collectApiUrl.trim();if(!e.startsWith("http://")&&!e.startsWith("https://"))throw new M('Custom API URL must start with "http://" or "https://"',"config");if(!(n.custom.allowHttp??!1)&&e.startsWith("http://"))throw new M("Custom API URL must use HTTPS in production. Set allowHttp: true in integration config to allow HTTP (not recommended)","config")}if(n.googleAnalytics){if(!n.googleAnalytics.measurementId||typeof n.googleAnalytics.measurementId!="string"||n.googleAnalytics.measurementId.trim()==="")throw new M(E.INVALID_GOOGLE_ANALYTICS_ID,"config");if(!n.googleAnalytics.measurementId.trim().match(/^(G-|UA-)/))throw new M('Google Analytics measurement ID must start with "G-" or "UA-"',"config")}}},ht=n=>{ct(n);const e={...n??{},sessionTimeout:n?.sessionTimeout??9e5,globalMetadata:n?.globalMetadata??{},sensitiveQueryParams:n?.sensitiveQueryParams??[],errorSampling:n?.errorSampling??Ie,samplingRate:n?.samplingRate??1,pageViewThrottleMs:n?.pageViewThrottleMs??1e3,clickThrottleMs:n?.clickThrottleMs??300,maxSameEventPerMinute:n?.maxSameEventPerMinute??60};return e.integrations?.custom&&(e.integrations.custom={...e.integrations.custom,allowHttp:e.integrations.custom.allowHttp??!1}),e.viewport&&(e.viewport={...e.viewport,threshold:e.viewport.threshold??.5,minDwellTime:e.viewport.minDwellTime??2e3,cooldownPeriod:e.viewport.cooldownPeriod??6e4,maxTrackedElements:e.viewport.maxTrackedElements??100}),e},Et=n=>{if(typeof n=="string")return!0;if(typeof n=="object"&&n!==null&&!Array.isArray(n)){const e=Object.entries(n);if(e.length>20)return!1;for(const[,t]of e){if(t==null)continue;const r=typeof t;if(r!=="string"&&r!=="number"&&r!=="boolean")return!1}return!0}return!1},Ne=(n,e=0)=>{if(typeof n!="object"||n===null||e>1)return!1;for(const t of Object.values(n)){if(t==null)continue;const r=typeof t;if(!(r==="string"||r==="number"||r==="boolean")){if(Array.isArray(t)){if(t.length===0)continue;if(typeof t[0]=="string"){if(!t.every(o=>typeof o=="string"))return!1}else if(!t.every(o=>Et(o)))return!1;continue}if(r==="object"&&e===0){if(!Ne(t,e+1))return!1;continue}return!1}}return!0},ft=n=>typeof n!="string"?{valid:!1,error:"Event name must be a string"}:n.length===0?{valid:!1,error:"Event name cannot be empty"}:n.length>120?{valid:!1,error:"Event name is too long (max 120 characters)"}:n.includes("<")||n.includes(">")||n.includes("&")?{valid:!1,error:"Event name contains invalid characters"}:["constructor","prototype","__proto__","eval","function","var","let","const"].includes(n.toLowerCase())?{valid:!1,error:"Event name cannot be a reserved word"}:{valid:!0},ye=(n,e,t)=>{const r=lt(e),s=`${t} "${n}" metadata error`;if(!Ne(r))return{valid:!1,error:`${s}: object has invalid types. Valid types are string, number, boolean or string arrays.`};let i;try{i=JSON.stringify(r)}catch{return{valid:!1,error:`${s}: object contains circular references or cannot be serialized.`}}if(i.length>8192)return{valid:!1,error:`${s}: object is too large (max ${8192/1024} KB).`};if(Object.keys(r).length>10)return{valid:!1,error:`${s}: object has too many keys (max 10 keys).`};for(const[l,c]of Object.entries(r)){if(Array.isArray(c)){if(c.length>10)return{valid:!1,error:`${s}: array property "${l}" is too large (max 10 items).`};for(const d of c)if(typeof d=="string"&&d.length>500)return{valid:!1,error:`${s}: array property "${l}" contains strings that are too long (max 500 characters).`}}if(typeof c=="string"&&c.length>1e3)return{valid:!1,error:`${s}: property "${l}" is too long (max 1000 characters).`}}return{valid:!0,sanitizedMetadata:r}},gt=(n,e,t)=>{if(Array.isArray(e)){const r=[],s=`${t} "${n}" metadata error`;for(let i=0;i<e.length;i++){const o=e[i];if(typeof o!="object"||o===null||Array.isArray(o))return{valid:!1,error:`${s}: array item at index ${i} must be an object.`};const l=ye(n,o,t);if(!l.valid)return{valid:!1,error:`${s}: array item at index ${i} is invalid: ${l.error}`};l.sanitizedMetadata&&r.push(l.sanitizedMetadata)}return{valid:!0,sanitizedMetadata:r}}return ye(n,e,t)},mt=(n,e)=>{const t=ft(n);if(!t.valid)return a("error","Event name validation failed",{showToClient:!0,data:{eventName:n,error:t.error}}),t;if(!e)return{valid:!0};const r=gt(n,e,"customEvent");return r.valid||a("error","Event metadata validation failed",{showToClient:!0,data:{eventName:n,error:r.error}}),r};class St{listeners=new Map;on(e,t){this.listeners.has(e)||this.listeners.set(e,[]),this.listeners.get(e).push(t)}off(e,t){const r=this.listeners.get(e);if(r){const s=r.indexOf(t);s>-1&&r.splice(s,1)}}emit(e,t){const r=this.listeners.get(e);r&&r.forEach(s=>{s(t)})}removeAllListeners(){this.listeners.clear()}}const ee={};class S{get(e){return ee[e]}set(e,t){ee[e]=t}getState(){return{...ee}}}class _t extends S{storeManager;lastPermanentErrorLog=null;constructor(e){super(),this.storeManager=e}getQueueStorageKey(){const e=this.get("userId")||"anonymous";return je(e)}sendEventsQueueSync(e){return this.shouldSkipSend()?!0:this.get("config")?.integrations?.custom?.collectApiUrl===F.Fail?(a("warn","Fail mode: simulating network failure (sync)",{data:{events:e.events.length}}),!1):this.sendQueueSyncInternal(e)}async sendEventsQueue(e,t){try{const r=await this.send(e);return r?(this.clearPersistedEvents(),t?.onSuccess?.(e.events.length,e.events,e)):(this.persistEvents(e),t?.onFailure?.()),r}catch(r){return r instanceof L?(this.logPermanentError("Permanent error, not retrying",r),this.clearPersistedEvents(),t?.onFailure?.(),!1):(this.persistEvents(e),t?.onFailure?.(),!1)}}async recoverPersistedEvents(e){try{const t=this.getPersistedData();if(!t||!this.isDataRecent(t)||t.events.length===0){this.clearPersistedEvents();return}const r=this.createRecoveryBody(t);await this.send(r)?(this.clearPersistedEvents(),e?.onSuccess?.(t.events.length,t.events,r)):e?.onFailure?.()}catch(t){if(t instanceof L){this.logPermanentError("Permanent error during recovery, clearing persisted events",t),this.clearPersistedEvents(),e?.onFailure?.();return}a("error","Failed to recover persisted events",{error:t})}}stop(){}async send(e){if(this.shouldSkipSend())return this.simulateSuccessfulSend();if(this.get("config")?.integrations?.custom?.collectApiUrl===F.Fail)return a("warn","Fail mode: simulating network failure",{data:{events:e.events.length}}),!1;const{url:r,payload:s}=this.prepareRequest(e);try{return(await this.sendWithTimeout(r,s)).ok}catch(i){if(i instanceof L)throw i;return a("error","Send request failed",{error:i,data:{events:e.events.length,url:r.replace(/\/\/[^/]+/,"//[DOMAIN]")}}),!1}}async sendWithTimeout(e,t){const r=new AbortController,s=setTimeout(()=>{r.abort()},1e4);try{const i=await fetch(e,{method:"POST",body:t,keepalive:!0,credentials:"include",signal:r.signal,headers:{"Content-Type":"application/json"}});if(!i.ok)throw i.status>=400&&i.status<500?new L(`HTTP ${i.status}: ${i.statusText}`,i.status):new Error(`HTTP ${i.status}: ${i.statusText}`);return i}finally{clearTimeout(s)}}sendQueueSyncInternal(e){const{url:t,payload:r}=this.prepareRequest(e);if(r.length>65536)return a("warn","Payload exceeds sendBeacon limit, persisting for recovery",{data:{size:r.length,limit:65536,events:e.events.length}}),this.persistEvents(e),!1;const s=new Blob([r],{type:"application/json"});if(!this.isSendBeaconAvailable())return a("warn","sendBeacon not available, persisting events for recovery"),this.persistEvents(e),!1;const i=navigator.sendBeacon(t,s);return i||(a("warn","sendBeacon rejected request, persisting events for recovery"),this.persistEvents(e)),i}prepareRequest(e){const t={...e,_metadata:{referer:typeof window<"u"?window.location.href:void 0,timestamp:Date.now()}};return{url:this.get("collectApiUrl"),payload:JSON.stringify(t)}}getPersistedData(){try{const e=this.getQueueStorageKey(),t=this.storeManager.getItem(e);if(t)return JSON.parse(t)}catch(e){a("warn","Failed to parse persisted data",{error:e}),this.clearPersistedEvents()}return null}isDataRecent(e){return!e.timestamp||typeof e.timestamp!="number"?!1:(Date.now()-e.timestamp)/(1e3*60*60)<2}createRecoveryBody(e){return{user_id:e.userId,session_id:e.sessionId,device:e.device,events:e.events,...e.global_metadata&&{global_metadata:e.global_metadata}}}persistEvents(e){try{const t={userId:e.user_id,sessionId:e.session_id,device:e.device,events:e.events,timestamp:Date.now(),...e.global_metadata&&{global_metadata:e.global_metadata}},r=this.getQueueStorageKey();return this.storeManager.setItem(r,JSON.stringify(t)),!!this.storeManager.getItem(r)}catch(t){return a("warn","Failed to persist events",{error:t}),!1}}clearPersistedEvents(){try{const e=this.getQueueStorageKey();this.storeManager.removeItem(e)}catch(e){a("warn","Failed to clear persisted events",{error:e})}}shouldSkipSend(){return!this.get("collectApiUrl")}async simulateSuccessfulSend(){const e=Math.random()*400+100;return await new Promise(t=>setTimeout(t,e)),!0}isSendBeaconAvailable(){return typeof navigator<"u"&&typeof navigator.sendBeacon=="function"}logPermanentError(e,t){const r=Date.now();(!this.lastPermanentErrorLog||this.lastPermanentErrorLog.statusCode!==t.statusCode||r-this.lastPermanentErrorLog.timestamp>=rt)&&(a("error",e,{data:{status:t.statusCode,message:t.message}}),this.lastPermanentErrorLog={statusCode:t.statusCode,timestamp:r})}}class Tt extends S{googleAnalytics;dataSender;emitter;eventsQueue=[];pendingEventsBuffer=[];recentEventFingerprints=new Map;sendIntervalId=null;rateLimitCounter=0;rateLimitWindowStart=0;perEventRateLimits=new Map;sessionEventCounts={total:0,[u.CLICK]:0,[u.PAGE_VIEW]:0,[u.CUSTOM]:0,[u.VIEWPORT_VISIBLE]:0,[u.SCROLL]:0};lastSessionId=null;constructor(e,t=null,r=null){super(),this.googleAnalytics=t,this.dataSender=new _t(e),this.emitter=r}async recoverPersistedEvents(){await this.dataSender.recoverPersistedEvents({onSuccess:(e,t,r)=>{if(t&&t.length>0){const s=t.map(i=>i.id);this.removeProcessedEvents(s),r&&this.emitEventsQueue(r)}},onFailure:()=>{a("warn","Failed to recover persisted events")}})}track({type:e,page_url:t,from_page_url:r,scroll_data:s,click_data:i,custom_event:o,web_vitals:l,error_data:c,session_end_reason:d,viewport_data:T}){if(!e){a("error","Event type is required - event will be ignored");return}const m=this.get("sessionId");if(!m){this.pendingEventsBuffer.length>=100&&(this.pendingEventsBuffer.shift(),a("warn","Pending events buffer full - dropping oldest event",{data:{maxBufferSize:100}})),this.pendingEventsBuffer.push({type:e,page_url:t,from_page_url:r,scroll_data:s,click_data:i,custom_event:o,web_vitals:l,error_data:c,session_end_reason:d,viewport_data:T});return}this.lastSessionId!==m&&(this.lastSessionId=m,this.sessionEventCounts={total:0,[u.CLICK]:0,[u.PAGE_VIEW]:0,[u.CUSTOM]:0,[u.VIEWPORT_VISIBLE]:0,[u.SCROLL]:0});const O=e===u.SESSION_START||e===u.SESSION_END;if(!O&&!this.checkRateLimit())return;const _=e;if(!O){if(this.sessionEventCounts.total>=1e3){a("warn","Session event limit reached",{data:{type:_,total:this.sessionEventCounts.total,limit:1e3}});return}const y=this.getTypeLimitForEvent(_);if(y){const Ee=this.sessionEventCounts[_];if(Ee!==void 0&&Ee>=y){a("warn","Session event type limit reached",{data:{type:_,count:Ee,limit:y}});return}}}if(_===u.CUSTOM&&o?.name){const y=this.get("config")?.maxSameEventPerMinute??60;if(!this.checkPerEventRateLimit(o.name,y))return}const cr=_===u.SESSION_START,ur=t||this.get("pageUrl"),he=this.buildEventPayload({type:_,page_url:ur,from_page_url:r,scroll_data:s,click_data:i,custom_event:o,web_vitals:l,error_data:c,session_end_reason:d,viewport_data:T});if(!(!O&&!this.shouldSample())){if(cr){const y=this.get("sessionId");if(!y){a("error","Session start event requires sessionId - event will be ignored");return}if(this.get("hasStartSession")){a("warn","Duplicate session_start detected",{data:{sessionId:y}});return}this.set("hasStartSession",!0)}if(!this.isDuplicateEvent(he)){if(this.get("mode")===b.QA&&_===u.CUSTOM&&o){console.log("[TraceLog] Event",{name:o.name,...o.metadata&&{metadata:o.metadata}}),this.emitEvent(he);return}this.addToQueue(he),O||(this.sessionEventCounts.total++,this.sessionEventCounts[_]!==void 0&&this.sessionEventCounts[_]++)}}}stop(){this.sendIntervalId&&(clearInterval(this.sendIntervalId),this.sendIntervalId=null),this.eventsQueue=[],this.pendingEventsBuffer=[],this.recentEventFingerprints.clear(),this.rateLimitCounter=0,this.rateLimitWindowStart=0,this.perEventRateLimits.clear(),this.sessionEventCounts={total:0,[u.CLICK]:0,[u.PAGE_VIEW]:0,[u.CUSTOM]:0,[u.VIEWPORT_VISIBLE]:0,[u.SCROLL]:0},this.lastSessionId=null,this.dataSender.stop()}async flushImmediately(){return this.flushEvents(!1)}flushImmediatelySync(){return this.flushEvents(!0)}getQueueLength(){return this.eventsQueue.length}flushPendingEvents(){if(this.pendingEventsBuffer.length===0)return;if(!this.get("sessionId")){a("warn","Cannot flush pending events: session not initialized - keeping in buffer",{data:{bufferedEventCount:this.pendingEventsBuffer.length}});return}const t=[...this.pendingEventsBuffer];this.pendingEventsBuffer=[],t.forEach(r=>{this.track(r)})}clearSendInterval(){this.sendIntervalId&&(clearInterval(this.sendIntervalId),this.sendIntervalId=null)}flushEvents(e){if(this.eventsQueue.length===0)return e?!0:Promise.resolve(!0);const t=this.buildEventsPayload(),r=[...this.eventsQueue],s=r.map(i=>i.id);if(e){const i=this.dataSender.sendEventsQueueSync(t);return i&&(this.removeProcessedEvents(s),this.clearSendInterval(),this.emitEventsQueue(t)),i}else return this.dataSender.sendEventsQueue(t,{onSuccess:()=>{this.removeProcessedEvents(s),this.clearSendInterval(),this.emitEventsQueue(t)},onFailure:()=>{a("warn","Async flush failed",{data:{eventCount:r.length}})}})}async sendEventsQueue(){if(!this.get("sessionId")||this.eventsQueue.length===0)return;const e=this.buildEventsPayload(),t=[...this.eventsQueue],r=t.map(s=>s.id);await this.dataSender.sendEventsQueue(e,{onSuccess:()=>{this.removeProcessedEvents(r),this.emitEventsQueue(e)},onFailure:()=>{a("warn","Events send failed, keeping in queue",{data:{eventCount:t.length}})}})}buildEventsPayload(){const e=new Map,t=[];for(const s of this.eventsQueue){const i=this.createEventSignature(s);e.has(i)||t.push(i),e.set(i,s)}const r=t.map(s=>e.get(s)).filter(s=>!!s).sort((s,i)=>s.timestamp-i.timestamp);return{user_id:this.get("userId"),session_id:this.get("sessionId"),device:this.get("device"),events:r,...this.get("config")?.globalMetadata&&{global_metadata:this.get("config")?.globalMetadata}}}buildEventPayload(e){const t=e.type===u.SESSION_START,r=e.page_url??this.get("pageUrl");return{id:ot(),type:e.type,page_url:r,timestamp:Date.now(),...t&&{referrer:document.referrer||"Direct"},...e.from_page_url&&{from_page_url:e.from_page_url},...e.scroll_data&&{scroll_data:e.scroll_data},...e.click_data&&{click_data:e.click_data},...e.custom_event&&{custom_event:e.custom_event},...e.web_vitals&&{web_vitals:e.web_vitals},...e.error_data&&{error_data:e.error_data},...e.session_end_reason&&{session_end_reason:e.session_end_reason},...e.viewport_data&&{viewport_data:e.viewport_data},...t&&Ae()&&{utm:Ae()}}}isDuplicateEvent(e){const t=Date.now(),r=this.createEventFingerprint(e),s=this.recentEventFingerprints.get(r);return s&&t-s<500?(this.recentEventFingerprints.set(r,t),!0):(this.recentEventFingerprints.set(r,t),this.recentEventFingerprints.size>1e3&&this.pruneOldFingerprints(),this.recentEventFingerprints.size>2e3&&(this.recentEventFingerprints.clear(),this.recentEventFingerprints.set(r,t),a("warn","Event fingerprint cache exceeded hard limit, cleared",{data:{hardLimit:2e3}})),!1)}pruneOldFingerprints(){const e=Date.now(),t=500*10;for(const[r,s]of this.recentEventFingerprints.entries())e-s>t&&this.recentEventFingerprints.delete(r);a("debug","Pruned old event fingerprints",{data:{remaining:this.recentEventFingerprints.size,cutoffMs:t}})}createEventFingerprint(e){let t=`${e.type}_${e.page_url}`;if(e.click_data){const r=Math.round((e.click_data.x||0)/10)*10,s=Math.round((e.click_data.y||0)/10)*10;t+=`_click_${r}_${s}`}return e.scroll_data&&(t+=`_scroll_${e.scroll_data.depth}_${e.scroll_data.direction}`),e.custom_event&&(t+=`_custom_${e.custom_event.name}`),e.web_vitals&&(t+=`_vitals_${e.web_vitals.type}`),e.error_data&&(t+=`_error_${e.error_data.type}_${e.error_data.message}`),t}createEventSignature(e){return this.createEventFingerprint(e)}addToQueue(e){if(this.eventsQueue.push(e),this.emitEvent(e),this.eventsQueue.length>100){const t=this.eventsQueue.findIndex(s=>s.type!==u.SESSION_START&&s.type!==u.SESSION_END),r=t>=0?this.eventsQueue.splice(t,1)[0]:this.eventsQueue.shift();a("warn","Event queue overflow, oldest non-critical event removed",{data:{maxLength:100,currentLength:this.eventsQueue.length,removedEventType:r?.type,wasCritical:r?.type===u.SESSION_START||r?.type===u.SESSION_END}})}this.sendIntervalId||this.startSendInterval(),this.eventsQueue.length>=50&&this.sendEventsQueue(),this.handleGoogleAnalyticsIntegration(e)}startSendInterval(){this.sendIntervalId=window.setInterval(()=>{this.eventsQueue.length>0&&this.sendEventsQueue()},1e4)}handleGoogleAnalyticsIntegration(e){if(this.googleAnalytics&&e.type===u.CUSTOM&&e.custom_event){if(this.get("mode")===b.QA)return;this.googleAnalytics.trackEvent(e.custom_event.name,e.custom_event.metadata??{})}}shouldSample(){const e=this.get("config")?.samplingRate??1;return Math.random()<e}checkRateLimit(){const e=Date.now();return e-this.rateLimitWindowStart>1e3&&(this.rateLimitCounter=0,this.rateLimitWindowStart=e),this.rateLimitCounter>=50?!1:(this.rateLimitCounter++,!0)}checkPerEventRateLimit(e,t){const r=Date.now(),i=(this.perEventRateLimits.get(e)??[]).filter(o=>r-o<6e4);return i.length>=t?(a("warn","Per-event rate limit exceeded for custom event",{data:{eventName:e,limit:t,window:`${6e4/1e3}s`}}),!1):(i.push(r),this.perEventRateLimits.set(e,i),!0)}getTypeLimitForEvent(e){return{[u.CLICK]:500,[u.PAGE_VIEW]:100,[u.CUSTOM]:500,[u.VIEWPORT_VISIBLE]:200,[u.SCROLL]:120}[e]??null}removeProcessedEvents(e){const t=new Set(e);this.eventsQueue=this.eventsQueue.filter(r=>!t.has(r.id))}emitEvent(e){this.emitter&&this.emitter.emit(G.EVENT,e)}emitEventsQueue(e){this.emitter&&this.emitter.emit(G.QUEUE,e)}}class It{static getId(e){const t=Qe,r=e.getItem(t);if(r)return r;const s=it();return e.setItem(t,s),s}}class pt extends S{storageManager;eventManager;projectId;sessionTimeoutId=null;broadcastChannel=null;activityHandler=null;visibilityChangeHandler=null;beforeUnloadHandler=null;isTracking=!1;constructor(e,t,r){super(),this.storageManager=e,this.eventManager=t,this.projectId=r}initCrossTabSync(){if(typeof BroadcastChannel>"u"){a("warn","BroadcastChannel not supported");return}const e=this.getProjectId();this.broadcastChannel=new BroadcastChannel(qe(e)),this.broadcastChannel.onmessage=t=>{const{action:r,sessionId:s,timestamp:i,projectId:o}=t.data??{};if(o===e){if(r==="session_end"){this.resetSessionState();return}s&&typeof i=="number"&&i>Date.now()-5e3&&(this.set("sessionId",s),this.set("hasStartSession",!0),this.persistSession(s,i),this.isTracking&&this.setupSessionTimeout())}}}shareSession(e){this.broadcastChannel&&typeof this.broadcastChannel.postMessage=="function"&&this.broadcastChannel.postMessage({action:"session_start",projectId:this.getProjectId(),sessionId:e,timestamp:Date.now()})}broadcastSessionEnd(e,t){if(e&&this.broadcastChannel&&typeof this.broadcastChannel.postMessage=="function")try{this.broadcastChannel.postMessage({action:"session_end",projectId:this.getProjectId(),sessionId:e,reason:t,timestamp:Date.now()})}catch(r){a("warn","Failed to broadcast session end",{error:r,data:{sessionId:e,reason:t}})}}cleanupCrossTabSync(){this.broadcastChannel&&(typeof this.broadcastChannel.close=="function"&&this.broadcastChannel.close(),this.broadcastChannel=null)}recoverSession(){const e=this.loadStoredSession();if(!e)return null;const t=this.get("config")?.sessionTimeout??9e5;return Date.now()-e.lastActivity>t?(this.clearStoredSession(),null):e.id}persistSession(e,t=Date.now()){this.saveStoredSession({id:e,lastActivity:t})}clearStoredSession(){const e=this.getSessionStorageKey();this.storageManager.removeItem(e)}loadStoredSession(){const e=this.getSessionStorageKey(),t=this.storageManager.getItem(e);if(!t)return null;try{const r=JSON.parse(t);return!r.id||typeof r.lastActivity!="number"?null:r}catch{return this.storageManager.removeItem(e),null}}saveStoredSession(e){const t=this.getSessionStorageKey();this.storageManager.setItem(t,JSON.stringify(e))}getSessionStorageKey(){return Ke(this.getProjectId())}getProjectId(){return this.projectId}startTracking(){if(this.isTracking){a("warn","Session tracking already active");return}const e=this.recoverSession(),t=e??this.generateSessionId(),r=!!e;this.isTracking=!0;try{this.set("sessionId",t),this.persistSession(t),r||this.eventManager.track({type:u.SESSION_START}),this.initCrossTabSync(),this.shareSession(t),this.setupSessionTimeout(),this.setupActivityListeners(),this.setupLifecycleListeners()}catch(s){throw this.isTracking=!1,this.clearSessionTimeout(),this.cleanupActivityListeners(),this.cleanupLifecycleListeners(),this.cleanupCrossTabSync(),this.set("sessionId",null),s}}generateSessionId(){return`${Date.now()}-${Math.random().toString(36).substring(2,11)}`}setupSessionTimeout(){this.clearSessionTimeout();const e=this.get("config")?.sessionTimeout??9e5;this.sessionTimeoutId=setTimeout(()=>{this.endSession("inactivity")},e)}resetSessionTimeout(){this.setupSessionTimeout();const e=this.get("sessionId");e&&this.persistSession(e)}clearSessionTimeout(){this.sessionTimeoutId&&(clearTimeout(this.sessionTimeoutId),this.sessionTimeoutId=null)}setupActivityListeners(){this.activityHandler=()=>{this.resetSessionTimeout()},document.addEventListener("click",this.activityHandler,{passive:!0}),document.addEventListener("keydown",this.activityHandler,{passive:!0}),document.addEventListener("scroll",this.activityHandler,{passive:!0})}cleanupActivityListeners(){this.activityHandler&&(document.removeEventListener("click",this.activityHandler),document.removeEventListener("keydown",this.activityHandler),document.removeEventListener("scroll",this.activityHandler),this.activityHandler=null)}setupLifecycleListeners(){this.visibilityChangeHandler||this.beforeUnloadHandler||(this.visibilityChangeHandler=()=>{document.hidden?this.clearSessionTimeout():this.get("sessionId")&&this.setupSessionTimeout()},this.beforeUnloadHandler=()=>{this.endSession("page_unload")},document.addEventListener("visibilitychange",this.visibilityChangeHandler),window.addEventListener("beforeunload",this.beforeUnloadHandler))}cleanupLifecycleListeners(){this.visibilityChangeHandler&&(document.removeEventListener("visibilitychange",this.visibilityChangeHandler),this.visibilityChangeHandler=null),this.beforeUnloadHandler&&(window.removeEventListener("beforeunload",this.beforeUnloadHandler),this.beforeUnloadHandler=null)}endSession(e){const t=this.get("sessionId");if(!t){a("warn","endSession called without active session",{data:{reason:e}}),this.resetSessionState(e);return}this.eventManager.track({type:u.SESSION_END,session_end_reason:e}),this.eventManager.flushImmediatelySync()||a("warn","Sync flush failed during session end, events persisted for recovery",{data:{reason:e,sessionId:t}}),this.broadcastSessionEnd(t,e),this.resetSessionState(e)}resetSessionState(e){this.clearSessionTimeout(),this.cleanupActivityListeners(),this.cleanupLifecycleListeners(),this.cleanupCrossTabSync(),e!=="page_unload"&&this.clearStoredSession(),this.set("sessionId",null),this.set("hasStartSession",!1),this.isTracking=!1}stopTracking(){this.endSession("manual_stop")}destroy(){this.clearSessionTimeout(),this.cleanupActivityListeners(),this.cleanupCrossTabSync(),this.cleanupLifecycleListeners(),this.isTracking=!1,this.set("hasStartSession",!1)}}class vt extends S{eventManager;storageManager;sessionManager=null;destroyed=!1;constructor(e,t){super(),this.eventManager=t,this.storageManager=e}startTracking(){if(this.isActive())return;if(this.destroyed){a("warn","Cannot start tracking on destroyed handler");return}const e=this.get("config"),t=e?.integrations?.tracelog?.projectId??e?.integrations?.custom?.collectApiUrl??"default";if(!t)throw new Error("Cannot start session tracking: config not available");try{this.sessionManager=new pt(this.storageManager,this.eventManager,t),this.sessionManager.startTracking(),this.eventManager.flushPendingEvents()}catch(r){if(this.sessionManager){try{this.sessionManager.destroy()}catch{}this.sessionManager=null}throw a("error","Failed to start session tracking",{error:r}),r}}isActive(){return this.sessionManager!==null&&!this.destroyed}cleanupSessionManager(){this.sessionManager&&(this.sessionManager.stopTracking(),this.sessionManager.destroy(),this.sessionManager=null)}stopTracking(){this.cleanupSessionManager()}destroy(){this.destroyed||(this.sessionManager&&(this.sessionManager.destroy(),this.sessionManager=null),this.destroyed=!0,this.set("hasStartSession",!1))}}class At extends S{eventManager;onTrack;originalPushState;originalReplaceState;lastPageViewTime=0;constructor(e,t){super(),this.eventManager=e,this.onTrack=t}startTracking(){this.trackInitialPageView(),window.addEventListener("popstate",this.trackCurrentPage,!0),window.addEventListener("hashchange",this.trackCurrentPage,!0),this.patchHistory("pushState"),this.patchHistory("replaceState")}stopTracking(){window.removeEventListener("popstate",this.trackCurrentPage,!0),window.removeEventListener("hashchange",this.trackCurrentPage,!0),this.originalPushState&&(window.history.pushState=this.originalPushState),this.originalReplaceState&&(window.history.replaceState=this.originalReplaceState),this.lastPageViewTime=0}patchHistory(e){const t=window.history[e];e==="pushState"&&!this.originalPushState?this.originalPushState=t:e==="replaceState"&&!this.originalReplaceState&&(this.originalReplaceState=t),window.history[e]=(...r)=>{t.apply(window.history,r),this.trackCurrentPage()}}trackCurrentPage=()=>{const e=window.location.href,t=Z(e,this.get("config").sensitiveQueryParams);if(this.get("pageUrl")===t)return;const r=Date.now(),s=this.get("config").pageViewThrottleMs??1e3;if(r-this.lastPageViewTime<s)return;this.lastPageViewTime=r,this.onTrack();const i=this.get("pageUrl");this.set("pageUrl",t);const o=this.extractPageViewData();this.eventManager.track({type:u.PAGE_VIEW,page_url:this.get("pageUrl"),from_page_url:i,...o&&{page_view:o}})};trackInitialPageView(){const e=Z(window.location.href,this.get("config").sensitiveQueryParams),t=this.extractPageViewData();this.lastPageViewTime=Date.now(),this.eventManager.track({type:u.PAGE_VIEW,page_url:e,...t&&{page_view:t}}),this.onTrack()}extractPageViewData(){const{pathname:e,search:t,hash:r}=window.location,{referrer:s}=document,{title:i}=document;return!s&&!i&&!e&&!t&&!r?void 0:{...s&&{referrer:s},...i&&{title:i},...e&&{pathname:e},...t&&{search:t},...r&&{hash:r}}}}class wt extends S{eventManager;clickHandler;lastClickTimes=new Map;constructor(e){super(),this.eventManager=e}startTracking(){this.clickHandler||(this.clickHandler=e=>{const t=e,r=t.target,s=typeof HTMLElement<"u"&&r instanceof HTMLElement?r:typeof HTMLElement<"u"&&r instanceof Node&&r.parentElement instanceof HTMLElement?r.parentElement:null;if(!s){a("warn","Click target not found or not an element");return}if(this.shouldIgnoreElement(s))return;const i=this.get("config")?.clickThrottleMs??300;if(i>0&&!this.checkClickThrottle(s,i))return;const o=this.findTrackingElement(s),l=this.getRelevantClickElement(s),c=this.calculateClickCoordinates(t,s);if(o){const T=this.extractTrackingData(o);if(T){const m=this.createCustomEventData(T);this.eventManager.track({type:u.CUSTOM,custom_event:{name:m.name,...m.value&&{metadata:{value:m.value}}}})}}const d=this.generateClickData(s,l,c);this.eventManager.track({type:u.CLICK,click_data:d})},window.addEventListener("click",this.clickHandler,!0))}stopTracking(){this.clickHandler&&(window.removeEventListener("click",this.clickHandler,!0),this.clickHandler=void 0),this.lastClickTimes.clear()}shouldIgnoreElement(e){return e.hasAttribute(`${A}-ignore`)?!0:e.closest(`[${A}-ignore]`)!==null}checkClickThrottle(e,t){const r=this.getElementSignature(e),s=Date.now(),i=this.lastClickTimes.get(r);return i!==void 0&&s-i<t?(a("debug","ClickHandler: Click suppressed by throttle",{data:{signature:r,throttleRemaining:t-(s-i)}}),!1):(this.lastClickTimes.set(r,s),!0)}getElementSignature(e){if(e.id)return`#${e.id}`;const t=e.getAttribute("data-testid");if(t)return`[data-testid="${t}"]`;const r=e.getAttribute(`${A}-name`);return r?`[${A}-name="${r}"]`:this.getElementPath(e)}getElementPath(e){const t=[];let r=e;for(;r&&r!==document.body;){let s=r.tagName.toLowerCase();if(r.className){const i=r.className.split(" ")[0];i&&(s+=`.${i}`)}t.unshift(s),r=r.parentElement}return t.join(">")||"unknown"}findTrackingElement(e){return e.hasAttribute(`${A}-name`)?e:e.closest(`[${A}-name]`)}getRelevantClickElement(e){for(const t of Ue)try{if(e.matches(t))return e;const r=e.closest(t);if(r)return r}catch(r){a("warn","Invalid selector in element search",{error:r,data:{selector:t}});continue}return e}clamp(e){return Math.max(0,Math.min(1,Number(e.toFixed(3))))}calculateClickCoordinates(e,t){const r=t.getBoundingClientRect(),s=e.clientX,i=e.clientY,o=r.width>0?this.clamp((s-r.left)/r.width):0,l=r.height>0?this.clamp((i-r.top)/r.height):0;return{x:s,y:i,relativeX:o,relativeY:l}}extractTrackingData(e){const t=e.getAttribute(`${A}-name`),r=e.getAttribute(`${A}-value`);if(t)return{element:e,name:t,...r&&{value:r}}}generateClickData(e,t,r){const{x:s,y:i,relativeX:o,relativeY:l}=r,c=this.getRelevantText(e,t),d=this.extractElementAttributes(t);return{x:s,y:i,relativeX:o,relativeY:l,tag:t.tagName.toLowerCase(),...t.id&&{id:t.id},...t.className&&{class:t.className},...c&&{text:c},...d.href&&{href:d.href},...d.title&&{title:d.title},...d.alt&&{alt:d.alt},...d.role&&{role:d.role},...d["aria-label"]&&{ariaLabel:d["aria-label"]},...Object.keys(d).length>0&&{dataAttributes:d}}}sanitizeText(e){let t=e;for(const r of q){const s=new RegExp(r.source,r.flags);t=t.replace(s,"[REDACTED]")}return t}getRelevantText(e,t){const r=e.textContent?.trim()??"",s=t.textContent?.trim()??"";if(!r&&!s)return"";let i="";return r&&r.length<=255?i=r:s.length<=255?i=s:i=s.slice(0,252)+"...",this.sanitizeText(i)}extractElementAttributes(e){const t=["id","class","data-testid","aria-label","title","href","type","name","alt","role"],r={};for(const s of t){const i=e.getAttribute(s);i&&(r[s]=i)}return r}createCustomEventData(e){return{name:e.name,...e.value&&{value:e.value}}}}class Mt extends S{eventManager;containers=[];limitWarningLogged=!1;minDepthChange=5;minIntervalMs=500;maxEventsPerSession=120;windowScrollableCache=null;retryTimeoutId=null;constructor(e){super(),this.eventManager=e}startTracking(){this.limitWarningLogged=!1,this.applyConfigOverrides(),this.set("scrollEventCount",0),this.tryDetectScrollContainers(0)}stopTracking(){this.retryTimeoutId!==null&&(clearTimeout(this.retryTimeoutId),this.retryTimeoutId=null);for(const e of this.containers)this.clearContainerTimer(e),e.element instanceof Window?window.removeEventListener("scroll",e.listener):e.element.removeEventListener("scroll",e.listener);this.containers.length=0,this.set("scrollEventCount",0),this.limitWarningLogged=!1,this.windowScrollableCache=null}tryDetectScrollContainers(e){const t=this.findScrollableElements();if(t.length>0){for(const r of t){const s=this.getElementSelector(r);this.setupScrollContainer(r,s)}this.applyPrimaryScrollSelectorIfConfigured();return}if(e<5){this.retryTimeoutId=window.setTimeout(()=>{this.retryTimeoutId=null,this.tryDetectScrollContainers(e+1)},200);return}this.containers.length===0&&this.setupScrollContainer(window,"window"),this.applyPrimaryScrollSelectorIfConfigured()}applyPrimaryScrollSelectorIfConfigured(){const e=this.get("config");e?.primaryScrollSelector&&this.applyPrimaryScrollSelector(e.primaryScrollSelector)}findScrollableElements(){if(!document.body)return[];const e=[],t=document.createTreeWalker(document.body,NodeFilter.SHOW_ELEMENT,{acceptNode:s=>{const i=s;if(!i.isConnected||!i.offsetParent)return NodeFilter.FILTER_SKIP;const o=getComputedStyle(i);return o.overflowY==="auto"||o.overflowY==="scroll"||o.overflow==="auto"||o.overflow==="scroll"?NodeFilter.FILTER_ACCEPT:NodeFilter.FILTER_SKIP}});let r;for(;(r=t.nextNode())&&e.length<10;){const s=r;this.isElementScrollable(s)&&e.push(s)}return e}getElementSelector(e){if(e===window)return"window";const t=e;if(t.id)return`#${t.id}`;if(t.className&&typeof t.className=="string"){const r=t.className.split(" ").filter(s=>s.trim())[0];if(r)return`.${r}`}return t.tagName.toLowerCase()}determineIfPrimary(e){return this.isWindowScrollable()?e===window:this.containers.length===0}setupScrollContainer(e,t){if(this.containers.some(d=>d.element===e)||e!==window&&!this.isElementScrollable(e))return;const s=()=>{this.get("suppressNextScroll")||(this.clearContainerTimer(c),c.debounceTimer=window.setTimeout(()=>{const d=this.calculateScrollData(c);if(d){const T=Date.now();this.processScrollEvent(c,d,T)}c.debounceTimer=null},250))},i=this.getScrollTop(e),o=this.calculateScrollDepth(i,this.getScrollHeight(e),this.getViewportHeight(e)),l=this.determineIfPrimary(e),c={element:e,selector:t,isPrimary:l,lastScrollPos:i,lastDepth:o,lastDirection:U.DOWN,lastEventTime:0,maxDepthReached:o,debounceTimer:null,listener:s};this.containers.push(c),e instanceof Window?window.addEventListener("scroll",s,{passive:!0}):e.addEventListener("scroll",s,{passive:!0})}processScrollEvent(e,t,r){if(!this.shouldEmitScrollEvent(e,t,r))return;e.lastEventTime=r,e.lastDepth=t.depth,e.lastDirection=t.direction;const s=this.get("scrollEventCount")??0;this.set("scrollEventCount",s+1),this.eventManager.track({type:u.SCROLL,scroll_data:{...t,container_selector:e.selector,is_primary:e.isPrimary}})}shouldEmitScrollEvent(e,t,r){return this.hasReachedSessionLimit()?(this.logLimitOnce(),!1):!(!this.hasElapsedMinimumInterval(e,r)||!this.hasSignificantDepthChange(e,t.depth))}hasReachedSessionLimit(){return(this.get("scrollEventCount")??0)>=this.maxEventsPerSession}hasElapsedMinimumInterval(e,t){return e.lastEventTime===0?!0:t-e.lastEventTime>=this.minIntervalMs}hasSignificantDepthChange(e,t){return Math.abs(t-e.lastDepth)>=this.minDepthChange}logLimitOnce(){this.limitWarningLogged||(this.limitWarningLogged=!0,a("warn","Max scroll events per session reached",{data:{limit:this.maxEventsPerSession}}))}applyConfigOverrides(){this.minDepthChange=5,this.minIntervalMs=500,this.maxEventsPerSession=120}isWindowScrollable(){return this.windowScrollableCache!==null?this.windowScrollableCache:(this.windowScrollableCache=document.documentElement.scrollHeight>window.innerHeight,this.windowScrollableCache)}clearContainerTimer(e){e.debounceTimer!==null&&(clearTimeout(e.debounceTimer),e.debounceTimer=null)}getScrollDirection(e,t){return e>t?U.DOWN:U.UP}calculateScrollDepth(e,t,r){if(t<=r)return 0;const s=t-r;return Math.min(100,Math.max(0,Math.floor(e/s*100)))}calculateScrollData(e){const{element:t,lastScrollPos:r,lastEventTime:s}=e,i=this.getScrollTop(t),o=Date.now(),l=Math.abs(i-r);if(l<10||t===window&&!this.isWindowScrollable())return null;const c=this.getViewportHeight(t),d=this.getScrollHeight(t),T=this.getScrollDirection(i,r),m=this.calculateScrollDepth(i,d,c),O=s>0?o-s:0,_=O>0?Math.round(l/O*1e3):0;return m>e.maxDepthReached&&(e.maxDepthReached=m),e.lastScrollPos=i,{depth:m,direction:T,velocity:_,max_depth_reached:e.maxDepthReached}}getScrollTop(e){return e instanceof Window?window.scrollY:e.scrollTop}getViewportHeight(e){return e instanceof Window?window.innerHeight:e.clientHeight}getScrollHeight(e){return e instanceof Window?document.documentElement.scrollHeight:e.scrollHeight}isElementScrollable(e){const t=getComputedStyle(e),r=t.overflowY==="auto"||t.overflowY==="scroll"||t.overflowX==="auto"||t.overflowX==="scroll"||t.overflow==="auto"||t.overflow==="scroll",s=e.scrollHeight>e.clientHeight||e.scrollWidth>e.clientWidth;return r&&s}applyPrimaryScrollSelector(e){let t;if(e==="window")t=window;else{const s=document.querySelector(e);if(!(s instanceof HTMLElement)){a("warn",`Selector "${e}" did not match an HTMLElement`);return}t=s}this.containers.forEach(s=>{this.updateContainerPrimary(s,s.element===t)}),!this.containers.some(s=>s.element===t)&&t instanceof HTMLElement&&this.isElementScrollable(t)&&this.setupScrollContainer(t,e)}updateContainerPrimary(e,t){e.isPrimary=t}}class Nt extends S{eventManager;trackedElements=new Map;observer=null;mutationObserver=null;mutationDebounceTimer=null;config=null;constructor(e){super(),this.eventManager=e}startTracking(){const e=this.get("config");if(this.config=e.viewport??null,!this.config?.elements||this.config.elements.length===0)return;const t=this.config.threshold??.5,r=this.config.minDwellTime??1e3;if(t<0||t>1){a("warn","ViewportHandler: Invalid threshold, must be between 0 and 1");return}if(r<0){a("warn","ViewportHandler: Invalid minDwellTime, must be non-negative");return}if(typeof IntersectionObserver>"u"){a("warn","ViewportHandler: IntersectionObserver not supported in this browser");return}this.observer=new IntersectionObserver(this.handleIntersection,{threshold:t}),this.observeElements(),this.setupMutationObserver()}stopTracking(){this.observer&&(this.observer.disconnect(),this.observer=null),this.mutationObserver&&(this.mutationObserver.disconnect(),this.mutationObserver=null),this.mutationDebounceTimer!==null&&(window.clearTimeout(this.mutationDebounceTimer),this.mutationDebounceTimer=null);for(const e of this.trackedElements.values())e.timeoutId!==null&&window.clearTimeout(e.timeoutId);this.trackedElements.clear()}observeElements(){if(!this.config||!this.observer)return;const e=this.config.maxTrackedElements??100;let t=this.trackedElements.size;for(const r of this.config.elements)try{const s=document.querySelectorAll(r.selector);for(const i of Array.from(s)){if(t>=e){a("warn","ViewportHandler: Maximum tracked elements reached",{data:{limit:e,selector:r.selector,message:"Some elements will not be tracked. Consider more specific selectors."}});return}i.hasAttribute(`${A}-ignore`)||this.trackedElements.has(i)||(this.trackedElements.set(i,{element:i,selector:r.selector,id:r.id,name:r.name,startTime:null,timeoutId:null,lastFiredTime:null}),this.observer?.observe(i),t++)}}catch(s){a("warn",`ViewportHandler: Invalid selector "${r.selector}"`,{error:s})}a("debug","ViewportHandler: Elements tracked",{data:{count:t,limit:e}})}handleIntersection=e=>{if(!this.config)return;const t=this.config.minDwellTime??1e3;for(const r of e){const s=this.trackedElements.get(r.target);s&&(r.isIntersecting?s.startTime===null&&(s.startTime=performance.now(),s.timeoutId=window.setTimeout(()=>{this.fireViewportEvent(s,r.intersectionRatio)},t)):s.startTime!==null&&(s.timeoutId!==null&&(window.clearTimeout(s.timeoutId),s.timeoutId=null),s.startTime=null))}};fireViewportEvent(e,t){if(e.startTime===null)return;const r=Math.round(performance.now()-e.startTime);if(e.element.hasAttribute("data-tlog-ignore"))return;const s=this.config?.cooldownPeriod??6e4,i=Date.now();if(e.lastFiredTime!==null&&i-e.lastFiredTime<s){a("debug","ViewportHandler: Event suppressed by cooldown period",{data:{selector:e.selector,cooldownRemaining:s-(i-e.lastFiredTime)}}),e.startTime=null,e.timeoutId=null;return}const o={selector:e.selector,dwellTime:r,visibilityRatio:t,...e.id!==void 0&&{id:e.id},...e.name!==void 0&&{name:e.name}};this.eventManager.track({type:u.VIEWPORT_VISIBLE,viewport_data:o}),e.startTime=null,e.timeoutId=null,e.lastFiredTime=i}setupMutationObserver(){if(!(!this.config||typeof MutationObserver>"u")){if(!document.body){a("warn","ViewportHandler: document.body not available, skipping MutationObserver setup");return}this.mutationObserver=new MutationObserver(e=>{let t=!1;for(const r of e)r.type==="childList"&&(r.addedNodes.length>0&&(t=!0),r.removedNodes.length>0&&this.cleanupRemovedNodes(r.removedNodes));t&&(this.mutationDebounceTimer!==null&&window.clearTimeout(this.mutationDebounceTimer),this.mutationDebounceTimer=window.setTimeout(()=>{this.observeElements(),this.mutationDebounceTimer=null},100))}),this.mutationObserver.observe(document.body,{childList:!0,subtree:!0})}}cleanupRemovedNodes(e){e.forEach(t=>{if(t.nodeType!==1)return;const r=t,s=this.trackedElements.get(r);s&&(s.timeoutId!==null&&window.clearTimeout(s.timeoutId),this.observer?.unobserve(r),this.trackedElements.delete(r)),Array.from(this.trackedElements.keys()).filter(o=>r.contains(o)).forEach(o=>{const l=this.trackedElements.get(o);l&&l.timeoutId!==null&&window.clearTimeout(l.timeoutId),this.observer?.unobserve(o),this.trackedElements.delete(o)})})}}class yt extends S{isInitialized=!1;async initialize(){if(this.isInitialized)return;const e=this.get("config").integrations?.googleAnalytics?.measurementId,t=this.get("userId");if(!(!e?.trim()||!t?.trim()))try{if(this.isScriptAlreadyLoaded()){this.isInitialized=!0;return}await this.loadScript(e),this.configureGtag(e,t),this.isInitialized=!0}catch(r){a("error","Google Analytics initialization failed",{error:r})}}trackEvent(e,t){if(!(!e?.trim()||!this.isInitialized||typeof window.gtag!="function"))try{const r=Array.isArray(t)?{items:t}:t;window.gtag("event",e,r)}catch(r){a("error","Google Analytics event tracking failed",{error:r})}}cleanup(){this.isInitialized=!1;const e=document.getElementById("tracelog-ga-script");e&&e.remove()}isScriptAlreadyLoaded(){return document.getElementById("tracelog-ga-script")?!0:!!document.querySelector('script[src*="googletagmanager.com/gtag/js"]')}async loadScript(e){return new Promise((t,r)=>{const s=document.createElement("script");s.id="tracelog-ga-script",s.async=!0,s.src=`https://www.googletagmanager.com/gtag/js?id=${e}`,s.onload=()=>{t()},s.onerror=()=>{r(new Error("Failed to load Google Analytics script"))},document.head.appendChild(s)})}configureGtag(e,t){const r=document.createElement("script");r.innerHTML=`
|
|
1
|
+
(function(h){"use strict";const A="data-tlog",Ue=["button","a",'input[type="button"]','input[type="submit"]','input[type="reset"]','input[type="checkbox"]','input[type="radio"]',"select","textarea",'[role="button"]','[role="link"]','[role="tab"]','[role="menuitem"]','[role="option"]','[role="checkbox"]','[role="radio"]','[role="switch"]',"[routerLink]","[ng-click]","[data-action]","[data-click]","[data-navigate]","[data-toggle]","[onclick]",".btn",".button",".clickable",".nav-link",".menu-item","[data-testid]",'[tabindex="0"]'],He=["utm_source","utm_medium","utm_campaign","utm_term","utm_content"],Fe=["token","auth","key","session","reset","password","api_key","apikey","secret","access_token","refresh_token","verification","code","otp"],E={INVALID_SESSION_TIMEOUT:"Session timeout must be between 30000ms (30 seconds) and 86400000ms (24 hours)",INVALID_SAMPLING_RATE:"Sampling rate must be between 0 and 1",INVALID_ERROR_SAMPLING_RATE:"Error sampling must be between 0 and 1",INVALID_TRACELOG_PROJECT_ID:"TraceLog project ID is required when integration is enabled",INVALID_CUSTOM_API_URL:"Custom API URL is required when integration is enabled",INVALID_GOOGLE_ANALYTICS_ID:"Google Analytics measurement ID is required when integration is enabled",INVALID_GLOBAL_METADATA:"Global metadata must be an object",INVALID_SENSITIVE_QUERY_PARAMS:"Sensitive query params must be an array of strings",INVALID_PRIMARY_SCROLL_SELECTOR:"Primary scroll selector must be a non-empty string",INVALID_PRIMARY_SCROLL_SELECTOR_SYNTAX:"Invalid CSS selector syntax for primaryScrollSelector",INVALID_PAGE_VIEW_THROTTLE:"Page view throttle must be a non-negative number",INVALID_CLICK_THROTTLE:"Click throttle must be a non-negative number",INVALID_MAX_SAME_EVENT_PER_MINUTE:"Max same event per minute must be a positive number",INVALID_VIEWPORT_CONFIG:"Viewport config must be an object",INVALID_VIEWPORT_ELEMENTS:"Viewport elements must be a non-empty array",INVALID_VIEWPORT_ELEMENT:"Each viewport element must have a valid selector string",INVALID_VIEWPORT_ELEMENT_ID:"Viewport element id must be a non-empty string",INVALID_VIEWPORT_ELEMENT_NAME:"Viewport element name must be a non-empty string",INVALID_VIEWPORT_THRESHOLD:"Viewport threshold must be a number between 0 and 1",INVALID_VIEWPORT_MIN_DWELL_TIME:"Viewport minDwellTime must be a non-negative number",INVALID_VIEWPORT_COOLDOWN_PERIOD:"Viewport cooldownPeriod must be a non-negative number",INVALID_VIEWPORT_MAX_TRACKED_ELEMENTS:"Viewport maxTrackedElements must be a positive number"},Ge=[/<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi,/javascript:/gi,/on\w+\s*=/gi,/<iframe\b[^<]*(?:(?!<\/iframe>)<[^<]*)*<\/iframe>/gi,/<embed\b[^>]*>/gi,/<object\b[^<]*(?:(?!<\/object>)<[^<]*)*<\/object>/gi];var F=(n=>(n.Localhost="localhost:8080",n.Fail="localhost:9999",n))(F||{}),w=(n=>(n.Mobile="mobile",n.Tablet="tablet",n.Desktop="desktop",n.Unknown="unknown",n))(w||{}),G=(n=>(n.EVENT="event",n.QUEUE="queue",n))(G||{});class L extends Error{constructor(e,t){super(e),this.statusCode=t,this.name="PermanentError",Error.captureStackTrace&&Error.captureStackTrace(this,L)}}var u=(n=>(n.PAGE_VIEW="page_view",n.CLICK="click",n.SCROLL="scroll",n.SESSION_START="session_start",n.SESSION_END="session_end",n.CUSTOM="custom",n.WEB_VITALS="web_vitals",n.ERROR="error",n.VIEWPORT_VISIBLE="viewport_visible",n))(u||{}),U=(n=>(n.UP="up",n.DOWN="down",n))(U||{}),C=(n=>(n.JS_ERROR="js_error",n.PROMISE_REJECTION="promise_rejection",n))(C||{}),b=(n=>(n.QA="qa",n))(b||{});function xe(n){return n.type===u.SCROLL&&"scroll_data"in n&&n.scroll_data.is_primary===!0}function We(n){return n.type===u.SCROLL&&"scroll_data"in n&&n.scroll_data.is_primary===!1}class P extends Error{constructor(e,t,r){super(e),this.errorCode=t,this.layer=r,this.name=this.constructor.name,Error.captureStackTrace&&Error.captureStackTrace(this,this.constructor)}}class f extends P{constructor(e,t="config"){super(e,"APP_CONFIG_INVALID",t)}}class fe extends P{constructor(e,t="config"){super(e,"SESSION_TIMEOUT_INVALID",t)}}class j extends P{constructor(e,t="config"){super(e,"SAMPLING_RATE_INVALID",t)}}class y extends P{constructor(e,t="config"){super(e,"INTEGRATION_INVALID",t)}}class Xe extends P{constructor(e,t,r="runtime"){super(e,"INITIALIZATION_TIMEOUT",r),this.timeoutMs=t}}const Be=(n,e)=>{if(e){if(e instanceof Error){const t=e.message.replace(/\s+at\s+.*$/gm,"").replace(/\(.*?:\d+:\d+\)/g,"");return`[TraceLog] ${n}: ${t}`}return`[TraceLog] ${n}: ${e instanceof Error?e.message:"Unknown error"}`}return`[TraceLog] ${n}`},a=(n,e,t)=>{const{error:r,data:s,showToClient:i=!1}=t??{},o=r?Be(e,r):`[TraceLog] ${e}`,l=n==="error"?"error":n==="warn"?"warn":"log";if(!(n==="debug"||n==="info"&&!i))if(s!==void 0){const c=$e(s);console[l](o,c)}else s!==void 0?console[l](o,s):console[l](o)},$e=n=>{const e={},t=["token","password","secret","key","apikey","api_key","sessionid","session_id"];for(const[r,s]of Object.entries(n)){const i=r.toLowerCase();t.some(o=>i.includes(o))?e[r]="[REDACTED]":e[r]=s}return e};let K,ge;const ze=()=>{typeof window<"u"&&!K&&(K=window.matchMedia("(pointer: coarse)"),ge=window.matchMedia("(hover: none)"))},Ye=()=>{try{const n=navigator;if(n.userAgentData&&typeof n.userAgentData.mobile=="boolean")return n.userAgentData.platform&&/ipad|tablet/i.test(n.userAgentData.platform)?w.Tablet:n.userAgentData.mobile?w.Mobile:w.Desktop;ze();const e=window.innerWidth,t=K?.matches??!1,r=ge?.matches??!1,s="ontouchstart"in window||navigator.maxTouchPoints>0,i=navigator.userAgent.toLowerCase(),o=/mobile|android|iphone|ipod|blackberry|iemobile|opera mini/.test(i),l=/tablet|ipad|android(?!.*mobile)/.test(i);return e<=767||o&&s?w.Mobile:e>=768&&e<=1024||l||t&&r&&s?w.Tablet:w.Desktop}catch(n){return a("warn","Device detection failed, defaulting to desktop",{error:n}),w.Desktop}},M="tlog",me=`${M}:qa_mode`,Qe=`${M}:uid`,je=n=>n?`${M}:${n}:queue`:`${M}:queue`,Ke=n=>n?`${M}:${n}:session`:`${M}:session`,qe=n=>n?`${M}:${n}:broadcast`:`${M}:broadcast`,Se={LCP:4e3,FCP:1800,CLS:.25,INP:200,TTFB:800,LONG_TASK:50},Ze=1e3,q=[/\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Z|a-z]{2,}\b/gi,/\b\d{3}[-.]?\d{3}[-.]?\d{4}\b/g,/\b\d{4}[-\s]?\d{4}[-\s]?\d{4}[-\s]?\d{4}\b/g,/\b[A-Z]{2}\d{2}[-\s]?\d{4}[-\s]?\d{4}[-\s]?\d{4}[-\s]?\d{4}[-\s]?\d{4}\b/gi,/\b[sp]k_(test|live)_[a-zA-Z0-9]{10,}\b/gi,/Bearer\s+[A-Za-z0-9_-]+(?:\.[A-Za-z0-9_-]+)?(?:\.[A-Za-z0-9_-]+)?/gi,/:\/\/[^:/]+:([^@]+)@/gi],_e=500,Te=5e3,x=50,Je=x*2,Ie=1,et=1e3,tt=10,pe=5e3,rt=6e4,ve="tlog_mode",nt="qa",st=()=>{if(sessionStorage.getItem(me)==="true")return!0;const e=new URLSearchParams(window.location.search),r=e.get(ve)===nt;if(r){sessionStorage.setItem(me,"true"),e.delete(ve);const s=e.toString(),i=`${window.location.pathname}${s?"?"+s:""}${window.location.hash}`;try{window.history.replaceState({},"",i)}catch(o){a("warn","History API not available, cannot replace URL",{error:o})}console.log("%c[TraceLog] QA Mode ACTIVE","background: #ff9800; color: white; font-weight: bold; padding: 2px 8px; border-radius: 3px;")}return r},Ae=()=>{const n=new URLSearchParams(window.location.search),e={};return He.forEach(r=>{const s=n.get(r);if(s){const i=r.split("utm_")[1];e[i]=s}}),Object.keys(e).length?e:void 0},it=()=>typeof crypto<"u"&&crypto.randomUUID?crypto.randomUUID():"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g,n=>{const e=Math.random()*16|0;return(n==="x"?e:e&3|8).toString(16)}),ot=()=>{const n=Date.now();let e="";try{if(typeof crypto<"u"&&crypto.getRandomValues){const t=crypto.getRandomValues(new Uint8Array(4));t&&(e=Array.from(t,r=>r.toString(16).padStart(2,"0")).join(""))}}catch{}return e||(e=Math.floor(Math.random()*4294967295).toString(16).padStart(8,"0")),`${n}-${e}`},we=(n,e=!1)=>{try{const t=new URL(n),r=t.protocol==="https:",s=t.protocol==="http:";return r||e&&s}catch{return!1}},at=n=>{if(n.integrations?.tracelog?.projectId){const s=new URL(window.location.href).hostname.split(".");if(s.length===0)throw new Error("Invalid URL");const i=n.integrations.tracelog.projectId,o=s.slice(-2).join("."),l=`https://${i}.${o}/collect`;if(!we(l))throw new Error("Invalid URL");return l}const e=n.integrations?.custom?.collectApiUrl;if(e){const t=n.integrations?.custom?.allowHttp??!1;if(!we(e,t))throw new Error("Invalid URL");return e}return""},Z=(n,e=[])=>{try{const t=new URL(n),r=t.searchParams,s=[...new Set([...Fe,...e])];let i=!1;const o=[];return s.forEach(c=>{r.has(c)&&(r.delete(c),i=!0,o.push(c))}),!i&&n.includes("?")?n:(t.search=r.toString(),t.toString())}catch(t){return a("warn","URL normalization failed, returning original",{error:t,data:{url:n.slice(0,100)}}),n}},ye=n=>{if(!n||typeof n!="string"||n.trim().length===0)return"";let e=n;n.length>1e3&&(e=n.slice(0,Math.max(0,1e3)));let t=0;for(const s of Ge){const i=e;e=e.replace(s,""),i!==e&&t++}return t>0&&a("warn","XSS patterns detected and removed",{data:{patternMatches:t,originalValue:n.slice(0,100)}}),e=e.replaceAll("&","&").replaceAll("<","<").replaceAll(">",">").replaceAll('"',""").replaceAll("'","'").replaceAll("/","/"),e.trim()},J=(n,e=0)=>{if(e>3||n==null)return null;if(typeof n=="string")return ye(n);if(typeof n=="number")return!Number.isFinite(n)||n<-Number.MAX_SAFE_INTEGER||n>Number.MAX_SAFE_INTEGER?0:n;if(typeof n=="boolean")return n;if(Array.isArray(n))return n.slice(0,100).map(s=>J(s,e+1)).filter(s=>s!==null);if(typeof n=="object"){const t={},s=Object.entries(n).slice(0,20);for(const[i,o]of s){const l=ye(i);if(l){const c=J(o,e+1);c!==null&&(t[l]=c)}}return t}return null},lt=n=>{if(typeof n!="object"||n===null)return{};try{const e=J(n);return typeof e=="object"&&e!==null?e:{}}catch(e){const t=e instanceof Error?e.message:String(e);throw new Error(`[TraceLog] Metadata sanitization failed: ${t}`)}},ct=n=>{if(n!==void 0&&(n===null||typeof n!="object"))throw new f("Configuration must be an object","config");if(n){if(n.sessionTimeout!==void 0&&(typeof n.sessionTimeout!="number"||n.sessionTimeout<3e4||n.sessionTimeout>864e5))throw new fe(E.INVALID_SESSION_TIMEOUT,"config");if(n.globalMetadata!==void 0&&(typeof n.globalMetadata!="object"||n.globalMetadata===null))throw new f(E.INVALID_GLOBAL_METADATA,"config");if(n.integrations&&dt(n.integrations),n.sensitiveQueryParams!==void 0){if(!Array.isArray(n.sensitiveQueryParams))throw new f(E.INVALID_SENSITIVE_QUERY_PARAMS,"config");for(const e of n.sensitiveQueryParams)if(typeof e!="string")throw new f("All sensitive query params must be strings","config")}if(n.errorSampling!==void 0&&(typeof n.errorSampling!="number"||n.errorSampling<0||n.errorSampling>1))throw new j(E.INVALID_ERROR_SAMPLING_RATE,"config");if(n.samplingRate!==void 0&&(typeof n.samplingRate!="number"||n.samplingRate<0||n.samplingRate>1))throw new j(E.INVALID_SAMPLING_RATE,"config");if(n.primaryScrollSelector!==void 0){if(typeof n.primaryScrollSelector!="string"||!n.primaryScrollSelector.trim())throw new f(E.INVALID_PRIMARY_SCROLL_SELECTOR,"config");if(n.primaryScrollSelector!=="window")try{document.querySelector(n.primaryScrollSelector)}catch{throw new f(`${E.INVALID_PRIMARY_SCROLL_SELECTOR_SYNTAX}: "${n.primaryScrollSelector}"`,"config")}}if(n.pageViewThrottleMs!==void 0&&(typeof n.pageViewThrottleMs!="number"||n.pageViewThrottleMs<0))throw new f(E.INVALID_PAGE_VIEW_THROTTLE,"config");if(n.clickThrottleMs!==void 0&&(typeof n.clickThrottleMs!="number"||n.clickThrottleMs<0))throw new f(E.INVALID_CLICK_THROTTLE,"config");if(n.maxSameEventPerMinute!==void 0&&(typeof n.maxSameEventPerMinute!="number"||n.maxSameEventPerMinute<=0))throw new f(E.INVALID_MAX_SAME_EVENT_PER_MINUTE,"config");n.viewport!==void 0&&ut(n.viewport)}},ut=n=>{if(typeof n!="object"||n===null)throw new f(E.INVALID_VIEWPORT_CONFIG,"config");if(!n.elements||!Array.isArray(n.elements))throw new f(E.INVALID_VIEWPORT_ELEMENTS,"config");if(n.elements.length===0)throw new f(E.INVALID_VIEWPORT_ELEMENTS,"config");const e=new Set;for(const t of n.elements){if(!t.selector||typeof t.selector!="string"||!t.selector.trim())throw new f(E.INVALID_VIEWPORT_ELEMENT,"config");const r=t.selector.trim();if(e.has(r))throw new f(`Duplicate viewport selector found: "${r}". Each selector should appear only once.`,"config");if(e.add(r),t.id!==void 0&&(typeof t.id!="string"||!t.id.trim()))throw new f(E.INVALID_VIEWPORT_ELEMENT_ID,"config");if(t.name!==void 0&&(typeof t.name!="string"||!t.name.trim()))throw new f(E.INVALID_VIEWPORT_ELEMENT_NAME,"config")}if(n.threshold!==void 0&&(typeof n.threshold!="number"||n.threshold<0||n.threshold>1))throw new f(E.INVALID_VIEWPORT_THRESHOLD,"config");if(n.minDwellTime!==void 0&&(typeof n.minDwellTime!="number"||n.minDwellTime<0))throw new f(E.INVALID_VIEWPORT_MIN_DWELL_TIME,"config");if(n.cooldownPeriod!==void 0&&(typeof n.cooldownPeriod!="number"||n.cooldownPeriod<0))throw new f(E.INVALID_VIEWPORT_COOLDOWN_PERIOD,"config");if(n.maxTrackedElements!==void 0&&(typeof n.maxTrackedElements!="number"||n.maxTrackedElements<=0))throw new f(E.INVALID_VIEWPORT_MAX_TRACKED_ELEMENTS,"config")},dt=n=>{if(n){if(n.tracelog&&(!n.tracelog.projectId||typeof n.tracelog.projectId!="string"||n.tracelog.projectId.trim()===""))throw new y(E.INVALID_TRACELOG_PROJECT_ID,"config");if(n.custom){if(!n.custom.collectApiUrl||typeof n.custom.collectApiUrl!="string"||n.custom.collectApiUrl.trim()==="")throw new y(E.INVALID_CUSTOM_API_URL,"config");if(n.custom.allowHttp!==void 0&&typeof n.custom.allowHttp!="boolean")throw new y("allowHttp must be a boolean","config");const e=n.custom.collectApiUrl.trim();if(!e.startsWith("http://")&&!e.startsWith("https://"))throw new y('Custom API URL must start with "http://" or "https://"',"config");if(!(n.custom.allowHttp??!1)&&e.startsWith("http://"))throw new y("Custom API URL must use HTTPS in production. Set allowHttp: true in integration config to allow HTTP (not recommended)","config")}if(n.googleAnalytics){if(!n.googleAnalytics.measurementId||typeof n.googleAnalytics.measurementId!="string"||n.googleAnalytics.measurementId.trim()==="")throw new y(E.INVALID_GOOGLE_ANALYTICS_ID,"config");if(!n.googleAnalytics.measurementId.trim().match(/^(G-|UA-)/))throw new y('Google Analytics measurement ID must start with "G-" or "UA-"',"config")}}},ht=n=>{ct(n);const e={...n??{},sessionTimeout:n?.sessionTimeout??9e5,globalMetadata:n?.globalMetadata??{},sensitiveQueryParams:n?.sensitiveQueryParams??[],errorSampling:n?.errorSampling??Ie,samplingRate:n?.samplingRate??1,pageViewThrottleMs:n?.pageViewThrottleMs??1e3,clickThrottleMs:n?.clickThrottleMs??300,maxSameEventPerMinute:n?.maxSameEventPerMinute??60};return e.integrations?.custom&&(e.integrations.custom={...e.integrations.custom,allowHttp:e.integrations.custom.allowHttp??!1}),e.viewport&&(e.viewport={...e.viewport,threshold:e.viewport.threshold??.5,minDwellTime:e.viewport.minDwellTime??2e3,cooldownPeriod:e.viewport.cooldownPeriod??6e4,maxTrackedElements:e.viewport.maxTrackedElements??100}),e},Et=n=>{if(typeof n=="string")return!0;if(typeof n=="object"&&n!==null&&!Array.isArray(n)){const e=Object.entries(n);if(e.length>20)return!1;for(const[,t]of e){if(t==null)continue;const r=typeof t;if(r!=="string"&&r!=="number"&&r!=="boolean")return!1}return!0}return!1},Me=(n,e=0)=>{if(typeof n!="object"||n===null||e>1)return!1;for(const t of Object.values(n)){if(t==null)continue;const r=typeof t;if(!(r==="string"||r==="number"||r==="boolean")){if(Array.isArray(t)){if(t.length===0)continue;if(typeof t[0]=="string"){if(!t.every(o=>typeof o=="string"))return!1}else if(!t.every(o=>Et(o)))return!1;continue}if(r==="object"&&e===0){if(!Me(t,e+1))return!1;continue}return!1}}return!0},ft=n=>typeof n!="string"?{valid:!1,error:"Event name must be a string"}:n.length===0?{valid:!1,error:"Event name cannot be empty"}:n.length>120?{valid:!1,error:"Event name is too long (max 120 characters)"}:n.includes("<")||n.includes(">")||n.includes("&")?{valid:!1,error:"Event name contains invalid characters"}:["constructor","prototype","__proto__","eval","function","var","let","const"].includes(n.toLowerCase())?{valid:!1,error:"Event name cannot be a reserved word"}:{valid:!0},Ne=(n,e,t)=>{const r=lt(e),s=`${t} "${n}" metadata error`;if(!Me(r))return{valid:!1,error:`${s}: object has invalid types. Valid types are string, number, boolean or string arrays.`};let i;try{i=JSON.stringify(r)}catch{return{valid:!1,error:`${s}: object contains circular references or cannot be serialized.`}}if(i.length>8192)return{valid:!1,error:`${s}: object is too large (max ${8192/1024} KB).`};if(Object.keys(r).length>10)return{valid:!1,error:`${s}: object has too many keys (max 10 keys).`};for(const[l,c]of Object.entries(r)){if(Array.isArray(c)){if(c.length>10)return{valid:!1,error:`${s}: array property "${l}" is too large (max 10 items).`};for(const d of c)if(typeof d=="string"&&d.length>500)return{valid:!1,error:`${s}: array property "${l}" contains strings that are too long (max 500 characters).`}}if(typeof c=="string"&&c.length>1e3)return{valid:!1,error:`${s}: property "${l}" is too long (max 1000 characters).`}}return{valid:!0,sanitizedMetadata:r}},gt=(n,e,t)=>{if(Array.isArray(e)){const r=[],s=`${t} "${n}" metadata error`;for(let i=0;i<e.length;i++){const o=e[i];if(typeof o!="object"||o===null||Array.isArray(o))return{valid:!1,error:`${s}: array item at index ${i} must be an object.`};const l=Ne(n,o,t);if(!l.valid)return{valid:!1,error:`${s}: array item at index ${i} is invalid: ${l.error}`};l.sanitizedMetadata&&r.push(l.sanitizedMetadata)}return{valid:!0,sanitizedMetadata:r}}return Ne(n,e,t)},mt=(n,e)=>{const t=ft(n);if(!t.valid)return a("error","Event name validation failed",{showToClient:!0,data:{eventName:n,error:t.error}}),t;if(!e)return{valid:!0};const r=gt(n,e,"customEvent");return r.valid||a("error","Event metadata validation failed",{showToClient:!0,data:{eventName:n,error:r.error}}),r};class St{listeners=new Map;on(e,t){this.listeners.has(e)||this.listeners.set(e,[]),this.listeners.get(e).push(t)}off(e,t){const r=this.listeners.get(e);if(r){const s=r.indexOf(t);s>-1&&r.splice(s,1)}}emit(e,t){const r=this.listeners.get(e);r&&r.forEach(s=>{s(t)})}removeAllListeners(){this.listeners.clear()}}const ee={};class S{get(e){return ee[e]}set(e,t){ee[e]=t}getState(){return{...ee}}}class _t extends S{storeManager;lastPermanentErrorLog=null;constructor(e){super(),this.storeManager=e}getQueueStorageKey(){const e=this.get("userId")||"anonymous";return je(e)}sendEventsQueueSync(e){return this.shouldSkipSend()?!0:this.get("config")?.integrations?.custom?.collectApiUrl===F.Fail?(a("warn","Fail mode: simulating network failure (sync)",{data:{events:e.events.length}}),!1):this.sendQueueSyncInternal(e)}async sendEventsQueue(e,t){try{const r=await this.send(e);return r?(this.clearPersistedEvents(),t?.onSuccess?.(e.events.length,e.events,e)):(this.persistEvents(e),t?.onFailure?.()),r}catch(r){return r instanceof L?(this.logPermanentError("Permanent error, not retrying",r),this.clearPersistedEvents(),t?.onFailure?.(),!1):(this.persistEvents(e),t?.onFailure?.(),!1)}}async recoverPersistedEvents(e){try{const t=this.getPersistedData();if(!t||!this.isDataRecent(t)||t.events.length===0){this.clearPersistedEvents();return}const r=this.createRecoveryBody(t);await this.send(r)?(this.clearPersistedEvents(),e?.onSuccess?.(t.events.length,t.events,r)):e?.onFailure?.()}catch(t){if(t instanceof L){this.logPermanentError("Permanent error during recovery, clearing persisted events",t),this.clearPersistedEvents(),e?.onFailure?.();return}a("error","Failed to recover persisted events",{error:t})}}stop(){}async send(e){if(this.shouldSkipSend())return this.simulateSuccessfulSend();if(this.get("config")?.integrations?.custom?.collectApiUrl===F.Fail)return a("warn","Fail mode: simulating network failure",{data:{events:e.events.length}}),!1;const{url:r,payload:s}=this.prepareRequest(e);try{return(await this.sendWithTimeout(r,s)).ok}catch(i){if(i instanceof L)throw i;return a("error","Send request failed",{error:i,data:{events:e.events.length,url:r.replace(/\/\/[^/]+/,"//[DOMAIN]")}}),!1}}async sendWithTimeout(e,t){const r=new AbortController,s=setTimeout(()=>{r.abort()},1e4);try{const i=await fetch(e,{method:"POST",body:t,keepalive:!0,credentials:"include",signal:r.signal,headers:{"Content-Type":"application/json"}});if(!i.ok)throw i.status>=400&&i.status<500?new L(`HTTP ${i.status}: ${i.statusText}`,i.status):new Error(`HTTP ${i.status}: ${i.statusText}`);return i}finally{clearTimeout(s)}}sendQueueSyncInternal(e){const{url:t,payload:r}=this.prepareRequest(e);if(r.length>65536)return a("warn","Payload exceeds sendBeacon limit, persisting for recovery",{data:{size:r.length,limit:65536,events:e.events.length}}),this.persistEvents(e),!1;const s=new Blob([r],{type:"application/json"});if(!this.isSendBeaconAvailable())return a("warn","sendBeacon not available, persisting events for recovery"),this.persistEvents(e),!1;const i=navigator.sendBeacon(t,s);return i||(a("warn","sendBeacon rejected request, persisting events for recovery"),this.persistEvents(e)),i}prepareRequest(e){const t={...e,_metadata:{referer:typeof window<"u"?window.location.href:void 0,timestamp:Date.now()}};return{url:this.get("collectApiUrl"),payload:JSON.stringify(t)}}getPersistedData(){try{const e=this.getQueueStorageKey(),t=this.storeManager.getItem(e);if(t)return JSON.parse(t)}catch(e){a("warn","Failed to parse persisted data",{error:e}),this.clearPersistedEvents()}return null}isDataRecent(e){return!e.timestamp||typeof e.timestamp!="number"?!1:(Date.now()-e.timestamp)/(1e3*60*60)<2}createRecoveryBody(e){return{user_id:e.userId,session_id:e.sessionId,device:e.device,events:e.events,...e.global_metadata&&{global_metadata:e.global_metadata}}}persistEvents(e){try{const t={userId:e.user_id,sessionId:e.session_id,device:e.device,events:e.events,timestamp:Date.now(),...e.global_metadata&&{global_metadata:e.global_metadata}},r=this.getQueueStorageKey();return this.storeManager.setItem(r,JSON.stringify(t)),!!this.storeManager.getItem(r)}catch(t){return a("warn","Failed to persist events",{error:t}),!1}}clearPersistedEvents(){try{const e=this.getQueueStorageKey();this.storeManager.removeItem(e)}catch(e){a("warn","Failed to clear persisted events",{error:e})}}shouldSkipSend(){return!this.get("collectApiUrl")}async simulateSuccessfulSend(){const e=Math.random()*400+100;return await new Promise(t=>setTimeout(t,e)),!0}isSendBeaconAvailable(){return typeof navigator<"u"&&typeof navigator.sendBeacon=="function"}logPermanentError(e,t){const r=Date.now();(!this.lastPermanentErrorLog||this.lastPermanentErrorLog.statusCode!==t.statusCode||r-this.lastPermanentErrorLog.timestamp>=rt)&&(a("error",e,{data:{status:t.statusCode,message:t.message}}),this.lastPermanentErrorLog={statusCode:t.statusCode,timestamp:r})}}class Tt extends S{googleAnalytics;dataSender;emitter;eventsQueue=[];pendingEventsBuffer=[];recentEventFingerprints=new Map;sendIntervalId=null;rateLimitCounter=0;rateLimitWindowStart=0;perEventRateLimits=new Map;sessionEventCounts={total:0,[u.CLICK]:0,[u.PAGE_VIEW]:0,[u.CUSTOM]:0,[u.VIEWPORT_VISIBLE]:0,[u.SCROLL]:0};lastSessionId=null;constructor(e,t=null,r=null){super(),this.googleAnalytics=t,this.dataSender=new _t(e),this.emitter=r}async recoverPersistedEvents(){await this.dataSender.recoverPersistedEvents({onSuccess:(e,t,r)=>{if(t&&t.length>0){const s=t.map(i=>i.id);this.removeProcessedEvents(s),r&&this.emitEventsQueue(r)}},onFailure:()=>{a("warn","Failed to recover persisted events")}})}track({type:e,page_url:t,from_page_url:r,scroll_data:s,click_data:i,custom_event:o,web_vitals:l,error_data:c,session_end_reason:d,viewport_data:T}){if(!e){a("error","Event type is required - event will be ignored");return}const m=this.get("sessionId");if(!m){this.pendingEventsBuffer.length>=100&&(this.pendingEventsBuffer.shift(),a("warn","Pending events buffer full - dropping oldest event",{data:{maxBufferSize:100}})),this.pendingEventsBuffer.push({type:e,page_url:t,from_page_url:r,scroll_data:s,click_data:i,custom_event:o,web_vitals:l,error_data:c,session_end_reason:d,viewport_data:T});return}this.lastSessionId!==m&&(this.lastSessionId=m,this.sessionEventCounts={total:0,[u.CLICK]:0,[u.PAGE_VIEW]:0,[u.CUSTOM]:0,[u.VIEWPORT_VISIBLE]:0,[u.SCROLL]:0});const O=e===u.SESSION_START||e===u.SESSION_END;if(!O&&!this.checkRateLimit())return;const _=e;if(!O){if(this.sessionEventCounts.total>=1e3){a("warn","Session event limit reached",{data:{type:_,total:this.sessionEventCounts.total,limit:1e3}});return}const N=this.getTypeLimitForEvent(_);if(N){const Ee=this.sessionEventCounts[_];if(Ee!==void 0&&Ee>=N){a("warn","Session event type limit reached",{data:{type:_,count:Ee,limit:N}});return}}}if(_===u.CUSTOM&&o?.name){const N=this.get("config")?.maxSameEventPerMinute??60;if(!this.checkPerEventRateLimit(o.name,N))return}const cr=_===u.SESSION_START,ur=t||this.get("pageUrl"),he=this.buildEventPayload({type:_,page_url:ur,from_page_url:r,scroll_data:s,click_data:i,custom_event:o,web_vitals:l,error_data:c,session_end_reason:d,viewport_data:T});if(!(!O&&!this.shouldSample())){if(cr){const N=this.get("sessionId");if(!N){a("error","Session start event requires sessionId - event will be ignored");return}if(this.get("hasStartSession")){a("warn","Duplicate session_start detected",{data:{sessionId:N}});return}this.set("hasStartSession",!0)}if(!this.isDuplicateEvent(he)){if(this.get("mode")===b.QA&&_===u.CUSTOM&&o){console.log("[TraceLog] Event",{name:o.name,...o.metadata&&{metadata:o.metadata}}),this.emitEvent(he);return}this.addToQueue(he),O||(this.sessionEventCounts.total++,this.sessionEventCounts[_]!==void 0&&this.sessionEventCounts[_]++)}}}stop(){this.sendIntervalId&&(clearInterval(this.sendIntervalId),this.sendIntervalId=null),this.eventsQueue=[],this.pendingEventsBuffer=[],this.recentEventFingerprints.clear(),this.rateLimitCounter=0,this.rateLimitWindowStart=0,this.perEventRateLimits.clear(),this.sessionEventCounts={total:0,[u.CLICK]:0,[u.PAGE_VIEW]:0,[u.CUSTOM]:0,[u.VIEWPORT_VISIBLE]:0,[u.SCROLL]:0},this.lastSessionId=null,this.dataSender.stop()}async flushImmediately(){return this.flushEvents(!1)}flushImmediatelySync(){return this.flushEvents(!0)}getQueueLength(){return this.eventsQueue.length}flushPendingEvents(){if(this.pendingEventsBuffer.length===0)return;if(!this.get("sessionId")){a("warn","Cannot flush pending events: session not initialized - keeping in buffer",{data:{bufferedEventCount:this.pendingEventsBuffer.length}});return}const t=[...this.pendingEventsBuffer];this.pendingEventsBuffer=[],t.forEach(r=>{this.track(r)})}clearSendInterval(){this.sendIntervalId&&(clearInterval(this.sendIntervalId),this.sendIntervalId=null)}flushEvents(e){if(this.eventsQueue.length===0)return e?!0:Promise.resolve(!0);const t=this.buildEventsPayload(),r=[...this.eventsQueue],s=r.map(i=>i.id);if(e){const i=this.dataSender.sendEventsQueueSync(t);return i&&(this.removeProcessedEvents(s),this.clearSendInterval(),this.emitEventsQueue(t)),i}else return this.dataSender.sendEventsQueue(t,{onSuccess:()=>{this.removeProcessedEvents(s),this.clearSendInterval(),this.emitEventsQueue(t)},onFailure:()=>{a("warn","Async flush failed",{data:{eventCount:r.length}})}})}async sendEventsQueue(){if(!this.get("sessionId")||this.eventsQueue.length===0)return;const e=this.buildEventsPayload(),t=[...this.eventsQueue],r=t.map(s=>s.id);await this.dataSender.sendEventsQueue(e,{onSuccess:()=>{this.removeProcessedEvents(r),this.emitEventsQueue(e)},onFailure:()=>{a("warn","Events send failed, keeping in queue",{data:{eventCount:t.length}})}})}buildEventsPayload(){const e=new Map,t=[];for(const s of this.eventsQueue){const i=this.createEventSignature(s);e.has(i)||t.push(i),e.set(i,s)}const r=t.map(s=>e.get(s)).filter(s=>!!s).sort((s,i)=>s.timestamp-i.timestamp);return{user_id:this.get("userId"),session_id:this.get("sessionId"),device:this.get("device"),events:r,...this.get("config")?.globalMetadata&&{global_metadata:this.get("config")?.globalMetadata}}}buildEventPayload(e){const t=e.type===u.SESSION_START,r=e.page_url??this.get("pageUrl");return{id:ot(),type:e.type,page_url:r,timestamp:Date.now(),...t&&{referrer:document.referrer||"Direct"},...e.from_page_url&&{from_page_url:e.from_page_url},...e.scroll_data&&{scroll_data:e.scroll_data},...e.click_data&&{click_data:e.click_data},...e.custom_event&&{custom_event:e.custom_event},...e.web_vitals&&{web_vitals:e.web_vitals},...e.error_data&&{error_data:e.error_data},...e.session_end_reason&&{session_end_reason:e.session_end_reason},...e.viewport_data&&{viewport_data:e.viewport_data},...t&&Ae()&&{utm:Ae()}}}isDuplicateEvent(e){const t=Date.now(),r=this.createEventFingerprint(e),s=this.recentEventFingerprints.get(r);return s&&t-s<500?(this.recentEventFingerprints.set(r,t),!0):(this.recentEventFingerprints.set(r,t),this.recentEventFingerprints.size>1e3&&this.pruneOldFingerprints(),this.recentEventFingerprints.size>2e3&&(this.recentEventFingerprints.clear(),this.recentEventFingerprints.set(r,t),a("warn","Event fingerprint cache exceeded hard limit, cleared",{data:{hardLimit:2e3}})),!1)}pruneOldFingerprints(){const e=Date.now(),t=500*10;for(const[r,s]of this.recentEventFingerprints.entries())e-s>t&&this.recentEventFingerprints.delete(r);a("debug","Pruned old event fingerprints",{data:{remaining:this.recentEventFingerprints.size,cutoffMs:t}})}createEventFingerprint(e){let t=`${e.type}_${e.page_url}`;if(e.click_data){const r=Math.round((e.click_data.x||0)/10)*10,s=Math.round((e.click_data.y||0)/10)*10;t+=`_click_${r}_${s}`}return e.scroll_data&&(t+=`_scroll_${e.scroll_data.depth}_${e.scroll_data.direction}`),e.custom_event&&(t+=`_custom_${e.custom_event.name}`),e.web_vitals&&(t+=`_vitals_${e.web_vitals.type}`),e.error_data&&(t+=`_error_${e.error_data.type}_${e.error_data.message}`),t}createEventSignature(e){return this.createEventFingerprint(e)}addToQueue(e){if(this.eventsQueue.push(e),this.emitEvent(e),this.eventsQueue.length>100){const t=this.eventsQueue.findIndex(s=>s.type!==u.SESSION_START&&s.type!==u.SESSION_END),r=t>=0?this.eventsQueue.splice(t,1)[0]:this.eventsQueue.shift();a("warn","Event queue overflow, oldest non-critical event removed",{data:{maxLength:100,currentLength:this.eventsQueue.length,removedEventType:r?.type,wasCritical:r?.type===u.SESSION_START||r?.type===u.SESSION_END}})}this.sendIntervalId||this.startSendInterval(),this.eventsQueue.length>=50&&this.sendEventsQueue(),this.handleGoogleAnalyticsIntegration(e)}startSendInterval(){this.sendIntervalId=window.setInterval(()=>{this.eventsQueue.length>0&&this.sendEventsQueue()},1e4)}handleGoogleAnalyticsIntegration(e){if(this.googleAnalytics&&e.type===u.CUSTOM&&e.custom_event){if(this.get("mode")===b.QA)return;this.googleAnalytics.trackEvent(e.custom_event.name,e.custom_event.metadata??{})}}shouldSample(){const e=this.get("config")?.samplingRate??1;return Math.random()<e}checkRateLimit(){const e=Date.now();return e-this.rateLimitWindowStart>1e3&&(this.rateLimitCounter=0,this.rateLimitWindowStart=e),this.rateLimitCounter>=50?!1:(this.rateLimitCounter++,!0)}checkPerEventRateLimit(e,t){const r=Date.now(),i=(this.perEventRateLimits.get(e)??[]).filter(o=>r-o<6e4);return i.length>=t?(a("warn","Per-event rate limit exceeded for custom event",{data:{eventName:e,limit:t,window:`${6e4/1e3}s`}}),!1):(i.push(r),this.perEventRateLimits.set(e,i),!0)}getTypeLimitForEvent(e){return{[u.CLICK]:500,[u.PAGE_VIEW]:100,[u.CUSTOM]:500,[u.VIEWPORT_VISIBLE]:200,[u.SCROLL]:120}[e]??null}removeProcessedEvents(e){const t=new Set(e);this.eventsQueue=this.eventsQueue.filter(r=>!t.has(r.id))}emitEvent(e){this.emitter&&this.emitter.emit(G.EVENT,e)}emitEventsQueue(e){this.emitter&&this.emitter.emit(G.QUEUE,e)}}class It{static getId(e){const t=Qe,r=e.getItem(t);if(r)return r;const s=it();return e.setItem(t,s),s}}class pt extends S{storageManager;eventManager;projectId;sessionTimeoutId=null;broadcastChannel=null;activityHandler=null;visibilityChangeHandler=null;beforeUnloadHandler=null;isTracking=!1;constructor(e,t,r){super(),this.storageManager=e,this.eventManager=t,this.projectId=r}initCrossTabSync(){if(typeof BroadcastChannel>"u"){a("warn","BroadcastChannel not supported");return}const e=this.getProjectId();this.broadcastChannel=new BroadcastChannel(qe(e)),this.broadcastChannel.onmessage=t=>{const{action:r,sessionId:s,timestamp:i,projectId:o}=t.data??{};if(o===e){if(r==="session_end"){this.resetSessionState();return}s&&typeof i=="number"&&i>Date.now()-5e3&&(this.set("sessionId",s),this.set("hasStartSession",!0),this.persistSession(s,i),this.isTracking&&this.setupSessionTimeout())}}}shareSession(e){this.broadcastChannel&&typeof this.broadcastChannel.postMessage=="function"&&this.broadcastChannel.postMessage({action:"session_start",projectId:this.getProjectId(),sessionId:e,timestamp:Date.now()})}broadcastSessionEnd(e,t){if(e&&this.broadcastChannel&&typeof this.broadcastChannel.postMessage=="function")try{this.broadcastChannel.postMessage({action:"session_end",projectId:this.getProjectId(),sessionId:e,reason:t,timestamp:Date.now()})}catch(r){a("warn","Failed to broadcast session end",{error:r,data:{sessionId:e,reason:t}})}}cleanupCrossTabSync(){this.broadcastChannel&&(typeof this.broadcastChannel.close=="function"&&this.broadcastChannel.close(),this.broadcastChannel=null)}recoverSession(){const e=this.loadStoredSession();if(!e)return null;const t=this.get("config")?.sessionTimeout??9e5;return Date.now()-e.lastActivity>t?(this.clearStoredSession(),null):e.id}persistSession(e,t=Date.now()){this.saveStoredSession({id:e,lastActivity:t})}clearStoredSession(){const e=this.getSessionStorageKey();this.storageManager.removeItem(e)}loadStoredSession(){const e=this.getSessionStorageKey(),t=this.storageManager.getItem(e);if(!t)return null;try{const r=JSON.parse(t);return!r.id||typeof r.lastActivity!="number"?null:r}catch{return this.storageManager.removeItem(e),null}}saveStoredSession(e){const t=this.getSessionStorageKey();this.storageManager.setItem(t,JSON.stringify(e))}getSessionStorageKey(){return Ke(this.getProjectId())}getProjectId(){return this.projectId}startTracking(){if(this.isTracking){a("warn","Session tracking already active");return}const e=this.recoverSession(),t=e??this.generateSessionId(),r=!!e;this.isTracking=!0;try{this.set("sessionId",t),this.persistSession(t),r||this.eventManager.track({type:u.SESSION_START}),this.initCrossTabSync(),this.shareSession(t),this.setupSessionTimeout(),this.setupActivityListeners(),this.setupLifecycleListeners()}catch(s){throw this.isTracking=!1,this.clearSessionTimeout(),this.cleanupActivityListeners(),this.cleanupLifecycleListeners(),this.cleanupCrossTabSync(),this.set("sessionId",null),s}}generateSessionId(){return`${Date.now()}-${Math.random().toString(36).substring(2,11)}`}setupSessionTimeout(){this.clearSessionTimeout();const e=this.get("config")?.sessionTimeout??9e5;this.sessionTimeoutId=setTimeout(()=>{this.endSession("inactivity")},e)}resetSessionTimeout(){this.setupSessionTimeout();const e=this.get("sessionId");e&&this.persistSession(e)}clearSessionTimeout(){this.sessionTimeoutId&&(clearTimeout(this.sessionTimeoutId),this.sessionTimeoutId=null)}setupActivityListeners(){this.activityHandler=()=>{this.resetSessionTimeout()},document.addEventListener("click",this.activityHandler,{passive:!0}),document.addEventListener("keydown",this.activityHandler,{passive:!0}),document.addEventListener("scroll",this.activityHandler,{passive:!0})}cleanupActivityListeners(){this.activityHandler&&(document.removeEventListener("click",this.activityHandler),document.removeEventListener("keydown",this.activityHandler),document.removeEventListener("scroll",this.activityHandler),this.activityHandler=null)}setupLifecycleListeners(){this.visibilityChangeHandler||this.beforeUnloadHandler||(this.visibilityChangeHandler=()=>{document.hidden?this.clearSessionTimeout():this.get("sessionId")&&this.setupSessionTimeout()},this.beforeUnloadHandler=()=>{this.endSession("page_unload")},document.addEventListener("visibilitychange",this.visibilityChangeHandler),window.addEventListener("beforeunload",this.beforeUnloadHandler))}cleanupLifecycleListeners(){this.visibilityChangeHandler&&(document.removeEventListener("visibilitychange",this.visibilityChangeHandler),this.visibilityChangeHandler=null),this.beforeUnloadHandler&&(window.removeEventListener("beforeunload",this.beforeUnloadHandler),this.beforeUnloadHandler=null)}endSession(e){const t=this.get("sessionId");if(!t){a("warn","endSession called without active session",{data:{reason:e}}),this.resetSessionState(e);return}this.eventManager.track({type:u.SESSION_END,session_end_reason:e}),this.eventManager.flushImmediatelySync()||a("warn","Sync flush failed during session end, events persisted for recovery",{data:{reason:e,sessionId:t}}),this.broadcastSessionEnd(t,e),this.resetSessionState(e)}resetSessionState(e){this.clearSessionTimeout(),this.cleanupActivityListeners(),this.cleanupLifecycleListeners(),this.cleanupCrossTabSync(),e!=="page_unload"&&this.clearStoredSession(),this.set("sessionId",null),this.set("hasStartSession",!1),this.isTracking=!1}stopTracking(){this.endSession("manual_stop")}destroy(){this.clearSessionTimeout(),this.cleanupActivityListeners(),this.cleanupCrossTabSync(),this.cleanupLifecycleListeners(),this.isTracking=!1,this.set("hasStartSession",!1)}}class vt extends S{eventManager;storageManager;sessionManager=null;destroyed=!1;constructor(e,t){super(),this.eventManager=t,this.storageManager=e}startTracking(){if(this.isActive())return;if(this.destroyed){a("warn","Cannot start tracking on destroyed handler");return}const e=this.get("config"),t=e?.integrations?.tracelog?.projectId??e?.integrations?.custom?.collectApiUrl??"default";if(!t)throw new Error("Cannot start session tracking: config not available");try{this.sessionManager=new pt(this.storageManager,this.eventManager,t),this.sessionManager.startTracking(),this.eventManager.flushPendingEvents()}catch(r){if(this.sessionManager){try{this.sessionManager.destroy()}catch{}this.sessionManager=null}throw a("error","Failed to start session tracking",{error:r}),r}}isActive(){return this.sessionManager!==null&&!this.destroyed}cleanupSessionManager(){this.sessionManager&&(this.sessionManager.stopTracking(),this.sessionManager.destroy(),this.sessionManager=null)}stopTracking(){this.cleanupSessionManager()}destroy(){this.destroyed||(this.sessionManager&&(this.sessionManager.destroy(),this.sessionManager=null),this.destroyed=!0,this.set("hasStartSession",!1))}}class At extends S{eventManager;onTrack;originalPushState;originalReplaceState;lastPageViewTime=0;constructor(e,t){super(),this.eventManager=e,this.onTrack=t}startTracking(){this.trackInitialPageView(),window.addEventListener("popstate",this.trackCurrentPage,!0),window.addEventListener("hashchange",this.trackCurrentPage,!0),this.patchHistory("pushState"),this.patchHistory("replaceState")}stopTracking(){window.removeEventListener("popstate",this.trackCurrentPage,!0),window.removeEventListener("hashchange",this.trackCurrentPage,!0),this.originalPushState&&(window.history.pushState=this.originalPushState),this.originalReplaceState&&(window.history.replaceState=this.originalReplaceState),this.lastPageViewTime=0}patchHistory(e){const t=window.history[e];e==="pushState"&&!this.originalPushState?this.originalPushState=t:e==="replaceState"&&!this.originalReplaceState&&(this.originalReplaceState=t),window.history[e]=(...r)=>{t.apply(window.history,r),this.trackCurrentPage()}}trackCurrentPage=()=>{const e=window.location.href,t=Z(e,this.get("config").sensitiveQueryParams);if(this.get("pageUrl")===t)return;const r=Date.now(),s=this.get("config").pageViewThrottleMs??1e3;if(r-this.lastPageViewTime<s)return;this.lastPageViewTime=r,this.onTrack();const i=this.get("pageUrl");this.set("pageUrl",t);const o=this.extractPageViewData();this.eventManager.track({type:u.PAGE_VIEW,page_url:this.get("pageUrl"),from_page_url:i,...o&&{page_view:o}})};trackInitialPageView(){const e=Z(window.location.href,this.get("config").sensitiveQueryParams),t=this.extractPageViewData();this.lastPageViewTime=Date.now(),this.eventManager.track({type:u.PAGE_VIEW,page_url:e,...t&&{page_view:t}}),this.onTrack()}extractPageViewData(){const{pathname:e,search:t,hash:r}=window.location,{referrer:s}=document,{title:i}=document;return!s&&!i&&!e&&!t&&!r?void 0:{...s&&{referrer:s},...i&&{title:i},...e&&{pathname:e},...t&&{search:t},...r&&{hash:r}}}}class wt extends S{eventManager;clickHandler;lastClickTimes=new Map;constructor(e){super(),this.eventManager=e}startTracking(){this.clickHandler||(this.clickHandler=e=>{const t=e,r=t.target,s=typeof HTMLElement<"u"&&r instanceof HTMLElement?r:typeof HTMLElement<"u"&&r instanceof Node&&r.parentElement instanceof HTMLElement?r.parentElement:null;if(!s){a("warn","Click target not found or not an element");return}if(this.shouldIgnoreElement(s))return;const i=this.get("config")?.clickThrottleMs??300;if(i>0&&!this.checkClickThrottle(s,i))return;const o=this.findTrackingElement(s),l=this.getRelevantClickElement(s),c=this.calculateClickCoordinates(t,s);if(o){const T=this.extractTrackingData(o);if(T){const m=this.createCustomEventData(T);this.eventManager.track({type:u.CUSTOM,custom_event:{name:m.name,...m.value&&{metadata:{value:m.value}}}})}}const d=this.generateClickData(s,l,c);this.eventManager.track({type:u.CLICK,click_data:d})},window.addEventListener("click",this.clickHandler,!0))}stopTracking(){this.clickHandler&&(window.removeEventListener("click",this.clickHandler,!0),this.clickHandler=void 0),this.lastClickTimes.clear()}shouldIgnoreElement(e){return e.hasAttribute(`${A}-ignore`)?!0:e.closest(`[${A}-ignore]`)!==null}checkClickThrottle(e,t){const r=this.getElementSignature(e),s=Date.now(),i=this.lastClickTimes.get(r);return i!==void 0&&s-i<t?(a("debug","ClickHandler: Click suppressed by throttle",{data:{signature:r,throttleRemaining:t-(s-i)}}),!1):(this.lastClickTimes.set(r,s),!0)}getElementSignature(e){if(e.id)return`#${e.id}`;const t=e.getAttribute("data-testid");if(t)return`[data-testid="${t}"]`;const r=e.getAttribute(`${A}-name`);return r?`[${A}-name="${r}"]`:this.getElementPath(e)}getElementPath(e){const t=[];let r=e;for(;r&&r!==document.body;){let s=r.tagName.toLowerCase();if(r.className){const i=r.className.split(" ")[0];i&&(s+=`.${i}`)}t.unshift(s),r=r.parentElement}return t.join(">")||"unknown"}findTrackingElement(e){return e.hasAttribute(`${A}-name`)?e:e.closest(`[${A}-name]`)}getRelevantClickElement(e){for(const t of Ue)try{if(e.matches(t))return e;const r=e.closest(t);if(r)return r}catch(r){a("warn","Invalid selector in element search",{error:r,data:{selector:t}});continue}return e}clamp(e){return Math.max(0,Math.min(1,Number(e.toFixed(3))))}calculateClickCoordinates(e,t){const r=t.getBoundingClientRect(),s=e.clientX,i=e.clientY,o=r.width>0?this.clamp((s-r.left)/r.width):0,l=r.height>0?this.clamp((i-r.top)/r.height):0;return{x:s,y:i,relativeX:o,relativeY:l}}extractTrackingData(e){const t=e.getAttribute(`${A}-name`),r=e.getAttribute(`${A}-value`);if(t)return{element:e,name:t,...r&&{value:r}}}generateClickData(e,t,r){const{x:s,y:i,relativeX:o,relativeY:l}=r,c=this.getRelevantText(e,t),d=this.extractElementAttributes(t);return{x:s,y:i,relativeX:o,relativeY:l,tag:t.tagName.toLowerCase(),...t.id&&{id:t.id},...t.className&&{class:t.className},...c&&{text:c},...d.href&&{href:d.href},...d.title&&{title:d.title},...d.alt&&{alt:d.alt},...d.role&&{role:d.role},...d["aria-label"]&&{ariaLabel:d["aria-label"]},...Object.keys(d).length>0&&{dataAttributes:d}}}sanitizeText(e){let t=e;for(const r of q){const s=new RegExp(r.source,r.flags);t=t.replace(s,"[REDACTED]")}return t}getRelevantText(e,t){const r=e.textContent?.trim()??"",s=t.textContent?.trim()??"";if(!r&&!s)return"";let i="";return r&&r.length<=255?i=r:s.length<=255?i=s:i=s.slice(0,252)+"...",this.sanitizeText(i)}extractElementAttributes(e){const t=["id","class","data-testid","aria-label","title","href","type","name","alt","role"],r={};for(const s of t){const i=e.getAttribute(s);i&&(r[s]=i)}return r}createCustomEventData(e){return{name:e.name,...e.value&&{value:e.value}}}}class yt extends S{eventManager;containers=[];limitWarningLogged=!1;minDepthChange=5;minIntervalMs=500;maxEventsPerSession=120;windowScrollableCache=null;retryTimeoutId=null;constructor(e){super(),this.eventManager=e}startTracking(){this.limitWarningLogged=!1,this.applyConfigOverrides(),this.set("scrollEventCount",0),this.tryDetectScrollContainers(0)}stopTracking(){this.retryTimeoutId!==null&&(clearTimeout(this.retryTimeoutId),this.retryTimeoutId=null);for(const e of this.containers)this.clearContainerTimer(e),e.element instanceof Window?window.removeEventListener("scroll",e.listener):e.element.removeEventListener("scroll",e.listener);this.containers.length=0,this.set("scrollEventCount",0),this.limitWarningLogged=!1,this.windowScrollableCache=null}tryDetectScrollContainers(e){const t=this.findScrollableElements();if(t.length>0){for(const r of t){const s=this.getElementSelector(r);this.setupScrollContainer(r,s)}this.applyPrimaryScrollSelectorIfConfigured();return}if(e<5){this.retryTimeoutId=window.setTimeout(()=>{this.retryTimeoutId=null,this.tryDetectScrollContainers(e+1)},200);return}this.containers.length===0&&this.setupScrollContainer(window,"window"),this.applyPrimaryScrollSelectorIfConfigured()}applyPrimaryScrollSelectorIfConfigured(){const e=this.get("config");e?.primaryScrollSelector&&this.applyPrimaryScrollSelector(e.primaryScrollSelector)}findScrollableElements(){if(!document.body)return[];const e=[],t=document.createTreeWalker(document.body,NodeFilter.SHOW_ELEMENT,{acceptNode:s=>{const i=s;if(!i.isConnected||!i.offsetParent)return NodeFilter.FILTER_SKIP;const o=getComputedStyle(i);return o.overflowY==="auto"||o.overflowY==="scroll"||o.overflow==="auto"||o.overflow==="scroll"?NodeFilter.FILTER_ACCEPT:NodeFilter.FILTER_SKIP}});let r;for(;(r=t.nextNode())&&e.length<10;){const s=r;this.isElementScrollable(s)&&e.push(s)}return e}getElementSelector(e){if(e===window)return"window";const t=e;if(t.id)return`#${t.id}`;if(t.className&&typeof t.className=="string"){const r=t.className.split(" ").filter(s=>s.trim())[0];if(r)return`.${r}`}return t.tagName.toLowerCase()}determineIfPrimary(e){return this.isWindowScrollable()?e===window:this.containers.length===0}setupScrollContainer(e,t){if(this.containers.some(d=>d.element===e)||e!==window&&!this.isElementScrollable(e))return;const s=()=>{this.get("suppressNextScroll")||(this.clearContainerTimer(c),c.debounceTimer=window.setTimeout(()=>{const d=this.calculateScrollData(c);if(d){const T=Date.now();this.processScrollEvent(c,d,T)}c.debounceTimer=null},250))},i=this.getScrollTop(e),o=this.calculateScrollDepth(i,this.getScrollHeight(e),this.getViewportHeight(e)),l=this.determineIfPrimary(e),c={element:e,selector:t,isPrimary:l,lastScrollPos:i,lastDepth:o,lastDirection:U.DOWN,lastEventTime:0,maxDepthReached:o,debounceTimer:null,listener:s};this.containers.push(c),e instanceof Window?window.addEventListener("scroll",s,{passive:!0}):e.addEventListener("scroll",s,{passive:!0})}processScrollEvent(e,t,r){if(!this.shouldEmitScrollEvent(e,t,r))return;e.lastEventTime=r,e.lastDepth=t.depth,e.lastDirection=t.direction;const s=this.get("scrollEventCount")??0;this.set("scrollEventCount",s+1),this.eventManager.track({type:u.SCROLL,scroll_data:{...t,container_selector:e.selector,is_primary:e.isPrimary}})}shouldEmitScrollEvent(e,t,r){return this.hasReachedSessionLimit()?(this.logLimitOnce(),!1):!(!this.hasElapsedMinimumInterval(e,r)||!this.hasSignificantDepthChange(e,t.depth))}hasReachedSessionLimit(){return(this.get("scrollEventCount")??0)>=this.maxEventsPerSession}hasElapsedMinimumInterval(e,t){return e.lastEventTime===0?!0:t-e.lastEventTime>=this.minIntervalMs}hasSignificantDepthChange(e,t){return Math.abs(t-e.lastDepth)>=this.minDepthChange}logLimitOnce(){this.limitWarningLogged||(this.limitWarningLogged=!0,a("warn","Max scroll events per session reached",{data:{limit:this.maxEventsPerSession}}))}applyConfigOverrides(){this.minDepthChange=5,this.minIntervalMs=500,this.maxEventsPerSession=120}isWindowScrollable(){return this.windowScrollableCache!==null?this.windowScrollableCache:(this.windowScrollableCache=document.documentElement.scrollHeight>window.innerHeight,this.windowScrollableCache)}clearContainerTimer(e){e.debounceTimer!==null&&(clearTimeout(e.debounceTimer),e.debounceTimer=null)}getScrollDirection(e,t){return e>t?U.DOWN:U.UP}calculateScrollDepth(e,t,r){if(t<=r)return 0;const s=t-r;return Math.min(100,Math.max(0,Math.floor(e/s*100)))}calculateScrollData(e){const{element:t,lastScrollPos:r,lastEventTime:s}=e,i=this.getScrollTop(t),o=Date.now(),l=Math.abs(i-r);if(l<10||t===window&&!this.isWindowScrollable())return null;const c=this.getViewportHeight(t),d=this.getScrollHeight(t),T=this.getScrollDirection(i,r),m=this.calculateScrollDepth(i,d,c),O=s>0?o-s:0,_=O>0?Math.round(l/O*1e3):0;return m>e.maxDepthReached&&(e.maxDepthReached=m),e.lastScrollPos=i,{depth:m,direction:T,velocity:_,max_depth_reached:e.maxDepthReached}}getScrollTop(e){return e instanceof Window?window.scrollY:e.scrollTop}getViewportHeight(e){return e instanceof Window?window.innerHeight:e.clientHeight}getScrollHeight(e){return e instanceof Window?document.documentElement.scrollHeight:e.scrollHeight}isElementScrollable(e){const t=getComputedStyle(e),r=t.overflowY==="auto"||t.overflowY==="scroll"||t.overflowX==="auto"||t.overflowX==="scroll"||t.overflow==="auto"||t.overflow==="scroll",s=e.scrollHeight>e.clientHeight||e.scrollWidth>e.clientWidth;return r&&s}applyPrimaryScrollSelector(e){let t;if(e==="window")t=window;else{const s=document.querySelector(e);if(!(s instanceof HTMLElement)){a("warn",`Selector "${e}" did not match an HTMLElement`);return}t=s}this.containers.forEach(s=>{this.updateContainerPrimary(s,s.element===t)}),!this.containers.some(s=>s.element===t)&&t instanceof HTMLElement&&this.isElementScrollable(t)&&this.setupScrollContainer(t,e)}updateContainerPrimary(e,t){e.isPrimary=t}}class Mt extends S{eventManager;trackedElements=new Map;observer=null;mutationObserver=null;mutationDebounceTimer=null;config=null;constructor(e){super(),this.eventManager=e}startTracking(){const e=this.get("config");if(this.config=e.viewport??null,!this.config?.elements||this.config.elements.length===0)return;const t=this.config.threshold??.5,r=this.config.minDwellTime??1e3;if(t<0||t>1){a("warn","ViewportHandler: Invalid threshold, must be between 0 and 1");return}if(r<0){a("warn","ViewportHandler: Invalid minDwellTime, must be non-negative");return}if(typeof IntersectionObserver>"u"){a("warn","ViewportHandler: IntersectionObserver not supported in this browser");return}this.observer=new IntersectionObserver(this.handleIntersection,{threshold:t}),this.observeElements(),this.setupMutationObserver()}stopTracking(){this.observer&&(this.observer.disconnect(),this.observer=null),this.mutationObserver&&(this.mutationObserver.disconnect(),this.mutationObserver=null),this.mutationDebounceTimer!==null&&(window.clearTimeout(this.mutationDebounceTimer),this.mutationDebounceTimer=null);for(const e of this.trackedElements.values())e.timeoutId!==null&&window.clearTimeout(e.timeoutId);this.trackedElements.clear()}observeElements(){if(!this.config||!this.observer)return;const e=this.config.maxTrackedElements??100;let t=this.trackedElements.size;for(const r of this.config.elements)try{const s=document.querySelectorAll(r.selector);for(const i of Array.from(s)){if(t>=e){a("warn","ViewportHandler: Maximum tracked elements reached",{data:{limit:e,selector:r.selector,message:"Some elements will not be tracked. Consider more specific selectors."}});return}i.hasAttribute(`${A}-ignore`)||this.trackedElements.has(i)||(this.trackedElements.set(i,{element:i,selector:r.selector,id:r.id,name:r.name,startTime:null,timeoutId:null,lastFiredTime:null}),this.observer?.observe(i),t++)}}catch(s){a("warn",`ViewportHandler: Invalid selector "${r.selector}"`,{error:s})}a("debug","ViewportHandler: Elements tracked",{data:{count:t,limit:e}})}handleIntersection=e=>{if(!this.config)return;const t=this.config.minDwellTime??1e3;for(const r of e){const s=this.trackedElements.get(r.target);s&&(r.isIntersecting?s.startTime===null&&(s.startTime=performance.now(),s.timeoutId=window.setTimeout(()=>{this.fireViewportEvent(s,r.intersectionRatio)},t)):s.startTime!==null&&(s.timeoutId!==null&&(window.clearTimeout(s.timeoutId),s.timeoutId=null),s.startTime=null))}};fireViewportEvent(e,t){if(e.startTime===null)return;const r=Math.round(performance.now()-e.startTime);if(e.element.hasAttribute("data-tlog-ignore"))return;const s=this.config?.cooldownPeriod??6e4,i=Date.now();if(e.lastFiredTime!==null&&i-e.lastFiredTime<s){a("debug","ViewportHandler: Event suppressed by cooldown period",{data:{selector:e.selector,cooldownRemaining:s-(i-e.lastFiredTime)}}),e.startTime=null,e.timeoutId=null;return}const o={selector:e.selector,dwellTime:r,visibilityRatio:t,...e.id!==void 0&&{id:e.id},...e.name!==void 0&&{name:e.name}};this.eventManager.track({type:u.VIEWPORT_VISIBLE,viewport_data:o}),e.startTime=null,e.timeoutId=null,e.lastFiredTime=i}setupMutationObserver(){if(!(!this.config||typeof MutationObserver>"u")){if(!document.body){a("warn","ViewportHandler: document.body not available, skipping MutationObserver setup");return}this.mutationObserver=new MutationObserver(e=>{let t=!1;for(const r of e)r.type==="childList"&&(r.addedNodes.length>0&&(t=!0),r.removedNodes.length>0&&this.cleanupRemovedNodes(r.removedNodes));t&&(this.mutationDebounceTimer!==null&&window.clearTimeout(this.mutationDebounceTimer),this.mutationDebounceTimer=window.setTimeout(()=>{this.observeElements(),this.mutationDebounceTimer=null},100))}),this.mutationObserver.observe(document.body,{childList:!0,subtree:!0})}}cleanupRemovedNodes(e){e.forEach(t=>{if(t.nodeType!==1)return;const r=t,s=this.trackedElements.get(r);s&&(s.timeoutId!==null&&window.clearTimeout(s.timeoutId),this.observer?.unobserve(r),this.trackedElements.delete(r)),Array.from(this.trackedElements.keys()).filter(o=>r.contains(o)).forEach(o=>{const l=this.trackedElements.get(o);l&&l.timeoutId!==null&&window.clearTimeout(l.timeoutId),this.observer?.unobserve(o),this.trackedElements.delete(o)})})}}class Nt extends S{isInitialized=!1;async initialize(){if(this.isInitialized)return;const e=this.get("config").integrations?.googleAnalytics?.measurementId,t=this.get("userId");if(!(!e?.trim()||!t?.trim()))try{if(this.isScriptAlreadyLoaded()){this.isInitialized=!0;return}await this.loadScript(e),this.configureGtag(e,t),this.isInitialized=!0}catch(r){a("error","Google Analytics initialization failed",{error:r})}}trackEvent(e,t){if(!(!e?.trim()||!this.isInitialized||typeof window.gtag!="function"))try{const r=Array.isArray(t)?{items:t}:t;window.gtag("event",e,r)}catch(r){a("error","Google Analytics event tracking failed",{error:r})}}cleanup(){this.isInitialized=!1;const e=document.getElementById("tracelog-ga-script");e&&e.remove()}isScriptAlreadyLoaded(){return document.getElementById("tracelog-ga-script")?!0:!!document.querySelector('script[src*="googletagmanager.com/gtag/js"]')}async loadScript(e){return new Promise((t,r)=>{const s=document.createElement("script");s.id="tracelog-ga-script",s.async=!0,s.src=`https://www.googletagmanager.com/gtag/js?id=${e}`,s.onload=()=>{t()},s.onerror=()=>{r(new Error("Failed to load Google Analytics script"))},document.head.appendChild(s)})}configureGtag(e,t){const r=document.createElement("script");r.innerHTML=`
|
|
2
2
|
window.dataLayer = window.dataLayer || [];
|
|
3
3
|
function gtag(){dataLayer.push(arguments);}
|
|
4
4
|
gtag('js', new Date());
|
|
5
5
|
gtag('config', '${e}', {
|
|
6
6
|
'user_id': '${t}'
|
|
7
7
|
});
|
|
8
|
-
`,document.head.appendChild(r)}}class Lt{storage;sessionStorageRef;fallbackStorage=new Map;fallbackSessionStorage=new Map;hasQuotaExceededError=!1;constructor(){this.storage=this.initializeStorage("localStorage"),this.sessionStorageRef=this.initializeStorage("sessionStorage"),this.storage||a("warn","localStorage not available, using memory fallback"),this.sessionStorageRef||a("warn","sessionStorage not available, using memory fallback")}getItem(e){try{return this.storage?this.storage.getItem(e):this.fallbackStorage.get(e)??null}catch{return this.fallbackStorage.get(e)??null}}setItem(e,t){this.fallbackStorage.set(e,t);try{if(this.storage){this.storage.setItem(e,t);return}}catch(r){if(r instanceof DOMException&&r.name==="QuotaExceededError")if(this.hasQuotaExceededError=!0,a("warn","localStorage quota exceeded, attempting cleanup",{data:{key:e,valueSize:t.length}}),this.cleanupOldData())try{if(this.storage){this.storage.setItem(e,t);return}}catch(i){a("error","localStorage quota exceeded even after cleanup - data will not persist",{error:i,data:{key:e,valueSize:t.length}})}else a("error","localStorage quota exceeded and no data to cleanup - data will not persist",{error:r,data:{key:e,valueSize:t.length}})}}removeItem(e){try{this.storage&&this.storage.removeItem(e)}catch{}this.fallbackStorage.delete(e)}clear(){if(!this.storage){this.fallbackStorage.clear();return}try{const e=[];for(let t=0;t<this.storage.length;t++){const r=this.storage.key(t);r?.startsWith("tracelog_")&&e.push(r)}e.forEach(t=>{this.storage.removeItem(t)}),this.fallbackStorage.clear()}catch(e){a("error","Failed to clear storage",{error:e}),this.fallbackStorage.clear()}}isAvailable(){return this.storage!==null}hasQuotaError(){return this.hasQuotaExceededError}cleanupOldData(){if(!this.storage)return!1;try{const e=[],t=[];for(let i=0;i<this.storage.length;i++){const o=this.storage.key(i);o?.startsWith("tracelog_")&&(e.push(o),o.startsWith("tracelog_persisted_events_")&&t.push(o))}if(t.length>0)return t.forEach(i=>{try{this.storage.removeItem(i)}catch{}}),!0;const r=["tracelog_session_","tracelog_user_id","tracelog_device_id","tracelog_config"],s=e.filter(i=>!r.some(o=>i.startsWith(o)));return s.length>0?(s.slice(0,5).forEach(o=>{try{this.storage.removeItem(o)}catch{}}),!0):!1}catch(e){return a("error","Failed to cleanup old data",{error:e}),!1}}initializeStorage(e){if(typeof window>"u")return null;try{const t=e==="localStorage"?window.localStorage:window.sessionStorage,r="__tracelog_test__";return t.setItem(r,"test"),t.removeItem(r),t}catch{return null}}getSessionItem(e){try{return this.sessionStorageRef?this.sessionStorageRef.getItem(e):this.fallbackSessionStorage.get(e)??null}catch{return this.fallbackSessionStorage.get(e)??null}}setSessionItem(e,t){this.fallbackSessionStorage.set(e,t);try{if(this.sessionStorageRef){this.sessionStorageRef.setItem(e,t);return}}catch(r){r instanceof DOMException&&r.name==="QuotaExceededError"&&a("error","sessionStorage quota exceeded - data will not persist",{error:r,data:{key:e,valueSize:t.length}})}}removeSessionItem(e){try{this.sessionStorageRef&&this.sessionStorageRef.removeItem(e)}catch{}this.fallbackSessionStorage.delete(e)}}class Rt extends S{eventManager;reportedByNav=new Map;observers=[];lastLongTaskSentAt=0;vitalThresholds=Se;constructor(e){super(),this.eventManager=e}async startTracking(){await this.initWebVitals(),this.observeLongTasks()}stopTracking(){this.observers.forEach((e,t)=>{try{e.disconnect()}catch(r){a("warn","Failed to disconnect performance observer",{error:r,data:{observerIndex:t}})}}),this.observers.length=0,this.reportedByNav.clear()}observeWebVitalsFallback(){this.reportTTFB(),this.safeObserve("largest-contentful-paint",r=>{const s=r.getEntries(),i=s[s.length-1];i&&this.sendVital({type:"LCP",value:Number(i.startTime.toFixed(2))})},{type:"largest-contentful-paint",buffered:!0},!0);let e=0,t=this.getNavigationId();this.safeObserve("layout-shift",r=>{const s=this.getNavigationId();s!==t&&(e=0,t=s);const i=r.getEntries();for(const o of i){if(o.hadRecentInput===!0)continue;const l=typeof o.value=="number"?o.value:0;e+=l}this.sendVital({type:"CLS",value:Number(e.toFixed(2))})},{type:"layout-shift",buffered:!0}),this.safeObserve("paint",r=>{for(const s of r.getEntries())s.name==="first-contentful-paint"&&this.sendVital({type:"FCP",value:Number(s.startTime.toFixed(2))})},{type:"paint",buffered:!0},!0),this.safeObserve("event",r=>{let s=0;const i=r.getEntries();for(const o of i){const l=(o.processingEnd??0)-(o.startTime??0);s=Math.max(s,l)}s>0&&this.sendVital({type:"INP",value:Number(s.toFixed(2))})},{type:"event",buffered:!0})}async initWebVitals(){try{const{onLCP:e,onCLS:t,onFCP:r,onTTFB:s,onINP:i}=await Promise.resolve().then(()=>lr),o=l=>c=>{const d=Number(c.value.toFixed(2));this.sendVital({type:l,value:d})};e(o("LCP"),{reportAllChanges:!1}),t(o("CLS"),{reportAllChanges:!1}),r(o("FCP"),{reportAllChanges:!1}),s(o("TTFB"),{reportAllChanges:!1}),i(o("INP"),{reportAllChanges:!1})}catch(e){a("warn","Failed to load web-vitals library, using fallback",{error:e}),this.observeWebVitalsFallback()}}reportTTFB(){try{const e=performance.getEntriesByType("navigation")[0];if(!e)return;const t=e.responseStart;typeof t=="number"&&Number.isFinite(t)&&this.sendVital({type:"TTFB",value:Number(t.toFixed(2))})}catch(e){a("warn","Failed to report TTFB",{error:e})}}observeLongTasks(){this.safeObserve("longtask",e=>{const t=e.getEntries();for(const r of t){const s=Number(r.duration.toFixed(2)),i=Date.now();i-this.lastLongTaskSentAt>=Ze&&(this.shouldSendVital("LONG_TASK",s)&&this.trackWebVital("LONG_TASK",s),this.lastLongTaskSentAt=i)}},{type:"longtask",buffered:!0})}sendVital(e){if(!this.shouldSendVital(e.type,e.value))return;const t=this.getNavigationId();if(t){const r=this.reportedByNav.get(t);if(r?.has(e.type))return;r?r.add(e.type):this.reportedByNav.set(t,new Set([e.type]))}this.trackWebVital(e.type,e.value)}trackWebVital(e,t){if(!Number.isFinite(t)){a("warn","Invalid web vital value",{data:{type:e,value:t}});return}this.eventManager.track({type:u.WEB_VITALS,web_vitals:{type:e,value:t}})}getNavigationId(){try{const e=performance.getEntriesByType("navigation")[0];if(!e)return null;const t=e.startTime||performance.now(),r=Math.random().toString(36).substr(2,5);return`${t.toFixed(2)}_${window.location.pathname}_${r}`}catch(e){return a("warn","Failed to get navigation ID",{error:e}),null}}isObserverSupported(e){if(typeof PerformanceObserver>"u")return!1;const t=PerformanceObserver.supportedEntryTypes;return!t||t.includes(e)}safeObserve(e,t,r,s=!1){try{if(!this.isObserverSupported(e))return!1;const i=new PerformanceObserver((o,l)=>{try{t(o,l)}catch(c){a("warn","Observer callback failed",{error:c,data:{type:e}})}if(s)try{l.disconnect()}catch{}});return i.observe(r??{type:e,buffered:!0}),s||this.observers.push(i),!0}catch(i){return a("warn","Failed to create performance observer",{error:i,data:{type:e}}),!1}}shouldSendVital(e,t){if(typeof t!="number"||!Number.isFinite(t))return a("warn","Invalid web vital value",{data:{type:e,value:t}}),!1;const r=this.vitalThresholds[e];return!(typeof r=="number"&&t<=r)}}class Ot extends S{eventManager;recentErrors=new Map;errorBurstCounter=0;burstWindowStart=0;burstBackoffUntil=0;constructor(e){super(),this.eventManager=e}startTracking(){window.addEventListener("error",this.handleError),window.addEventListener("unhandledrejection",this.handleRejection)}stopTracking(){window.removeEventListener("error",this.handleError),window.removeEventListener("unhandledrejection",this.handleRejection),this.recentErrors.clear(),this.errorBurstCounter=0,this.burstWindowStart=0,this.burstBackoffUntil=0}shouldSample(){const e=Date.now();if(e<this.burstBackoffUntil)return!1;if(e-this.burstWindowStart>et&&(this.errorBurstCounter=0,this.burstWindowStart=e),this.errorBurstCounter++,this.errorBurstCounter>tt)return this.burstBackoffUntil=e+pe,a("warn","Error burst detected - entering cooldown",{data:{errorsInWindow:this.errorBurstCounter,cooldownMs:pe}}),!1;const r=this.get("config")?.errorSampling??Ie;return Math.random()<r}handleError=e=>{if(!this.shouldSample())return;const t=this.sanitize(e.message||"Unknown error");this.shouldSuppressError(C.JS_ERROR,t)||this.eventManager.track({type:u.ERROR,error_data:{type:C.JS_ERROR,message:t,...e.filename&&{filename:e.filename},...e.lineno&&{line:e.lineno},...e.colno&&{column:e.colno}}})};handleRejection=e=>{if(!this.shouldSample())return;const t=this.extractRejectionMessage(e.reason),r=this.sanitize(t);this.shouldSuppressError(C.PROMISE_REJECTION,r)||this.eventManager.track({type:u.ERROR,error_data:{type:C.PROMISE_REJECTION,message:r}})};extractRejectionMessage(e){if(!e)return"Unknown rejection";if(typeof e=="string")return e;if(e instanceof Error)return e.stack??e.message??e.toString();if(typeof e=="object"&&"message"in e)return String(e.message);try{return JSON.stringify(e)}catch{return String(e)}}sanitize(e){let t=e.length>_e?e.slice(0,_e)+"...":e;for(const r of q){const s=new RegExp(r.source,r.flags);t=t.replace(s,"[REDACTED]")}return t}shouldSuppressError(e,t){const r=Date.now(),s=`${e}:${t}`,i=this.recentErrors.get(s);return i&&r-i<Te?(this.recentErrors.set(s,r),!0):(this.recentErrors.set(s,r),this.recentErrors.size>Je?(this.recentErrors.clear(),this.recentErrors.set(s,r),!1):(this.recentErrors.size>x&&this.pruneOldErrors(),!1))}pruneOldErrors(){const e=Date.now();for(const[s,i]of this.recentErrors.entries())e-i>Te&&this.recentErrors.delete(s);if(this.recentErrors.size<=x)return;const t=Array.from(this.recentErrors.entries()).sort((s,i)=>s[1]-i[1]),r=this.recentErrors.size-x;for(let s=0;s<r;s+=1){const i=t[s];i&&this.recentErrors.delete(i[0])}}}class Ct extends S{isInitialized=!1;suppressNextScrollTimer=null;emitter=new St;managers={};handlers={};integrations={};get initialized(){return this.isInitialized}async init(e={}){if(!this.isInitialized){this.managers.storage=new Lt;try{this.setupState(e),await this.setupIntegrations(),this.managers.event=new Tt(this.managers.storage,this.integrations.googleAnalytics,this.emitter),this.initializeHandlers(),await this.managers.event.recoverPersistedEvents().catch(t=>{a("warn","Failed to recover persisted events",{error:t})}),this.isInitialized=!0}catch(t){this.destroy(!0);const r=t instanceof Error?t.message:String(t);throw new Error(`[TraceLog] TraceLog initialization failed: ${r}`)}}}sendCustomEvent(e,t){if(!this.managers.event)return;const{valid:r,error:s,sanitizedMetadata:i}=mt(e,t);if(!r){if(this.get("mode")===b.QA)throw new Error(`[TraceLog] Custom event "${e}" validation failed: ${s}`);return}this.managers.event.track({type:u.CUSTOM,custom_event:{name:e,...i&&{metadata:i}}})}on(e,t){this.emitter.on(e,t)}off(e,t){this.emitter.off(e,t)}destroy(e=!1){!this.isInitialized&&!e||(this.integrations.googleAnalytics?.cleanup(),Object.values(this.handlers).filter(Boolean).forEach(t=>{try{t.stopTracking()}catch(r){a("warn","Failed to stop tracking",{error:r})}}),this.suppressNextScrollTimer&&(clearTimeout(this.suppressNextScrollTimer),this.suppressNextScrollTimer=null),this.managers.event?.flushImmediatelySync(),this.managers.event?.stop(),this.emitter.removeAllListeners(),this.set("hasStartSession",!1),this.set("suppressNextScroll",!1),this.set("sessionId",null),this.isInitialized=!1,this.handlers={})}setupState(e={}){this.set("config",e);const t=It.getId(this.managers.storage);this.set("userId",t);const r=at(e);this.set("collectApiUrl",r);const s=Ye();this.set("device",s);const i=Z(window.location.href,e.sensitiveQueryParams);this.set("pageUrl",i);const o=st()?b.QA:void 0;o&&this.set("mode",o)}async setupIntegrations(){if(this.get("config").integrations?.googleAnalytics?.measurementId?.trim())try{this.integrations.googleAnalytics=new yt,await this.integrations.googleAnalytics.initialize()}catch{this.integrations.googleAnalytics=void 0}}initializeHandlers(){this.handlers.session=new vt(this.managers.storage,this.managers.event),this.handlers.session.startTracking();const e=()=>{this.set("suppressNextScroll",!0),this.suppressNextScrollTimer&&clearTimeout(this.suppressNextScrollTimer),this.suppressNextScrollTimer=window.setTimeout(()=>{this.set("suppressNextScroll",!1)},500)};this.handlers.pageView=new At(this.managers.event,e),this.handlers.pageView.startTracking(),this.handlers.click=new wt(this.managers.event),this.handlers.click.startTracking(),this.handlers.scroll=new Mt(this.managers.event),this.handlers.scroll.startTracking(),this.handlers.performance=new Rt(this.managers.event),this.handlers.performance.startTracking().catch(t=>{a("warn","Failed to start performance tracking",{error:t})}),this.handlers.error=new Ot(this.managers.event),this.handlers.error.startTracking(),this.get("config").viewport&&(this.handlers.viewport=new Nt(this.managers.event),this.handlers.viewport.startTracking())}}const R=[];let g=null,D=!1,W=!1;const bt=async n=>{if(typeof window>"u"||typeof document>"u")throw new Error("[TraceLog] This library can only be used in a browser environment");if(!window.__traceLogDisabled&&!g&&!D){D=!0;try{const e=ht(n??{}),t=new Ct;try{R.forEach(({event:i,callback:o})=>{t.on(i,o)}),R.length=0;const r=t.init(e),s=new Promise((i,o)=>{setTimeout(()=>{o(new Error("[TraceLog] Initialization timeout after 10000ms"))},1e4)});await Promise.race([r,s]),g=t}catch(r){try{t.destroy(!0)}catch(s){a("error","Failed to cleanup partially initialized app",{error:s})}throw r}}catch(e){throw g=null,e}finally{D=!1}}},Pt=(n,e)=>{if(!g)throw new Error("[TraceLog] TraceLog not initialized. Please call init() first.");if(W)throw new Error("[TraceLog] Cannot send events while TraceLog is being destroyed");g.sendCustomEvent(n,e)},Dt=(n,e)=>{if(!g||D){R.push({event:n,callback:e});return}g.on(n,e)},Vt=(n,e)=>{if(!g){const t=R.findIndex(r=>r.event===n&&r.callback===e);t!==-1&&R.splice(t,1);return}g.off(n,e)},kt=()=>g!==null,Ut=()=>{if(W)throw new Error("[TraceLog] Destroy operation already in progress");if(!g)throw new Error("[TraceLog] App not initialized");W=!0;try{g.destroy(),g=null,D=!1,R.length=0}catch(n){g=null,D=!1,R.length=0,a("warn","Error during destroy, forced cleanup completed",{error:n})}finally{W=!1}},Ht={WEB_VITALS_THRESHOLDS:Se},Ft={PII_PATTERNS:q},Gt={LOW_ACTIVITY_EVENT_COUNT:50,HIGH_ACTIVITY_EVENT_COUNT:1e3,MIN_EVENTS_FOR_DYNAMIC_CALCULATION:100,MIN_EVENTS_FOR_TREND_ANALYSIS:30,BOUNCE_RATE_SESSION_THRESHOLD:1,MIN_ENGAGED_SESSION_DURATION_MS:30*1e3,MIN_SCROLL_DEPTH_ENGAGEMENT:25},xt={INACTIVITY_TIMEOUT_MS:1800*1e3,SHORT_SESSION_THRESHOLD_MS:30*1e3,MEDIUM_SESSION_THRESHOLD_MS:300*1e3,LONG_SESSION_THRESHOLD_MS:1800*1e3,MAX_REALISTIC_SESSION_DURATION_MS:480*60*1e3},Wt={MOBILE_MAX_WIDTH:768,TABLET_MAX_WIDTH:1024,MOBILE_PERFORMANCE_FACTOR:1.5,TABLET_PERFORMANCE_FACTOR:1.2},Xt={MIN_TEXT_LENGTH_FOR_ANALYSIS:10,MIN_CLICKS_FOR_HOT_ELEMENT:10,MIN_SCROLL_COMPLETION_PERCENT:80,MIN_TIME_ON_PAGE_FOR_READ_MS:15*1e3},Bt={SIGNIFICANT_CHANGE_PERCENT:20,MAJOR_CHANGE_PERCENT:50,MIN_EVENTS_FOR_INSIGHT:100,MIN_SESSIONS_FOR_INSIGHT:10,MIN_CORRELATION_STRENGTH:.7,LOW_ERROR_RATE_PERCENT:1,HIGH_ERROR_RATE_PERCENT:5,CRITICAL_ERROR_RATE_PERCENT:10},$t={SHORT_TERM_TREND_HOURS:24,MEDIUM_TERM_TREND_DAYS:7,LONG_TERM_TREND_DAYS:30,MIN_DATA_POINTS_FOR_TREND:5,WEEKLY_PATTERN_MIN_WEEKS:4,DAILY_PATTERN_MIN_DAYS:14},zt={MIN_SEGMENT_SIZE:10,MIN_COHORT_SIZE:5,COHORT_ANALYSIS_DAYS:[1,3,7,14,30],MIN_FUNNEL_EVENTS:20},Yt={DEFAULT_EVENTS_LIMIT:5,DEFAULT_SESSIONS_LIMIT:5,DEFAULT_PAGES_LIMIT:5,MAX_EVENTS_FOR_DEEP_ANALYSIS:1e4,MAX_TIME_RANGE_DAYS:365,ANALYTICS_BATCH_SIZE:1e3},Qt={ANOMALY_THRESHOLD_SIGMA:2.5,STRONG_ANOMALY_THRESHOLD_SIGMA:3,TRAFFIC_DROP_ALERT_PERCENT:-30,TRAFFIC_SPIKE_ALERT_PERCENT:200,MIN_BASELINE_DAYS:7,MIN_EVENTS_FOR_ANOMALY_DETECTION:50},jt={PAGE_URL_EXCLUDED:"excluded",PAGE_URL_UNKNOWN:"unknown"},Kt={init:bt,event:Pt,on:Dt,off:Vt,isInitialized:kt,destroy:Ut};var te,Le=-1,V=function(n){addEventListener("pageshow",(function(e){e.persisted&&(Le=e.timeStamp,n(e))}),!0)},re=function(){var n=self.performance&&performance.getEntriesByType&&performance.getEntriesByType("navigation")[0];if(n&&n.responseStart>0&&n.responseStart<performance.now())return n},X=function(){var n=re();return n&&n.activationStart||0},I=function(n,e){var t=re(),r="navigate";return Le>=0?r="back-forward-cache":t&&(document.prerendering||X()>0?r="prerender":document.wasDiscarded?r="restore":t.type&&(r=t.type.replace(/_/g,"-"))),{name:n,value:e===void 0?-1:e,rating:"good",delta:0,entries:[],id:"v4-".concat(Date.now(),"-").concat(Math.floor(8999999999999*Math.random())+1e12),navigationType:r}},H=function(n,e,t){try{if(PerformanceObserver.supportedEntryTypes.includes(n)){var r=new PerformanceObserver((function(s){Promise.resolve().then((function(){e(s.getEntries())}))}));return r.observe(Object.assign({type:n,buffered:!0},t||{})),r}}catch{}},p=function(n,e,t,r){var s,i;return function(o){e.value>=0&&(o||r)&&((i=e.value-(s||0))||s===void 0)&&(s=e.value,e.delta=i,e.rating=(function(l,c){return l>c[1]?"poor":l>c[0]?"needs-improvement":"good"})(e.value,t),n(e))}},ne=function(n){requestAnimationFrame((function(){return requestAnimationFrame((function(){return n()}))}))},B=function(n){document.addEventListener("visibilitychange",(function(){document.visibilityState==="hidden"&&n()}))},se=function(n){var e=!1;return function(){e||(n(),e=!0)}},k=-1,Re=function(){return document.visibilityState!=="hidden"||document.prerendering?1/0:0},$=function(n){document.visibilityState==="hidden"&&k>-1&&(k=n.type==="visibilitychange"?n.timeStamp:0,qt())},Oe=function(){addEventListener("visibilitychange",$,!0),addEventListener("prerenderingchange",$,!0)},qt=function(){removeEventListener("visibilitychange",$,!0),removeEventListener("prerenderingchange",$,!0)},Ce=function(){return k<0&&(k=Re(),Oe(),V((function(){setTimeout((function(){k=Re(),Oe()}),0)}))),{get firstHiddenTime(){return k}}},z=function(n){document.prerendering?addEventListener("prerenderingchange",(function(){return n()}),!0):n()},ie=[1800,3e3],be=function(n,e){e=e||{},z((function(){var t,r=Ce(),s=I("FCP"),i=H("paint",(function(o){o.forEach((function(l){l.name==="first-contentful-paint"&&(i.disconnect(),l.startTime<r.firstHiddenTime&&(s.value=Math.max(l.startTime-X(),0),s.entries.push(l),t(!0)))}))}));i&&(t=p(n,s,ie,e.reportAllChanges),V((function(o){s=I("FCP"),t=p(n,s,ie,e.reportAllChanges),ne((function(){s.value=performance.now()-o.timeStamp,t(!0)}))})))}))},oe=[.1,.25],Zt=function(n,e){e=e||{},be(se((function(){var t,r=I("CLS",0),s=0,i=[],o=function(c){c.forEach((function(d){if(!d.hadRecentInput){var T=i[0],m=i[i.length-1];s&&d.startTime-m.startTime<1e3&&d.startTime-T.startTime<5e3?(s+=d.value,i.push(d)):(s=d.value,i=[d])}})),s>r.value&&(r.value=s,r.entries=i,t())},l=H("layout-shift",o);l&&(t=p(n,r,oe,e.reportAllChanges),B((function(){o(l.takeRecords()),t(!0)})),V((function(){s=0,r=I("CLS",0),t=p(n,r,oe,e.reportAllChanges),ne((function(){return t()}))})),setTimeout(t,0))})))},Pe=0,ae=1/0,Y=0,Jt=function(n){n.forEach((function(e){e.interactionId&&(ae=Math.min(ae,e.interactionId),Y=Math.max(Y,e.interactionId),Pe=Y?(Y-ae)/7+1:0)}))},De=function(){return te?Pe:performance.interactionCount||0},er=function(){"interactionCount"in performance||te||(te=H("event",Jt,{type:"event",buffered:!0,durationThreshold:0}))},v=[],Q=new Map,Ve=0,tr=function(){var n=Math.min(v.length-1,Math.floor((De()-Ve)/50));return v[n]},rr=[],nr=function(n){if(rr.forEach((function(s){return s(n)})),n.interactionId||n.entryType==="first-input"){var e=v[v.length-1],t=Q.get(n.interactionId);if(t||v.length<10||n.duration>e.latency){if(t)n.duration>t.latency?(t.entries=[n],t.latency=n.duration):n.duration===t.latency&&n.startTime===t.entries[0].startTime&&t.entries.push(n);else{var r={id:n.interactionId,latency:n.duration,entries:[n]};Q.set(r.id,r),v.push(r)}v.sort((function(s,i){return i.latency-s.latency})),v.length>10&&v.splice(10).forEach((function(s){return Q.delete(s.id)}))}}},ke=function(n){var e=self.requestIdleCallback||self.setTimeout,t=-1;return n=se(n),document.visibilityState==="hidden"?n():(t=e(n),B(n)),t},le=[200,500],sr=function(n,e){"PerformanceEventTiming"in self&&"interactionId"in PerformanceEventTiming.prototype&&(e=e||{},z((function(){var t;er();var r,s=I("INP"),i=function(l){ke((function(){l.forEach(nr);var c=tr();c&&c.latency!==s.value&&(s.value=c.latency,s.entries=c.entries,r())}))},o=H("event",i,{durationThreshold:(t=e.durationThreshold)!==null&&t!==void 0?t:40});r=p(n,s,le,e.reportAllChanges),o&&(o.observe({type:"first-input",buffered:!0}),B((function(){i(o.takeRecords()),r(!0)})),V((function(){Ve=De(),v.length=0,Q.clear(),s=I("INP"),r=p(n,s,le,e.reportAllChanges)})))})))},ce=[2500,4e3],ue={},ir=function(n,e){e=e||{},z((function(){var t,r=Ce(),s=I("LCP"),i=function(c){e.reportAllChanges||(c=c.slice(-1)),c.forEach((function(d){d.startTime<r.firstHiddenTime&&(s.value=Math.max(d.startTime-X(),0),s.entries=[d],t())}))},o=H("largest-contentful-paint",i);if(o){t=p(n,s,ce,e.reportAllChanges);var l=se((function(){ue[s.id]||(i(o.takeRecords()),o.disconnect(),ue[s.id]=!0,t(!0))}));["keydown","click"].forEach((function(c){addEventListener(c,(function(){return ke(l)}),{once:!0,capture:!0})})),B(l),V((function(c){s=I("LCP"),t=p(n,s,ce,e.reportAllChanges),ne((function(){s.value=performance.now()-c.timeStamp,ue[s.id]=!0,t(!0)}))}))}}))},de=[800,1800],or=function n(e){document.prerendering?z((function(){return n(e)})):document.readyState!=="complete"?addEventListener("load",(function(){return n(e)}),!0):setTimeout(e,0)},ar=function(n,e){e=e||{};var t=I("TTFB"),r=p(n,t,de,e.reportAllChanges);or((function(){var s=re();s&&(t.value=Math.max(s.responseStart-X(),0),t.entries=[s],r(!0),V((function(){t=I("TTFB",0),(r=p(n,t,de,e.reportAllChanges))(!0)})))}))};const lr=Object.freeze(Object.defineProperty({__proto__:null,CLSThresholds:oe,FCPThresholds:ie,INPThresholds:le,LCPThresholds:ce,TTFBThresholds:de,onCLS:Zt,onFCP:be,onINP:sr,onLCP:ir,onTTFB:ar},Symbol.toStringTag,{value:"Module"}));h.ANALYTICS_QUERY_LIMITS=Yt,h.ANOMALY_DETECTION=Qt,h.AppConfigValidationError=f,h.CONTENT_ANALYTICS=Xt,h.DATA_PROTECTION=Ft,h.DEVICE_ANALYTICS=Wt,h.DeviceType=w,h.ENGAGEMENT_THRESHOLDS=Gt,h.EmitterEvent=G,h.ErrorType=C,h.EventType=u,h.INSIGHT_THRESHOLDS=Bt,h.InitializationTimeoutError=Xe,h.IntegrationValidationError=M,h.MAX_ARRAY_LENGTH=100,h.MAX_CUSTOM_EVENT_ARRAY_SIZE=10,h.MAX_CUSTOM_EVENT_KEYS=10,h.MAX_CUSTOM_EVENT_NAME_LENGTH=120,h.MAX_CUSTOM_EVENT_STRING_SIZE=8192,h.MAX_METADATA_NESTING_DEPTH=1,h.MAX_NESTED_OBJECT_KEYS=20,h.MAX_STRING_LENGTH=1e3,h.MAX_STRING_LENGTH_IN_ARRAY=500,h.Mode=b,h.PERFORMANCE_CONFIG=Ht,h.PermanentError=L,h.SEGMENTATION_ANALYTICS=zt,h.SESSION_ANALYTICS=xt,h.SPECIAL_PAGE_URLS=jt,h.SamplingRateValidationError=j,h.ScrollDirection=U,h.SessionTimeoutValidationError=fe,h.SpecialApiUrl=F,h.TEMPORAL_ANALYSIS=$t,h.TraceLogValidationError=P,h.isPrimaryScrollEvent=xe,h.isSecondaryScrollEvent=We,h.tracelog=Kt,Object.defineProperty(h,Symbol.toStringTag,{value:"Module"})})(this.TraceLog=this.TraceLog||{});typeof window<"u"&&window.TraceLog?.tracelog&&(window.tracelog=window.TraceLog.tracelog);
|
|
8
|
+
`,document.head.appendChild(r)}}class Lt{storage;sessionStorageRef;fallbackStorage=new Map;fallbackSessionStorage=new Map;hasQuotaExceededError=!1;constructor(){this.storage=this.initializeStorage("localStorage"),this.sessionStorageRef=this.initializeStorage("sessionStorage"),this.storage||a("warn","localStorage not available, using memory fallback"),this.sessionStorageRef||a("warn","sessionStorage not available, using memory fallback")}getItem(e){try{return this.storage?this.storage.getItem(e):this.fallbackStorage.get(e)??null}catch{return this.fallbackStorage.get(e)??null}}setItem(e,t){this.fallbackStorage.set(e,t);try{if(this.storage){this.storage.setItem(e,t);return}}catch(r){if(r instanceof DOMException&&r.name==="QuotaExceededError")if(this.hasQuotaExceededError=!0,a("warn","localStorage quota exceeded, attempting cleanup",{data:{key:e,valueSize:t.length}}),this.cleanupOldData())try{if(this.storage){this.storage.setItem(e,t);return}}catch(i){a("error","localStorage quota exceeded even after cleanup - data will not persist",{error:i,data:{key:e,valueSize:t.length}})}else a("error","localStorage quota exceeded and no data to cleanup - data will not persist",{error:r,data:{key:e,valueSize:t.length}})}}removeItem(e){try{this.storage&&this.storage.removeItem(e)}catch{}this.fallbackStorage.delete(e)}clear(){if(!this.storage){this.fallbackStorage.clear();return}try{const e=[];for(let t=0;t<this.storage.length;t++){const r=this.storage.key(t);r?.startsWith("tracelog_")&&e.push(r)}e.forEach(t=>{this.storage.removeItem(t)}),this.fallbackStorage.clear()}catch(e){a("error","Failed to clear storage",{error:e}),this.fallbackStorage.clear()}}isAvailable(){return this.storage!==null}hasQuotaError(){return this.hasQuotaExceededError}cleanupOldData(){if(!this.storage)return!1;try{const e=[],t=[];for(let i=0;i<this.storage.length;i++){const o=this.storage.key(i);o?.startsWith("tracelog_")&&(e.push(o),o.startsWith("tracelog_persisted_events_")&&t.push(o))}if(t.length>0)return t.forEach(i=>{try{this.storage.removeItem(i)}catch{}}),!0;const r=["tracelog_session_","tracelog_user_id","tracelog_device_id","tracelog_config"],s=e.filter(i=>!r.some(o=>i.startsWith(o)));return s.length>0?(s.slice(0,5).forEach(o=>{try{this.storage.removeItem(o)}catch{}}),!0):!1}catch(e){return a("error","Failed to cleanup old data",{error:e}),!1}}initializeStorage(e){if(typeof window>"u")return null;try{const t=e==="localStorage"?window.localStorage:window.sessionStorage,r="__tracelog_test__";return t.setItem(r,"test"),t.removeItem(r),t}catch{return null}}getSessionItem(e){try{return this.sessionStorageRef?this.sessionStorageRef.getItem(e):this.fallbackSessionStorage.get(e)??null}catch{return this.fallbackSessionStorage.get(e)??null}}setSessionItem(e,t){this.fallbackSessionStorage.set(e,t);try{if(this.sessionStorageRef){this.sessionStorageRef.setItem(e,t);return}}catch(r){r instanceof DOMException&&r.name==="QuotaExceededError"&&a("error","sessionStorage quota exceeded - data will not persist",{error:r,data:{key:e,valueSize:t.length}})}}removeSessionItem(e){try{this.sessionStorageRef&&this.sessionStorageRef.removeItem(e)}catch{}this.fallbackSessionStorage.delete(e)}}class Rt extends S{eventManager;reportedByNav=new Map;observers=[];lastLongTaskSentAt=0;vitalThresholds=Se;constructor(e){super(),this.eventManager=e}async startTracking(){await this.initWebVitals(),this.observeLongTasks()}stopTracking(){this.observers.forEach((e,t)=>{try{e.disconnect()}catch(r){a("warn","Failed to disconnect performance observer",{error:r,data:{observerIndex:t}})}}),this.observers.length=0,this.reportedByNav.clear()}observeWebVitalsFallback(){this.reportTTFB(),this.safeObserve("largest-contentful-paint",r=>{const s=r.getEntries(),i=s[s.length-1];i&&this.sendVital({type:"LCP",value:Number(i.startTime.toFixed(2))})},{type:"largest-contentful-paint",buffered:!0},!0);let e=0,t=this.getNavigationId();this.safeObserve("layout-shift",r=>{const s=this.getNavigationId();s!==t&&(e=0,t=s);const i=r.getEntries();for(const o of i){if(o.hadRecentInput===!0)continue;const l=typeof o.value=="number"?o.value:0;e+=l}this.sendVital({type:"CLS",value:Number(e.toFixed(2))})},{type:"layout-shift",buffered:!0}),this.safeObserve("paint",r=>{for(const s of r.getEntries())s.name==="first-contentful-paint"&&this.sendVital({type:"FCP",value:Number(s.startTime.toFixed(2))})},{type:"paint",buffered:!0},!0),this.safeObserve("event",r=>{let s=0;const i=r.getEntries();for(const o of i){const l=(o.processingEnd??0)-(o.startTime??0);s=Math.max(s,l)}s>0&&this.sendVital({type:"INP",value:Number(s.toFixed(2))})},{type:"event",buffered:!0})}async initWebVitals(){try{const{onLCP:e,onCLS:t,onFCP:r,onTTFB:s,onINP:i}=await Promise.resolve().then(()=>lr),o=l=>c=>{const d=Number(c.value.toFixed(2));this.sendVital({type:l,value:d})};e(o("LCP"),{reportAllChanges:!1}),t(o("CLS"),{reportAllChanges:!1}),r(o("FCP"),{reportAllChanges:!1}),s(o("TTFB"),{reportAllChanges:!1}),i(o("INP"),{reportAllChanges:!1})}catch(e){a("warn","Failed to load web-vitals library, using fallback",{error:e}),this.observeWebVitalsFallback()}}reportTTFB(){try{const e=performance.getEntriesByType("navigation")[0];if(!e)return;const t=e.responseStart;typeof t=="number"&&Number.isFinite(t)&&this.sendVital({type:"TTFB",value:Number(t.toFixed(2))})}catch(e){a("warn","Failed to report TTFB",{error:e})}}observeLongTasks(){this.safeObserve("longtask",e=>{const t=e.getEntries();for(const r of t){const s=Number(r.duration.toFixed(2)),i=Date.now();i-this.lastLongTaskSentAt>=Ze&&(this.shouldSendVital("LONG_TASK",s)&&this.trackWebVital("LONG_TASK",s),this.lastLongTaskSentAt=i)}},{type:"longtask",buffered:!0})}sendVital(e){if(!this.shouldSendVital(e.type,e.value))return;const t=this.getNavigationId();if(t){const r=this.reportedByNav.get(t);if(r?.has(e.type))return;r?r.add(e.type):this.reportedByNav.set(t,new Set([e.type]))}this.trackWebVital(e.type,e.value)}trackWebVital(e,t){if(!Number.isFinite(t)){a("warn","Invalid web vital value",{data:{type:e,value:t}});return}this.eventManager.track({type:u.WEB_VITALS,web_vitals:{type:e,value:t}})}getNavigationId(){try{const e=performance.getEntriesByType("navigation")[0];if(!e)return null;const t=e.startTime||performance.now(),r=Math.random().toString(36).substr(2,5);return`${t.toFixed(2)}_${window.location.pathname}_${r}`}catch(e){return a("warn","Failed to get navigation ID",{error:e}),null}}isObserverSupported(e){if(typeof PerformanceObserver>"u")return!1;const t=PerformanceObserver.supportedEntryTypes;return!t||t.includes(e)}safeObserve(e,t,r,s=!1){try{if(!this.isObserverSupported(e))return!1;const i=new PerformanceObserver((o,l)=>{try{t(o,l)}catch(c){a("warn","Observer callback failed",{error:c,data:{type:e}})}if(s)try{l.disconnect()}catch{}});return i.observe(r??{type:e,buffered:!0}),s||this.observers.push(i),!0}catch(i){return a("warn","Failed to create performance observer",{error:i,data:{type:e}}),!1}}shouldSendVital(e,t){if(typeof t!="number"||!Number.isFinite(t))return a("warn","Invalid web vital value",{data:{type:e,value:t}}),!1;const r=this.vitalThresholds[e];return!(typeof r=="number"&&t<=r)}}class Ot extends S{eventManager;recentErrors=new Map;errorBurstCounter=0;burstWindowStart=0;burstBackoffUntil=0;constructor(e){super(),this.eventManager=e}startTracking(){window.addEventListener("error",this.handleError),window.addEventListener("unhandledrejection",this.handleRejection)}stopTracking(){window.removeEventListener("error",this.handleError),window.removeEventListener("unhandledrejection",this.handleRejection),this.recentErrors.clear(),this.errorBurstCounter=0,this.burstWindowStart=0,this.burstBackoffUntil=0}shouldSample(){const e=Date.now();if(e<this.burstBackoffUntil)return!1;if(e-this.burstWindowStart>et&&(this.errorBurstCounter=0,this.burstWindowStart=e),this.errorBurstCounter++,this.errorBurstCounter>tt)return this.burstBackoffUntil=e+pe,a("warn","Error burst detected - entering cooldown",{data:{errorsInWindow:this.errorBurstCounter,cooldownMs:pe}}),!1;const r=this.get("config")?.errorSampling??Ie;return Math.random()<r}handleError=e=>{if(!this.shouldSample())return;const t=this.sanitize(e.message||"Unknown error");this.shouldSuppressError(C.JS_ERROR,t)||this.eventManager.track({type:u.ERROR,error_data:{type:C.JS_ERROR,message:t,...e.filename&&{filename:e.filename},...e.lineno&&{line:e.lineno},...e.colno&&{column:e.colno}}})};handleRejection=e=>{if(!this.shouldSample())return;const t=this.extractRejectionMessage(e.reason),r=this.sanitize(t);this.shouldSuppressError(C.PROMISE_REJECTION,r)||this.eventManager.track({type:u.ERROR,error_data:{type:C.PROMISE_REJECTION,message:r}})};extractRejectionMessage(e){if(!e)return"Unknown rejection";if(typeof e=="string")return e;if(e instanceof Error)return e.stack??e.message??e.toString();if(typeof e=="object"&&"message"in e)return String(e.message);try{return JSON.stringify(e)}catch{return String(e)}}sanitize(e){let t=e.length>_e?e.slice(0,_e)+"...":e;for(const r of q){const s=new RegExp(r.source,r.flags);t=t.replace(s,"[REDACTED]")}return t}shouldSuppressError(e,t){const r=Date.now(),s=`${e}:${t}`,i=this.recentErrors.get(s);return i&&r-i<Te?(this.recentErrors.set(s,r),!0):(this.recentErrors.set(s,r),this.recentErrors.size>Je?(this.recentErrors.clear(),this.recentErrors.set(s,r),!1):(this.recentErrors.size>x&&this.pruneOldErrors(),!1))}pruneOldErrors(){const e=Date.now();for(const[s,i]of this.recentErrors.entries())e-i>Te&&this.recentErrors.delete(s);if(this.recentErrors.size<=x)return;const t=Array.from(this.recentErrors.entries()).sort((s,i)=>s[1]-i[1]),r=this.recentErrors.size-x;for(let s=0;s<r;s+=1){const i=t[s];i&&this.recentErrors.delete(i[0])}}}class Ct extends S{isInitialized=!1;suppressNextScrollTimer=null;emitter=new St;managers={};handlers={};integrations={};get initialized(){return this.isInitialized}async init(e={}){if(!this.isInitialized){this.managers.storage=new Lt;try{this.setupState(e),await this.setupIntegrations(),this.managers.event=new Tt(this.managers.storage,this.integrations.googleAnalytics,this.emitter),this.initializeHandlers(),await this.managers.event.recoverPersistedEvents().catch(t=>{a("warn","Failed to recover persisted events",{error:t})}),this.isInitialized=!0}catch(t){this.destroy(!0);const r=t instanceof Error?t.message:String(t);throw new Error(`[TraceLog] TraceLog initialization failed: ${r}`)}}}sendCustomEvent(e,t){if(!this.managers.event)return;const{valid:r,error:s,sanitizedMetadata:i}=mt(e,t);if(!r){if(this.get("mode")===b.QA)throw new Error(`[TraceLog] Custom event "${e}" validation failed: ${s}`);return}this.managers.event.track({type:u.CUSTOM,custom_event:{name:e,...i&&{metadata:i}}})}on(e,t){this.emitter.on(e,t)}off(e,t){this.emitter.off(e,t)}destroy(e=!1){!this.isInitialized&&!e||(this.integrations.googleAnalytics?.cleanup(),Object.values(this.handlers).filter(Boolean).forEach(t=>{try{t.stopTracking()}catch(r){a("warn","Failed to stop tracking",{error:r})}}),this.suppressNextScrollTimer&&(clearTimeout(this.suppressNextScrollTimer),this.suppressNextScrollTimer=null),this.managers.event?.flushImmediatelySync(),this.managers.event?.stop(),this.emitter.removeAllListeners(),this.set("hasStartSession",!1),this.set("suppressNextScroll",!1),this.set("sessionId",null),this.isInitialized=!1,this.handlers={})}setupState(e={}){this.set("config",e);const t=It.getId(this.managers.storage);this.set("userId",t);const r=at(e);this.set("collectApiUrl",r);const s=Ye();this.set("device",s);const i=Z(window.location.href,e.sensitiveQueryParams);this.set("pageUrl",i);const o=st()?b.QA:void 0;o&&this.set("mode",o)}async setupIntegrations(){if(this.get("config").integrations?.googleAnalytics?.measurementId?.trim())try{this.integrations.googleAnalytics=new Nt,await this.integrations.googleAnalytics.initialize()}catch{this.integrations.googleAnalytics=void 0}}initializeHandlers(){this.handlers.session=new vt(this.managers.storage,this.managers.event),this.handlers.session.startTracking();const e=()=>{this.set("suppressNextScroll",!0),this.suppressNextScrollTimer&&clearTimeout(this.suppressNextScrollTimer),this.suppressNextScrollTimer=window.setTimeout(()=>{this.set("suppressNextScroll",!1)},500)};this.handlers.pageView=new At(this.managers.event,e),this.handlers.pageView.startTracking(),this.handlers.click=new wt(this.managers.event),this.handlers.click.startTracking(),this.handlers.scroll=new yt(this.managers.event),this.handlers.scroll.startTracking(),this.handlers.performance=new Rt(this.managers.event),this.handlers.performance.startTracking().catch(t=>{a("warn","Failed to start performance tracking",{error:t})}),this.handlers.error=new Ot(this.managers.event),this.handlers.error.startTracking(),this.get("config").viewport&&(this.handlers.viewport=new Mt(this.managers.event),this.handlers.viewport.startTracking())}}const R=[];let g=null,D=!1,W=!1;const bt=async n=>{if(!(typeof window>"u"||typeof document>"u")&&!window.__traceLogDisabled&&!g&&!D){D=!0;try{const e=ht(n??{}),t=new Ct;try{R.forEach(({event:i,callback:o})=>{t.on(i,o)}),R.length=0;const r=t.init(e),s=new Promise((i,o)=>{setTimeout(()=>{o(new Error("[TraceLog] Initialization timeout after 10000ms"))},1e4)});await Promise.race([r,s]),g=t}catch(r){try{t.destroy(!0)}catch(s){a("error","Failed to cleanup partially initialized app",{error:s})}throw r}}catch(e){throw g=null,e}finally{D=!1}}},Pt=(n,e)=>{if(!(typeof window>"u"||typeof document>"u")){if(!g)throw new Error("[TraceLog] TraceLog not initialized. Please call init() first.");if(W)throw new Error("[TraceLog] Cannot send events while TraceLog is being destroyed");g.sendCustomEvent(n,e)}},Dt=(n,e)=>{if(!(typeof window>"u"||typeof document>"u")){if(!g||D){R.push({event:n,callback:e});return}g.on(n,e)}},Vt=(n,e)=>{if(!(typeof window>"u"||typeof document>"u")){if(!g){const t=R.findIndex(r=>r.event===n&&r.callback===e);t!==-1&&R.splice(t,1);return}g.off(n,e)}},kt=()=>typeof window>"u"||typeof document>"u"?!1:g!==null,Ut=()=>{if(!(typeof window>"u"||typeof document>"u")){if(W)throw new Error("[TraceLog] Destroy operation already in progress");if(!g)throw new Error("[TraceLog] App not initialized");W=!0;try{g.destroy(),g=null,D=!1,R.length=0}catch(n){g=null,D=!1,R.length=0,a("warn","Error during destroy, forced cleanup completed",{error:n})}finally{W=!1}}},Ht={WEB_VITALS_THRESHOLDS:Se},Ft={PII_PATTERNS:q},Gt={LOW_ACTIVITY_EVENT_COUNT:50,HIGH_ACTIVITY_EVENT_COUNT:1e3,MIN_EVENTS_FOR_DYNAMIC_CALCULATION:100,MIN_EVENTS_FOR_TREND_ANALYSIS:30,BOUNCE_RATE_SESSION_THRESHOLD:1,MIN_ENGAGED_SESSION_DURATION_MS:30*1e3,MIN_SCROLL_DEPTH_ENGAGEMENT:25},xt={INACTIVITY_TIMEOUT_MS:1800*1e3,SHORT_SESSION_THRESHOLD_MS:30*1e3,MEDIUM_SESSION_THRESHOLD_MS:300*1e3,LONG_SESSION_THRESHOLD_MS:1800*1e3,MAX_REALISTIC_SESSION_DURATION_MS:480*60*1e3},Wt={MOBILE_MAX_WIDTH:768,TABLET_MAX_WIDTH:1024,MOBILE_PERFORMANCE_FACTOR:1.5,TABLET_PERFORMANCE_FACTOR:1.2},Xt={MIN_TEXT_LENGTH_FOR_ANALYSIS:10,MIN_CLICKS_FOR_HOT_ELEMENT:10,MIN_SCROLL_COMPLETION_PERCENT:80,MIN_TIME_ON_PAGE_FOR_READ_MS:15*1e3},Bt={SIGNIFICANT_CHANGE_PERCENT:20,MAJOR_CHANGE_PERCENT:50,MIN_EVENTS_FOR_INSIGHT:100,MIN_SESSIONS_FOR_INSIGHT:10,MIN_CORRELATION_STRENGTH:.7,LOW_ERROR_RATE_PERCENT:1,HIGH_ERROR_RATE_PERCENT:5,CRITICAL_ERROR_RATE_PERCENT:10},$t={SHORT_TERM_TREND_HOURS:24,MEDIUM_TERM_TREND_DAYS:7,LONG_TERM_TREND_DAYS:30,MIN_DATA_POINTS_FOR_TREND:5,WEEKLY_PATTERN_MIN_WEEKS:4,DAILY_PATTERN_MIN_DAYS:14},zt={MIN_SEGMENT_SIZE:10,MIN_COHORT_SIZE:5,COHORT_ANALYSIS_DAYS:[1,3,7,14,30],MIN_FUNNEL_EVENTS:20},Yt={DEFAULT_EVENTS_LIMIT:5,DEFAULT_SESSIONS_LIMIT:5,DEFAULT_PAGES_LIMIT:5,MAX_EVENTS_FOR_DEEP_ANALYSIS:1e4,MAX_TIME_RANGE_DAYS:365,ANALYTICS_BATCH_SIZE:1e3},Qt={ANOMALY_THRESHOLD_SIGMA:2.5,STRONG_ANOMALY_THRESHOLD_SIGMA:3,TRAFFIC_DROP_ALERT_PERCENT:-30,TRAFFIC_SPIKE_ALERT_PERCENT:200,MIN_BASELINE_DAYS:7,MIN_EVENTS_FOR_ANOMALY_DETECTION:50},jt={PAGE_URL_EXCLUDED:"excluded",PAGE_URL_UNKNOWN:"unknown"},Kt={init:bt,event:Pt,on:Dt,off:Vt,isInitialized:kt,destroy:Ut};var te,Le=-1,V=function(n){addEventListener("pageshow",(function(e){e.persisted&&(Le=e.timeStamp,n(e))}),!0)},re=function(){var n=self.performance&&performance.getEntriesByType&&performance.getEntriesByType("navigation")[0];if(n&&n.responseStart>0&&n.responseStart<performance.now())return n},X=function(){var n=re();return n&&n.activationStart||0},I=function(n,e){var t=re(),r="navigate";return Le>=0?r="back-forward-cache":t&&(document.prerendering||X()>0?r="prerender":document.wasDiscarded?r="restore":t.type&&(r=t.type.replace(/_/g,"-"))),{name:n,value:e===void 0?-1:e,rating:"good",delta:0,entries:[],id:"v4-".concat(Date.now(),"-").concat(Math.floor(8999999999999*Math.random())+1e12),navigationType:r}},H=function(n,e,t){try{if(PerformanceObserver.supportedEntryTypes.includes(n)){var r=new PerformanceObserver((function(s){Promise.resolve().then((function(){e(s.getEntries())}))}));return r.observe(Object.assign({type:n,buffered:!0},t||{})),r}}catch{}},p=function(n,e,t,r){var s,i;return function(o){e.value>=0&&(o||r)&&((i=e.value-(s||0))||s===void 0)&&(s=e.value,e.delta=i,e.rating=(function(l,c){return l>c[1]?"poor":l>c[0]?"needs-improvement":"good"})(e.value,t),n(e))}},ne=function(n){requestAnimationFrame((function(){return requestAnimationFrame((function(){return n()}))}))},B=function(n){document.addEventListener("visibilitychange",(function(){document.visibilityState==="hidden"&&n()}))},se=function(n){var e=!1;return function(){e||(n(),e=!0)}},k=-1,Re=function(){return document.visibilityState!=="hidden"||document.prerendering?1/0:0},$=function(n){document.visibilityState==="hidden"&&k>-1&&(k=n.type==="visibilitychange"?n.timeStamp:0,qt())},Oe=function(){addEventListener("visibilitychange",$,!0),addEventListener("prerenderingchange",$,!0)},qt=function(){removeEventListener("visibilitychange",$,!0),removeEventListener("prerenderingchange",$,!0)},Ce=function(){return k<0&&(k=Re(),Oe(),V((function(){setTimeout((function(){k=Re(),Oe()}),0)}))),{get firstHiddenTime(){return k}}},z=function(n){document.prerendering?addEventListener("prerenderingchange",(function(){return n()}),!0):n()},ie=[1800,3e3],be=function(n,e){e=e||{},z((function(){var t,r=Ce(),s=I("FCP"),i=H("paint",(function(o){o.forEach((function(l){l.name==="first-contentful-paint"&&(i.disconnect(),l.startTime<r.firstHiddenTime&&(s.value=Math.max(l.startTime-X(),0),s.entries.push(l),t(!0)))}))}));i&&(t=p(n,s,ie,e.reportAllChanges),V((function(o){s=I("FCP"),t=p(n,s,ie,e.reportAllChanges),ne((function(){s.value=performance.now()-o.timeStamp,t(!0)}))})))}))},oe=[.1,.25],Zt=function(n,e){e=e||{},be(se((function(){var t,r=I("CLS",0),s=0,i=[],o=function(c){c.forEach((function(d){if(!d.hadRecentInput){var T=i[0],m=i[i.length-1];s&&d.startTime-m.startTime<1e3&&d.startTime-T.startTime<5e3?(s+=d.value,i.push(d)):(s=d.value,i=[d])}})),s>r.value&&(r.value=s,r.entries=i,t())},l=H("layout-shift",o);l&&(t=p(n,r,oe,e.reportAllChanges),B((function(){o(l.takeRecords()),t(!0)})),V((function(){s=0,r=I("CLS",0),t=p(n,r,oe,e.reportAllChanges),ne((function(){return t()}))})),setTimeout(t,0))})))},Pe=0,ae=1/0,Y=0,Jt=function(n){n.forEach((function(e){e.interactionId&&(ae=Math.min(ae,e.interactionId),Y=Math.max(Y,e.interactionId),Pe=Y?(Y-ae)/7+1:0)}))},De=function(){return te?Pe:performance.interactionCount||0},er=function(){"interactionCount"in performance||te||(te=H("event",Jt,{type:"event",buffered:!0,durationThreshold:0}))},v=[],Q=new Map,Ve=0,tr=function(){var n=Math.min(v.length-1,Math.floor((De()-Ve)/50));return v[n]},rr=[],nr=function(n){if(rr.forEach((function(s){return s(n)})),n.interactionId||n.entryType==="first-input"){var e=v[v.length-1],t=Q.get(n.interactionId);if(t||v.length<10||n.duration>e.latency){if(t)n.duration>t.latency?(t.entries=[n],t.latency=n.duration):n.duration===t.latency&&n.startTime===t.entries[0].startTime&&t.entries.push(n);else{var r={id:n.interactionId,latency:n.duration,entries:[n]};Q.set(r.id,r),v.push(r)}v.sort((function(s,i){return i.latency-s.latency})),v.length>10&&v.splice(10).forEach((function(s){return Q.delete(s.id)}))}}},ke=function(n){var e=self.requestIdleCallback||self.setTimeout,t=-1;return n=se(n),document.visibilityState==="hidden"?n():(t=e(n),B(n)),t},le=[200,500],sr=function(n,e){"PerformanceEventTiming"in self&&"interactionId"in PerformanceEventTiming.prototype&&(e=e||{},z((function(){var t;er();var r,s=I("INP"),i=function(l){ke((function(){l.forEach(nr);var c=tr();c&&c.latency!==s.value&&(s.value=c.latency,s.entries=c.entries,r())}))},o=H("event",i,{durationThreshold:(t=e.durationThreshold)!==null&&t!==void 0?t:40});r=p(n,s,le,e.reportAllChanges),o&&(o.observe({type:"first-input",buffered:!0}),B((function(){i(o.takeRecords()),r(!0)})),V((function(){Ve=De(),v.length=0,Q.clear(),s=I("INP"),r=p(n,s,le,e.reportAllChanges)})))})))},ce=[2500,4e3],ue={},ir=function(n,e){e=e||{},z((function(){var t,r=Ce(),s=I("LCP"),i=function(c){e.reportAllChanges||(c=c.slice(-1)),c.forEach((function(d){d.startTime<r.firstHiddenTime&&(s.value=Math.max(d.startTime-X(),0),s.entries=[d],t())}))},o=H("largest-contentful-paint",i);if(o){t=p(n,s,ce,e.reportAllChanges);var l=se((function(){ue[s.id]||(i(o.takeRecords()),o.disconnect(),ue[s.id]=!0,t(!0))}));["keydown","click"].forEach((function(c){addEventListener(c,(function(){return ke(l)}),{once:!0,capture:!0})})),B(l),V((function(c){s=I("LCP"),t=p(n,s,ce,e.reportAllChanges),ne((function(){s.value=performance.now()-c.timeStamp,ue[s.id]=!0,t(!0)}))}))}}))},de=[800,1800],or=function n(e){document.prerendering?z((function(){return n(e)})):document.readyState!=="complete"?addEventListener("load",(function(){return n(e)}),!0):setTimeout(e,0)},ar=function(n,e){e=e||{};var t=I("TTFB"),r=p(n,t,de,e.reportAllChanges);or((function(){var s=re();s&&(t.value=Math.max(s.responseStart-X(),0),t.entries=[s],r(!0),V((function(){t=I("TTFB",0),(r=p(n,t,de,e.reportAllChanges))(!0)})))}))};const lr=Object.freeze(Object.defineProperty({__proto__:null,CLSThresholds:oe,FCPThresholds:ie,INPThresholds:le,LCPThresholds:ce,TTFBThresholds:de,onCLS:Zt,onFCP:be,onINP:sr,onLCP:ir,onTTFB:ar},Symbol.toStringTag,{value:"Module"}));h.ANALYTICS_QUERY_LIMITS=Yt,h.ANOMALY_DETECTION=Qt,h.AppConfigValidationError=f,h.CONTENT_ANALYTICS=Xt,h.DATA_PROTECTION=Ft,h.DEVICE_ANALYTICS=Wt,h.DeviceType=w,h.ENGAGEMENT_THRESHOLDS=Gt,h.EmitterEvent=G,h.ErrorType=C,h.EventType=u,h.INSIGHT_THRESHOLDS=Bt,h.InitializationTimeoutError=Xe,h.IntegrationValidationError=y,h.MAX_ARRAY_LENGTH=100,h.MAX_CUSTOM_EVENT_ARRAY_SIZE=10,h.MAX_CUSTOM_EVENT_KEYS=10,h.MAX_CUSTOM_EVENT_NAME_LENGTH=120,h.MAX_CUSTOM_EVENT_STRING_SIZE=8192,h.MAX_METADATA_NESTING_DEPTH=1,h.MAX_NESTED_OBJECT_KEYS=20,h.MAX_STRING_LENGTH=1e3,h.MAX_STRING_LENGTH_IN_ARRAY=500,h.Mode=b,h.PERFORMANCE_CONFIG=Ht,h.PermanentError=L,h.SEGMENTATION_ANALYTICS=zt,h.SESSION_ANALYTICS=xt,h.SPECIAL_PAGE_URLS=jt,h.SamplingRateValidationError=j,h.ScrollDirection=U,h.SessionTimeoutValidationError=fe,h.SpecialApiUrl=F,h.TEMPORAL_ANALYSIS=$t,h.TraceLogValidationError=P,h.isPrimaryScrollEvent=xe,h.isSecondaryScrollEvent=We,h.tracelog=Kt,Object.defineProperty(h,Symbol.toStringTag,{value:"Module"})})(this.TraceLog=this.TraceLog||{});typeof window<"u"&&window.TraceLog?.tracelog&&(window.tracelog=window.TraceLog.tracelog);
|