@tracelog/lib 0.5.2 → 0.5.4

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 CHANGED
@@ -45,9 +45,7 @@ tracelog.event('user_action', { data: 'example' });
45
45
  ```html
46
46
  <script src="https://cdn.jsdelivr.net/npm/@tracelog/lib@latest/dist/browser/tracelog.js"></script>
47
47
  <script>
48
- // tracelog is available globally
49
48
  tracelog.init({ id: 'your-project-id' });
50
- tracelog.event('page_view');
51
49
  </script>
52
50
  ```
53
51
 
@@ -1,8 +1,8 @@
1
- var tracelog=function(d){"use strict";var T=(r=>(r.Mobile="mobile",r.Tablet="tablet",r.Desktop="desktop",r.Unknown="unknown",r))(T||{});const P=15*60*1e3,Ze=500,et=1e4,Se=250,tt=24,Ee=100,pe=3,rt=5e3,ve=1e4,nt=10,ye=5,Te=500,Ie=120,b=1,st=0,it=1,O=3e4,D=864e5,_e=120,we=8*1024,Ae=10,be=10,X=255,_=1e3,q=100,Me=3,A=2,G="data-tl",at=["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"]'],ot=["utm_source","utm_medium","utm_campaign","utm_term","utm_content"],lt=2,ct=new Set(["mode","tags","samplingRate","excludedUrlPaths","ipExcluded"]),I={MISSING_PROJECT_ID:"Project ID is required",PROJECT_ID_EMPTY_AFTER_TRIM:"Project ID is required",INVALID_SESSION_TIMEOUT:`Session timeout must be between ${O}ms (30 seconds) and ${D}ms (24 hours)`,INVALID_ERROR_SAMPLING_RATE:"Error sampling must be between 0 and 1",INVALID_GOOGLE_ANALYTICS_ID:"Google Analytics measurement ID is required when integration is enabled",INVALID_SCROLL_CONTAINER_SELECTORS:"Scroll container selectors must be valid CSS selectors",INVALID_GLOBAL_METADATA:"Global metadata must be an object",INVALID_SENSITIVE_QUERY_PARAMS:"Sensitive query params must be an array of strings"},Re=[/<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi,/javascript:/gi,/on\w+\s*=/gi,/<iframe\b[^<]*(?:(?!<\/iframe>)<[^<]*)*<\/iframe>/gi,/<embed\b[^>]*>/gi,/<object\b[^<]*(?:(?!<\/object>)<[^<]*)*<\/object>/gi],k={samplingRate:b,excludedUrlPaths:[],tags:[],ipExcluded:!1},w="tl",ut=r=>r?`${w}:${r}:uid`:`${w}:uid`,dt=r=>r?`${w}:${r}:queue`:`${w}:queue`,ht=r=>r?`${w}:${r}:session`:`${w}:session`,gt=r=>r?`${w}:${r}:broadcast`:`${w}:broadcast`,Le={LCP:4e3,FCP:1800,CLS:.25,INP:200,TTFB:800,LONG_TASK:50},ft=1e3,Ne=[/\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],Ce=500,Pe=5e3,j=50,Oe=j*2,E={};function mt(){return E}class S{get(e){return E[e]}set(e,t){const n=E[e];if(e==="config"&&t){const s=t;if(s){const i=s.samplingRate??b,o=i<0||i>1?b:i;if(o!==i){const l={...s,samplingRate:o};E[e]=l}else E[e]=s}else E[e]=t}else E[e]=t;this.isCriticalStateKey(e)&&this.shouldLog(n,E[e])&&a.debug("StateManager","State updated",{key:e,oldValue:this.formatLogValue(e,n),newValue:this.formatLogValue(e,E[e])})}getState(){return{...E}}isCriticalStateKey(e){return e==="sessionId"||e==="config"||e==="hasStartSession"}shouldLog(e,t){return e!==t}formatLogValue(e,t){return e==="config"?t?"(configured)":"(not configured)":t}}class St{clientError=(e,t,n)=>this.log("CLIENT_ERROR",e,t,n);clientWarn=(e,t,n)=>this.log("CLIENT_WARN",e,t,n);info=(e,t,n)=>this.log("INFO",e,t,n);error=(e,t,n)=>this.log("ERROR",e,t,n);warn=(e,t,n)=>this.log("WARN",e,t,n);debug=(e,t,n)=>this.log("DEBUG",e,t,n);verbose=(e,t,n)=>this.log("VERBOSE",e,t,n);log(e,t,n,s){const i=mt()?.config?.mode;if(!this.shouldShow(e,i))return;const o=`[TraceLog:${t}] ${n}`,c=this.getMethod(e);s!==void 0?console[c](o,s):console[c](o)}shouldShow(e,t){return["CLIENT_ERROR","ERROR"].includes(e)?!0:t?t==="qa"?["INFO","CLIENT_ERROR","CLIENT_WARN"].includes(e):t==="debug":e==="CLIENT_WARN"}getMethod(e){return["CLIENT_ERROR","ERROR"].includes(e)?"error":["CLIENT_WARN","WARN"].includes(e)?"warn":"log"}}const a=new St;let J,De;const Et=()=>{typeof window<"u"&&!J&&(J=window.matchMedia("(pointer: coarse)"),De=window.matchMedia("(hover: none)"))},pt=()=>{try{a.debug("DeviceDetector","Starting device detection");const r=navigator;if(r.userAgentData&&typeof r.userAgentData.mobile=="boolean"){if(a.debug("DeviceDetector","Using modern User-Agent Client Hints API",{mobile:r.userAgentData.mobile,platform:r.userAgentData.platform}),r.userAgentData.platform&&/ipad|tablet/i.test(r.userAgentData.platform))return a.debug("DeviceDetector","Device detected as tablet via platform hint"),T.Tablet;const u=r.userAgentData.mobile?T.Mobile:T.Desktop;return a.debug("DeviceDetector","Device detected via User-Agent hints",{result:u}),u}a.debug("DeviceDetector","Using fallback detection methods"),Et();const e=window.innerWidth,t=J?.matches??!1,n=De?.matches??!1,s="ontouchstart"in window||navigator.maxTouchPoints>0,i=navigator.userAgent.toLowerCase(),o=/mobile|android|iphone|ipod|blackberry|iemobile|opera mini/.test(i),c=/tablet|ipad|android(?!.*mobile)/.test(i),l={width:e,hasCoarsePointer:t,hasNoHover:n,hasTouchSupport:s,isMobileUA:o,isTabletUA:c,maxTouchPoints:navigator.maxTouchPoints};return e<=767||o&&s?(a.debug("DeviceDetector","Device detected as mobile",l),T.Mobile):e>=768&&e<=1024||c||t&&n&&s?(a.debug("DeviceDetector","Device detected as tablet",l),T.Tablet):(a.debug("DeviceDetector","Device detected as desktop",l),T.Desktop)}catch(r){return a.warn("DeviceDetector","Device detection failed, defaulting to desktop",{error:r instanceof Error?r.message:r}),T.Desktop}},ke=()=>{a.debug("UTMParams","Extracting UTM parameters from URL",{url:window.location.href,search:window.location.search});const r=new URLSearchParams(window.location.search),e={};ot.forEach(n=>{const s=r.get(n);if(s){const i=n.split("utm_")[1];e[i]=s,a.debug("UTMParams","Found UTM parameter",{param:n,key:i,value:s})}});const t=Object.keys(e).length?e:void 0;return t?a.debug("UTMParams","UTM parameters extracted successfully",{parameterCount:Object.keys(t).length,parameters:Object.keys(t)}):a.debug("UTMParams","No UTM parameters found in URL"),t},vt=()=>typeof crypto<"u"&&crypto.randomUUID?crypto.randomUUID():"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g,r=>{const e=Math.random()*16|0;return(r==="x"?e:e&3|8).toString(16)});var m=(r=>(r.Skip="skip",r.Localhost="localhost:8080",r.Fail="localhost:9999",r))(m||{}),Z=(r=>(r.EVENT="event",r.QUEUE="queue",r))(Z||{}),h=(r=>(r.PAGE_VIEW="page_view",r.CLICK="click",r.SCROLL="scroll",r.SESSION_START="session_start",r.SESSION_END="session_end",r.CUSTOM="custom",r.WEB_VITALS="web_vitals",r.ERROR="error",r))(h||{}),U=(r=>(r.UP="up",r.DOWN="down",r))(U||{}),M=(r=>(r.JS_ERROR="js_error",r.PROMISE_REJECTION="promise_rejection",r))(M||{}),R=(r=>(r.QA="qa",r.DEBUG="debug",r))(R||{}),Ue=(r=>(r.AND="AND",r.OR="OR",r))(Ue||{}),xe=(r=>(r.URL_MATCHES="url_matches",r.ELEMENT_MATCHES="element_matches",r.DEVICE_TYPE="device_type",r.ELEMENT_TEXT="element_text",r.ELEMENT_ATTRIBUTE="element_attribute",r.UTM_SOURCE="utm_source",r.UTM_MEDIUM="utm_medium",r.UTM_CAMPAIGN="utm_campaign",r))(xe||{}),He=(r=>(r.EQUALS="equals",r.CONTAINS="contains",r.STARTS_WITH="starts_with",r.ENDS_WITH="ends_with",r.REGEX="regex",r.GREATER_THAN="greater_than",r.LESS_THAN="less_than",r.EXISTS="exists",r.NOT_EXISTS="not_exists",r))(He||{});class x extends Error{constructor(e,t,n){super(e),this.errorCode=t,this.layer=n,this.name=this.constructor.name,Error.captureStackTrace&&Error.captureStackTrace(this,this.constructor)}}class ee extends x{constructor(e="Project ID is required",t="config"){super(e,"PROJECT_ID_INVALID",t)}}class L extends x{constructor(e,t="config"){super(e,"APP_CONFIG_INVALID",t)}}class yt extends x{constructor(e,t="config"){super(e,"SESSION_TIMEOUT_INVALID",t)}}class Tt extends x{constructor(e,t="config"){super(e,"SAMPLING_RATE_INVALID",t)}}class Fe extends x{constructor(e,t="config"){super(e,"INTEGRATION_INVALID",t)}}const It=r=>{if(!r||typeof r!="object")throw a.clientError("ConfigValidation","Configuration must be an object",{config:r}),new L("Configuration must be an object","config");if(!("id"in r))throw a.clientError("ConfigValidation","Project ID is missing from configuration"),new ee(I.MISSING_PROJECT_ID,"config");if(r.id===null||r.id===void 0||typeof r.id!="string")throw a.clientError("ConfigValidation","Project ID must be a non-empty string",{providedId:r.id,type:typeof r.id}),new ee(I.MISSING_PROJECT_ID,"config");if(r.sessionTimeout!==void 0&&(typeof r.sessionTimeout!="number"||r.sessionTimeout<O||r.sessionTimeout>D))throw a.clientError("ConfigValidation","Invalid session timeout",{provided:r.sessionTimeout,min:O,max:D}),new yt(I.INVALID_SESSION_TIMEOUT,"config");if(r.globalMetadata!==void 0&&(typeof r.globalMetadata!="object"||r.globalMetadata===null))throw a.clientError("ConfigValidation","Global metadata must be an object",{provided:r.globalMetadata,type:typeof r.globalMetadata}),new L(I.INVALID_GLOBAL_METADATA,"config");if(r.scrollContainerSelectors!==void 0&&wt(r.scrollContainerSelectors),r.integrations&&At(r.integrations),r.sensitiveQueryParams!==void 0){if(!Array.isArray(r.sensitiveQueryParams))throw a.clientError("ConfigValidation","Sensitive query params must be an array",{provided:r.sensitiveQueryParams,type:typeof r.sensitiveQueryParams}),new L(I.INVALID_SENSITIVE_QUERY_PARAMS,"config");for(const e of r.sensitiveQueryParams)if(typeof e!="string")throw a.clientError("ConfigValidation","All sensitive query params must be strings",{param:e,type:typeof e}),new L("All sensitive query params must be strings","config")}if(r.errorSampling!==void 0&&(typeof r.errorSampling!="number"||r.errorSampling<0||r.errorSampling>1))throw a.clientError("ConfigValidation","Invalid error sampling rate",{provided:r.errorSampling,expected:"0-1"}),new Tt(I.INVALID_ERROR_SAMPLING_RATE,"config")},_t=r=>{if(r.includes("<")||r.includes(">")||/on\w+\s*=/i.test(r)||!/^[a-zA-Z0-9\-_#.[\]="':, >+~*()]+$/.test(r))return!1;let t=0;for(const s of r)if(s==="("&&t++,s===")"&&t--,t<0)return!1;if(t!==0)return!1;let n=0;for(const s of r)if(s==="["&&n++,s==="]"&&n--,n<0)return!1;return n===0},wt=r=>{const e=Array.isArray(r)?r:[r];for(const t of e){if(typeof t!="string"||t.trim()==="")throw a.clientError("ConfigValidation","Invalid scroll container selector",{selector:t,type:typeof t,isEmpty:t===""||typeof t=="string"&&t.trim()===""}),new L(I.INVALID_SCROLL_CONTAINER_SELECTORS,"config");if(!_t(t))throw a.clientError("ConfigValidation","Invalid or potentially unsafe CSS selector",{selector:t,reason:"Failed security validation"}),new L("Invalid or potentially unsafe CSS selector","config")}},At=r=>{if(r&&r.googleAnalytics){if(!r.googleAnalytics.measurementId||typeof r.googleAnalytics.measurementId!="string"||r.googleAnalytics.measurementId.trim()==="")throw a.clientError("ConfigValidation","Invalid Google Analytics measurement ID",{provided:r.googleAnalytics.measurementId,type:typeof r.googleAnalytics.measurementId}),new Fe(I.INVALID_GOOGLE_ANALYTICS_ID,"config");const e=r.googleAnalytics.measurementId.trim();if(!e.match(/^(G-|UA-)/))throw a.clientError("ConfigValidation",'Google Analytics measurement ID must start with "G-" or "UA-"',{provided:e}),new Fe('Google Analytics measurement ID must start with "G-" or "UA-"',"config")}},bt=r=>{It(r);const e={...r,id:r.id.trim(),globalMetadata:r.globalMetadata??{},sensitiveQueryParams:r.sensitiveQueryParams??[]};if(!e.id)throw a.clientError("ConfigValidation","Project ID is empty after trimming whitespace",{originalId:r.id,normalizedId:e.id}),new ee(I.PROJECT_ID_EMPTY_AFTER_TRIM,"config");return e},Ve=r=>{if(!r||typeof r!="string"||r.trim().length===0)return a.debug("Sanitize","String sanitization skipped - empty or invalid input",{value:r,type:typeof r}),"";const e=r.length;let t=r;r.length>_&&(t=r.slice(0,Math.max(0,_)),a.warn("Sanitize","String truncated due to length limit",{originalLength:e,maxLength:_,truncatedLength:t.length}));let n=0;for(const i of Re){const o=t;t=t.replace(i,""),o!==t&&n++}n>0&&a.warn("Sanitize","XSS patterns detected and removed",{patternMatches:n,originalValue:r.slice(0,100)}),t=t.replaceAll("&","&amp;").replaceAll("<","&lt;").replaceAll(">","&gt;").replaceAll('"',"&quot;").replaceAll("'","&#x27;").replaceAll("/","&#x2F;");const s=t.trim();return(e>50||n>0)&&a.debug("Sanitize","String sanitization completed",{originalLength:e,sanitizedLength:s.length,xssPatternMatches:n,wasTruncated:e>_}),s},Mt=r=>{if(typeof r!="string")return"";r.length>_&&(r=r.slice(0,Math.max(0,_)));let e=r;for(const t of Re)e=e.replace(t,"");return e=e.replaceAll("&","&amp;").replaceAll("<","&lt;").replaceAll(">","&gt;").replaceAll('"',"&quot;").replaceAll("'","&#x27;"),e.trim()},H=(r,e=0)=>{if(e>Me)return a.warn("Sanitize","Maximum object depth exceeded during sanitization",{depth:e,maxDepth:Me}),null;if(r==null)return null;if(typeof r=="string")return Ve(r);if(typeof r=="number")return!Number.isFinite(r)||r<-Number.MAX_SAFE_INTEGER||r>Number.MAX_SAFE_INTEGER?(a.warn("Sanitize","Invalid number sanitized to 0",{value:r,isFinite:Number.isFinite(r)}),0):r;if(typeof r=="boolean")return r;if(Array.isArray(r)){const t=r.length,n=r.slice(0,q);t>q&&a.warn("Sanitize","Array truncated due to length limit",{originalLength:t,maxLength:q,depth:e});const s=n.map(i=>H(i,e+1)).filter(i=>i!==null);return t>0&&s.length===0&&a.warn("Sanitize","All array items were filtered out during sanitization",{originalLength:t,depth:e}),s}if(typeof r=="object"){const t={},n=Object.entries(r),s=n.length,i=n.slice(0,20);s>20&&a.warn("Sanitize","Object keys truncated due to limit",{originalKeys:s,maxKeys:20,depth:e});let o=0;for(const[c,l]of i){const u=Ve(c);if(u){const g=H(l,e+1);g!==null?t[u]=g:o++}else o++}return o>0&&a.debug("Sanitize","Object properties filtered during sanitization",{filteredKeysCount:o,remainingKeys:Object.keys(t).length,depth:e}),t}return a.debug("Sanitize","Unknown value type sanitized to null",{type:typeof r,depth:e}),null},Rt=r=>{a.debug("Sanitize","Starting API config sanitization");const e={};if(typeof r!="object"||r===null)return a.warn("Sanitize","API config data is not an object",{data:r,type:typeof r}),e;try{const t=Object.keys(r);let n=0,s=0;for(const i of t)if(ct.has(i)){const o=r[i];if(i==="excludedUrlPaths"){const c=Array.isArray(o)?o:typeof o=="string"?[o]:[],l=c.length;e.excludedUrlPaths=c.map(g=>Mt(String(g))).filter(Boolean);const u=l-e.excludedUrlPaths.length;u>0&&a.warn("Sanitize","Some excluded URL paths were filtered during sanitization",{originalCount:l,filteredCount:u})}else if(i==="tags")Array.isArray(o)?(e.tags=o,a.debug("Sanitize","Tags processed",{count:o.length})):a.warn("Sanitize","Tags value is not an array",{value:o,type:typeof o});else if(i==="samplingRate"){const c=H(o);typeof c=="number"&&(e.samplingRate=c)}else{const c=H(o);c!==null?e[i]=c:a.warn("Sanitize","API config value sanitized to null",{key:i,originalValue:o})}n++}else s++,a.debug("Sanitize","API config key not allowed",{key:i});a.info("Sanitize","API config sanitization completed",{originalKeys:t.length,processedKeys:n,filteredKeys:s,finalKeys:Object.keys(e).length})}catch(t){throw a.error("Sanitize","API config sanitization failed",{error:t instanceof Error?t.message:t}),new Error(`API config sanitization failed: ${t instanceof Error?t.message:"Unknown error"}`)}return e},Lt=r=>{if(a.debug("Sanitize","Starting metadata sanitization",{hasMetadata:r!=null}),typeof r!="object"||r===null)return a.debug("Sanitize","Metadata is not an object, returning empty object",{metadata:r,type:typeof r}),{};try{const e=Object.keys(r).length,t=H(r),n=typeof t=="object"&&t!==null?t:{},s=Object.keys(n).length;return a.debug("Sanitize","Metadata sanitization completed",{originalKeys:e,finalKeys:s,keysFiltered:e-s}),n}catch(e){throw a.error("Sanitize","Metadata sanitization failed",{error:e instanceof Error?e.message:e}),new Error(`Metadata sanitization failed: ${e instanceof Error?e.message:"Unknown error"}`)}},Nt=r=>{if(typeof r!="object"||r===null)return!1;for(const e of Object.values(r)){if(e==null)continue;const t=typeof e;if(!(t==="string"||t==="number"||t==="boolean")){if(Array.isArray(e)){if(!e.every(n=>typeof n=="string"))return!1;continue}return!1}}return!0},Ct=r=>typeof r!="string"?{valid:!1,error:"Event name must be a string"}:r.length===0?{valid:!1,error:"Event name cannot be empty"}:r.length>_e?{valid:!1,error:`Event name is too long (max ${_e} characters)`}:r.includes("<")||r.includes(">")||r.includes("&")?{valid:!1,error:"Event name contains invalid characters"}:["constructor","prototype","__proto__","eval","function","var","let","const"].includes(r.toLowerCase())?{valid:!1,error:"Event name cannot be a reserved word"}:{valid:!0},ze=(r,e,t)=>{const n=Lt(e),s=`${t} "${r}" metadata error`;if(!Nt(n))return{valid:!1,error:`${s}: object has invalid types. Valid types are string, number, boolean or string arrays.`};let i;try{i=JSON.stringify(n)}catch{return{valid:!1,error:`${s}: object contains circular references or cannot be serialized.`}}if(i.length>we)return{valid:!1,error:`${s}: object is too large (max ${we/1024} KB).`};if(Object.keys(n).length>Ae)return{valid:!1,error:`${s}: object has too many keys (max ${Ae} keys).`};for(const[c,l]of Object.entries(n)){if(Array.isArray(l)){if(l.length>be)return{valid:!1,error:`${s}: array property "${c}" is too large (max ${be} items).`};for(const u of l)if(typeof u=="string"&&u.length>500)return{valid:!1,error:`${s}: array property "${c}" contains strings that are too long (max 500 characters).`}}if(typeof l=="string"&&l.length>_)return{valid:!1,error:`${s}: property "${c}" is too long (max ${_} characters).`}}return{valid:!0,sanitizedMetadata:n}},Pt=(r,e,t)=>{if(Array.isArray(e)){const n=[],s=`${t} "${r}" 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 c=ze(r,o,t);if(!c.valid)return{valid:!1,error:`${s}: array item at index ${i} is invalid: ${c.error}`};c.sanitizedMetadata&&n.push(c.sanitizedMetadata)}return{valid:!0,sanitizedMetadata:n}}return ze(r,e,t)},Ot=(r,e)=>{const t=Ct(r);if(!t.valid)return a.clientError("EventValidation","Event name validation failed",{eventName:r,error:t.error}),t;if(!e)return{valid:!0};const n=Pt(r,e,"customEvent");return n.valid||a.clientError("EventValidation","Event metadata validation failed",{eventName:r,error:n.error}),n},te=(r,e=!1)=>{try{const t=new URL(r),n=t.protocol==="https:",s=t.protocol==="http:";return n||e&&s}catch{return!1}},Dt=(r,e=!1)=>{const t=new URL(window.location.href),n=t.hostname,s=n.split(".");if(s.length===0)throw a.clientError("URLUtils","Invalid hostname - no domain parts found",{hostname:n}),new Error("Invalid URL");const i=s.slice(-2).join("."),c=`${e&&t.protocol==="http:"?"http":"https"}://${r}.${i}`;if(!te(c,e))throw a.clientError("URLUtils","Generated API URL failed validation",{apiUrl:c,allowHttp:e}),new Error("Invalid URL");return c},re=(r,e=[])=>{try{const t=new URL(r),n=t.searchParams,s=Array.from(n.keys()).length;let i=!1;const o=[];return e.forEach(l=>{n.has(l)&&(n.delete(l),i=!0,o.push(l))}),i&&a.debug("URLUtils","Sensitive parameters removed from URL",{removedParams:o,originalParamCount:s,finalParamCount:Array.from(n.keys()).length}),!i&&r.includes("?")?r:(t.search=n.toString(),t.toString())}catch(t){return a.warn("URLUtils","URL normalization failed, returning original",{url:r.slice(0,100),error:t instanceof Error?t.message:t}),r}},kt=(r,e=[])=>{if(e.length===0)return!1;let t;try{const l=new URL(r,window.location.origin);t=l.pathname+(l.hash??"")}catch(l){return a.warn("URLUtils","Failed to parse URL for path exclusion check",{url:r.slice(0,100),error:l instanceof Error?l.message:l}),!1}const n=l=>typeof l=="object"&&l!==void 0&&typeof l.test=="function",s=l=>l.replaceAll(/[$()*+.?[\\\]^{|}]/g,"\\$&"),i=l=>new RegExp("^"+l.split("*").map(u=>s(u)).join(".+")+"$");return!!e.find(l=>{try{return n(l)?l.test(t):l.includes("*")?i(l).test(t):l===t}catch(u){return a.warn("URLUtils","Error testing exclusion pattern",{pattern:l,path:t,error:u instanceof Error?u.message:u}),!1}})};async function Ut(r,e={}){const{timeout:t=1e4,...n}=e,s=new AbortController,i=setTimeout(()=>{s.abort()},t);try{const o=await fetch(r,{...n,signal:s.signal});return clearTimeout(i),o}catch(o){throw clearTimeout(i),o instanceof Error&&o.name==="AbortError"?new Error(`Request timeout after ${t}ms`):o}}class xt{listeners=new Map;on(e,t){this.listeners.has(e)||this.listeners.set(e,[]),this.listeners.get(e).push(t)}off(e,t){const n=this.listeners.get(e);if(n){const s=n.indexOf(t);s>-1&&n.splice(s,1)}}emit(e,t){const n=this.listeners.get(e);n&&n.forEach(s=>s(t))}removeAllListeners(){this.listeners.clear()}}function Ht(r,e=!1){try{if(r===m.Localhost||r===m.Fail){const n=`http://${r}`;if(!te(n,!0))throw new Error(`Invalid localhost URL format: ${r}`);return n}const t=Dt(r,e);if(!te(t,e))throw new Error(`Generated API URL failed validation: ${t}`);return t}catch(t){throw a.error("ApiManager","API URL generation failed",{projectId:r,allowHttp:e,error:t instanceof Error?t.message:t}),t}}class Ge{static build(e,t={}){const n=this.resolveMode(e,t.mode),s={id:e.id,sessionTimeout:this.resolveSessionTimeout(e.sessionTimeout),mode:n,samplingRate:this.resolveSamplingRate(t.samplingRate,e.samplingRate),errorSampling:this.resolveErrorSampling(e.errorSampling,n),excludedUrlPaths:t.excludedUrlPaths??e.excludedUrlPaths??[],tags:t.tags??[],ipExcluded:t.ipExcluded??!1,globalMetadata:e.globalMetadata??{},scrollContainerSelectors:e.scrollContainerSelectors,sensitiveQueryParams:e.sensitiveQueryParams??[],integrations:e.integrations,allowHttp:e.allowHttp??!1};return a.debug("ConfigBuilder","Configuration built",{projectId:s.id,mode:s.mode,samplingRate:s.samplingRate,errorSampling:s.errorSampling,hasTags:!!s.tags?.length,hasExclusions:!!s.excludedUrlPaths?.length}),s}static resolveSessionTimeout(e){return e===void 0?P:e<O||e>D?(a.warn("ConfigBuilder","Invalid session timeout, using default",{provided:e,min:O,max:D,default:P}),P):e}static resolveSamplingRate(e,t){const n=e??t;return n===void 0?b:n<st||n>it?(a.warn("ConfigBuilder","Invalid sampling rate, using default",{provided:n,default:b}),b):n}static resolveErrorSampling(e,t){return t===R.DEBUG||t===R.QA?e??1:e??.1}static resolveMode(e,t){return e.id===m.Skip||e.id===m.Fail||e.id.toLowerCase().startsWith("skip-")?R.DEBUG:t??e.mode}}class Ft{static PRODUCTION_DOMAINS=[/^https:\/\/.*\.tracelog\.app$/,/^https:\/\/.*\.tracelog\.dev$/];async get(e,t){if(t.id===m.Skip||t.id===m.Fail||t.id.toLowerCase().startsWith("skip-"))return this.createDefaultConfig(t);const n=await this.loadFromApi(e,t),s=this.applyQaModeIfEnabled(n),i=Ge.build(t,s);return a.info("ConfigManager","Configuration loaded",{projectId:i.id,mode:i.mode,hasTags:!!i.tags?.length,hasExclusions:!!i.excludedUrlPaths?.length}),i}async loadFromApi(e,t){try{const n=this.buildConfigUrl(e,t),s=this.buildHeaders(t),i=await Ut(n,{method:"GET",headers:s,timeout:ve});if(!i.ok)throw new Error(`HTTP ${i.status}: ${i.statusText}`);const o=await this.parseJsonResponse(i),c=Rt(o);return{...c,excludedUrlPaths:c.excludedUrlPaths??k.excludedUrlPaths,tags:c.tags??k.tags}}catch(n){const s=n instanceof Error?n.message:"Unknown error";throw a.error("ConfigManager","Failed to load configuration",{error:s,apiUrl:e,projectId:t.id}),new Error(`Configuration load failed: ${s}`)}}buildConfigUrl(e,t){if(t.id===m.Localhost||t.id===m.Fail)return`http://${t.id}/config`;const s=`${e}/config`;return this.isQaModeEnabled()?`${s}?qaMode=true`:s}buildHeaders(e){return{"Content-Type":"application/json","X-TraceLog-Project":e.id}}async parseJsonResponse(e){if(!e.headers.get("content-type")?.includes("application/json"))throw new Error("Invalid response content-type, expected JSON");const n=await e.json();if(!n||typeof n!="object"||Array.isArray(n))throw new Error("Invalid response format, expected object");return n}isQaModeEnabled(){return new URLSearchParams(window.location.search).get("qaMode")==="true"}applyQaModeIfEnabled(e){return this.isQaModeEnabled()&&!e.mode?(a.info("ConfigManager","QA mode enabled via URL parameter"),{...e,mode:R.QA}):e}createDefaultConfig(e){const t={tags:k.tags,ipExcluded:k.ipExcluded,...e.samplingRate===void 0&&{samplingRate:k.samplingRate}};return Ge.build(e,t)}}class Vt extends S{storeManager;retryTimeoutId=null;retryCount=0;isRetrying=!1;constructor(e){super(),this.storeManager=e}getQueueStorageKey(){const e=this.get("config")?.id||"default",t=this.get("userId")||"anonymous";return`${dt(e)}:${t}`}sendEventsQueueSync(e){if(this.shouldSkipSend())return this.resetRetryState(),!0;if(this.get("config")?.id===m.Fail)return a.warn("SenderManager","Fail mode: simulating network failure (sync)",{events:e.events.length}),!1;const n=this.sendQueueSyncInternal(e);return n&&this.resetRetryState(),n}async sendEventsQueue(e,t){!this.persistEvents(e)&&!this.shouldSkipSend()&&a.warn("SenderManager","Failed to persist events, attempting immediate send");const s=await this.send(e);return s?(this.clearPersistedEvents(),this.resetRetryState(),t?.onSuccess?.(e.events.length,e.events,e)):(this.scheduleRetry(e,t),t?.onFailure?.()),s}async recoverPersistedEvents(e){try{const t=this.getPersistedData();if(!t||!this.isDataRecent(t)||t.events.length===0){this.clearPersistedEvents();return}const n=this.createRecoveryBody(t);await this.send(n)?(this.clearPersistedEvents(),this.resetRetryState(),e?.onSuccess?.(t.events.length,t.events,n)):(this.scheduleRetry(n,e),e?.onFailure?.())}catch(t){a.error("SenderManager","Failed to recover persisted events",{error:t}),this.clearPersistedEvents()}}persistEventsForRecovery(e){return this.persistEvents(e)}async sendEventsQueueAsync(e){return this.sendEventsQueue(e)}stop(){this.clearRetryTimeout(),this.resetRetryState()}async send(e){if(this.shouldSkipSend())return this.simulateSuccessfulSend();if(this.get("config")?.id===m.Fail)return a.warn("SenderManager","Fail mode: simulating network failure",{events:e.events.length}),!1;const{url:n,payload:s}=this.prepareRequest(e);try{return(await this.sendWithTimeout(n,s)).ok}catch(i){const o=i instanceof Error?i.message:String(i);return a.error("SenderManager","Send request failed",{error:o,events:e.events.length,url:n.replace(/\/\/[^/]+/,"//[DOMAIN]")}),!1}}async sendWithTimeout(e,t){const n=new AbortController,s=setTimeout(()=>n.abort(),ve),i=this.get("config");try{const o=await fetch(e,{method:"POST",headers:{"Content-Type":"application/json","X-TraceLog-Project":i?.id||"unknown"},body:t,keepalive:!0,credentials:"include",signal:n.signal});if(!o.ok)throw new Error(`HTTP ${o.status}: ${o.statusText}`);return o}finally{clearTimeout(s)}}sendQueueSyncInternal(e){const{url:t,payload:n}=this.prepareRequest(e),s=new Blob([n],{type:"application/json"});if(this.isSendBeaconAvailable()){if(navigator.sendBeacon(t,s))return!0;a.warn("SenderManager","sendBeacon failed, persisting events for recovery")}else a.warn("SenderManager","sendBeacon not available, persisting events for recovery");return this.persistEventsForRecovery(e),!1}prepareRequest(e){const t=`${this.get("apiUrl")}/collect`,n={...e,_metadata:{referer:typeof window<"u"?window.location.href:void 0,timestamp:Date.now()}};return{url:t,payload:JSON.stringify(n)}}getPersistedData(){try{const e=this.getQueueStorageKey(),t=this.storeManager.getItem(e);if(t)return JSON.parse(t)}catch(e){a.warn("SenderManager","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)<tt}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}},n=this.getQueueStorageKey();return this.storeManager.setItem(n,JSON.stringify(t)),!!this.storeManager.getItem(n)}catch(t){return a.warn("SenderManager","Failed to persist events",{error:t}),!1}}clearPersistedEvents(){try{const e=this.getQueueStorageKey();this.storeManager.removeItem(e)}catch(e){a.warn("SenderManager","Failed to clear persisted events",{error:e})}}resetRetryState(){this.retryCount=0,this.isRetrying=!1,this.clearRetryTimeout()}scheduleRetry(e,t){if(this.retryTimeoutId!==null||this.isRetrying)return;if(this.retryCount>=pe){a.warn("SenderManager","Max retries reached, giving up",{retryCount:this.retryCount}),this.clearPersistedEvents(),this.resetRetryState(),t?.onFailure?.();return}const n=rt*Math.pow(2,this.retryCount);this.isRetrying=!0,this.retryTimeoutId=window.setTimeout(async()=>{this.retryTimeoutId=null,this.retryCount++;try{await this.send(e)?(this.clearPersistedEvents(),this.resetRetryState(),t?.onSuccess?.(e.events.length)):this.retryCount>=pe?(this.clearPersistedEvents(),this.resetRetryState(),t?.onFailure?.()):this.scheduleRetry(e,t)}finally{this.isRetrying=!1}},n),a.debug("SenderManager","Retry scheduled",{attempt:this.retryCount+1,delay:n,events:e.events.length})}shouldSkipSend(){const e=this.get("config"),{id:t}=e||{};return t===m.Skip}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"}clearRetryTimeout(){this.retryTimeoutId!==null&&(clearTimeout(this.retryTimeoutId),this.retryTimeoutId=null)}}class zt extends S{googleAnalytics;dataSender;emitter;eventsQueue=[];lastEventFingerprint=null;lastEventTime=0;sendIntervalId=null;constructor(e,t=null,n=null){super(),this.googleAnalytics=t,this.dataSender=new Vt(e),this.emitter=n}async recoverPersistedEvents(){await this.dataSender.recoverPersistedEvents({onSuccess:(e,t,n)=>{if(t&&t.length>0){const s=t.map(i=>i.timestamp+"_"+i.type);this.removeProcessedEvents(s),n&&this.emitEventsQueue(n)}},onFailure:async()=>{a.warn("EventManager","Failed to recover persisted events")}})}track({type:e,page_url:t,from_page_url:n,scroll_data:s,click_data:i,custom_event:o,web_vitals:c,error_data:l,session_end_reason:u}){if(!e){a.warn("EventManager","Event type is required");return}const g=e,z=g===h.SESSION_START,Nr=g===h.SESSION_END,Cr=z||Nr,Pr=t||this.get("pageUrl"),me=this.buildEventPayload({type:g,page_url:Pr,from_page_url:n,scroll_data:s,click_data:i,custom_event:o,web_vitals:c,error_data:l,session_end_reason:u});if(!this.isEventExcluded(me)&&!(!Cr&&!this.shouldSample())){if(z){const Je=this.get("sessionId");if(!Je){a.warn("EventManager","Session start event ignored: missing sessionId");return}if(this.get("hasStartSession")){a.warn("EventManager","Duplicate session_start detected",{sessionId:Je});return}this.set("hasStartSession",!0)}this.isDuplicateEvent(me)||this.addToQueue(me)}}stop(){this.sendIntervalId&&(clearInterval(this.sendIntervalId),this.sendIntervalId=null),this.eventsQueue=[],this.lastEventFingerprint=null,this.lastEventTime=0,this.dataSender.stop()}async flushImmediately(){return this.flushEvents(!1)}flushImmediatelySync(){return this.flushEvents(!0)}getQueueLength(){return this.eventsQueue.length}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(),n=[...this.eventsQueue],s=n.map(i=>`${i.timestamp}_${i.type}`);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("EventManager","Async flush failed",{eventCount:n.length})}})}async sendEventsQueue(){if(!this.get("sessionId")||this.eventsQueue.length===0)return;const e=this.buildEventsPayload(),t=[...this.eventsQueue],n=t.map(s=>`${s.timestamp}_${s.type}`);await this.dataSender.sendEventsQueue(e,{onSuccess:()=>{this.removeProcessedEvents(n),this.emitEventsQueue(e)},onFailure:async()=>{a.warn("EventManager","Events send failed, keeping in queue",{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 n=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:n,...this.get("config")?.globalMetadata&&{global_metadata:this.get("config")?.globalMetadata}}}buildEventPayload(e){const t=e.type===h.SESSION_START,n=e.page_url??this.get("pageUrl"),s={type:e.type,page_url:n,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},...t&&ke()&&{utm:ke()}},i=this.get("config")?.tags;return i?.length&&(s.tags=i),s}isEventExcluded(e){const t=this.get("config"),n=kt(e.page_url,t?.excludedUrlPaths??[]),s=this.get("hasStartSession"),i=e.type===h.SESSION_END,o=e.type===h.SESSION_START;return n&&!o&&!(i&&s)?!0:t?.ipExcluded===!0}isDuplicateEvent(e){const t=Date.now(),n=this.createEventFingerprint(e);return this.lastEventFingerprint===n&&t-this.lastEventTime<Ze?!0:(this.lastEventFingerprint=n,this.lastEventTime=t,!1)}createEventFingerprint(e){let t=`${e.type}_${e.page_url}`;if(e.click_data){const n=Math.round((e.click_data.x||0)/10)*10,s=Math.round((e.click_data.y||0)/10)*10;t+=`_click_${n}_${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>Ee){const t=this.eventsQueue.findIndex(s=>s.type!==h.SESSION_START&&s.type!==h.SESSION_END),n=t>=0?this.eventsQueue.splice(t,1)[0]:this.eventsQueue.shift();a.warn("EventManager","Event queue overflow, oldest non-critical event removed",{maxLength:Ee,currentLength:this.eventsQueue.length,removedEventType:n?.type,wasCritical:n?.type===h.SESSION_START||n?.type===h.SESSION_END})}this.sendIntervalId||this.startSendInterval(),this.handleGoogleAnalyticsIntegration(e)}startSendInterval(){this.sendIntervalId=window.setInterval(()=>{this.eventsQueue.length>0&&this.sendEventsQueue()},et)}handleGoogleAnalyticsIntegration(e){if(this.googleAnalytics&&e.type===h.CUSTOM&&e.custom_event){if(this.get("config")?.mode==="qa"||this.get("config")?.mode==="debug")return;this.googleAnalytics.trackEvent(e.custom_event.name,e.custom_event.metadata??{})}}shouldSample(){const e=this.get("config")?.samplingRate??1;return Math.random()<e}removeProcessedEvents(e){const t=new Set(e);this.eventsQueue=this.eventsQueue.filter(n=>{const s=`${n.timestamp}_${n.type}`;return!t.has(s)})}emitEvent(e){this.emitter&&this.emitter.emit(Z.EVENT,e)}emitEventsQueue(e){this.emitter&&this.emitter.emit(Z.QUEUE,e)}}class Gt{static getId(e,t){const n=ut(t??""),s=e.getItem(n);if(s)return s;const i=vt();return e.setItem(n,i),i}}class jt extends S{storageManager;eventManager;projectId;sessionTimeoutId=null;broadcastChannel=null;activityHandler=null;visibilityChangeHandler=null;beforeUnloadHandler=null;isTracking=!1;constructor(e,t,n){super(),this.storageManager=e,this.eventManager=t,this.projectId=n}initCrossTabSync(){if(typeof BroadcastChannel>"u"){a.warn("SessionManager","BroadcastChannel not supported");return}const e=this.getProjectId();this.broadcastChannel=new BroadcastChannel(gt(e)),this.broadcastChannel.onmessage=t=>{const{action:n,sessionId:s,timestamp:i,projectId:o}=t.data??{};if(o===e){if(n==="session_end"){a.debug("SessionManager","Session end synced from another tab"),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(),a.debug("SessionManager","Session synced from another tab",{sessionId:s}))}}}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){e&&this.broadcastChannel&&typeof this.broadcastChannel.postMessage=="function"&&this.broadcastChannel.postMessage({action:"session_end",projectId:this.getProjectId(),sessionId:e,reason:t,timestamp:Date.now()})}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??P;return Date.now()-e.lastActivity>t?(a.debug("SessionManager","Stored session expired"),this.clearStoredSession(),null):(a.info("SessionManager","Session recovered from storage",{sessionId:e.id}),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 n=JSON.parse(t);return!n.id||typeof n.lastActivity!="number"?null:n}catch{return this.storageManager.removeItem(e),null}}saveStoredSession(e){const t=this.getSessionStorageKey();this.storageManager.setItem(t,JSON.stringify(e))}getSessionStorageKey(){return ht(this.getProjectId())}getProjectId(){return this.projectId}async startTracking(){if(this.isTracking){a.warn("SessionManager","Session tracking already active");return}const e=this.recoverSession(),t=e??this.generateSessionId(),n=!!e;this.isTracking=!0;try{this.set("sessionId",t),this.persistSession(t),n||this.eventManager.track({type:h.SESSION_START}),this.initCrossTabSync(),this.shareSession(t),this.setupSessionTimeout(),this.setupActivityListeners(),this.setupLifecycleListeners(),a.info("SessionManager","Session tracking started",{sessionId:t,recovered:n})}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??P;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)}async endSession(e){const t=this.get("sessionId");if(!t){a.warn("SessionManager","endSession called without active session",{reason:e}),this.resetSessionState(e);return}a.info("SessionManager","Ending session",{sessionId:t,reason:e}),this.eventManager.track({type:h.SESSION_END,session_end_reason:e});const n=()=>{this.broadcastSessionEnd(t,e),this.resetSessionState(e)};if(this.eventManager.flushImmediatelySync()){n();return}try{await this.eventManager.flushImmediately(),n()}catch(i){a.warn("SessionManager","Async flush failed during session end",{error:i instanceof Error?i.message:"Unknown error"}),n()}}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}async stopTracking(){await this.endSession("manual_stop")}destroy(){this.clearSessionTimeout(),this.cleanupActivityListeners(),this.cleanupCrossTabSync(),this.cleanupLifecycleListeners(),this.isTracking=!1,this.set("hasStartSession",!1)}}class $t extends S{eventManager;storageManager;sessionManager=null;destroyed=!1;constructor(e,t){super(),this.eventManager=t,this.storageManager=e}async startTracking(){if(this.isActive())return;if(this.destroyed){a.warn("SessionHandler","Cannot start tracking on destroyed handler");return}const e=this.get("config")?.id;if(!e)throw new Error("Cannot start session tracking: config not available");try{this.sessionManager=new jt(this.storageManager,this.eventManager,e),await this.sessionManager.startTracking()}catch(t){if(this.sessionManager){try{this.sessionManager.destroy()}catch{}this.sessionManager=null}throw a.error("SessionHandler","Failed to start session tracking",{error:t instanceof Error?t.message:"Unknown error"}),t}}isActive(){return this.sessionManager!==null&&!this.destroyed}async cleanupSessionManager(){this.sessionManager&&(await this.sessionManager.stopTracking(),this.sessionManager.destroy(),this.sessionManager=null)}async stopTracking(){await this.cleanupSessionManager()}destroy(){this.destroyed||(this.sessionManager&&(this.sessionManager.destroy(),this.sessionManager=null),this.destroyed=!0,this.set("hasStartSession",!1))}}class Qt extends S{eventManager;onTrack;originalPushState;originalReplaceState;constructor(e,t){super(),this.eventManager=e,this.onTrack=t}startTracking(){a.debug("PageViewHandler","Starting page view tracking"),this.trackInitialPageView(),window.addEventListener("popstate",this.trackCurrentPage,!0),window.addEventListener("hashchange",this.trackCurrentPage,!0),this.patchHistory("pushState"),this.patchHistory("replaceState")}stopTracking(){a.debug("PageViewHandler","Stopping page view tracking"),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)}patchHistory(e){const t=window.history[e];e==="pushState"&&!this.originalPushState?this.originalPushState=t:e==="replaceState"&&!this.originalReplaceState&&(this.originalReplaceState=t),window.history[e]=(...n)=>{t.apply(window.history,n),this.trackCurrentPage()}}trackCurrentPage=async()=>{const e=window.location.href,t=re(e,this.get("config").sensitiveQueryParams);if(this.get("pageUrl")===t)return;this.onTrack();const n=this.get("pageUrl");a.debug("PageViewHandler","Page navigation detected",{from:n,to:t}),this.set("pageUrl",t);const s=this.extractPageViewData();this.eventManager.track({type:h.PAGE_VIEW,page_url:this.get("pageUrl"),from_page_url:n,...s&&{page_view:s}})};trackInitialPageView(){const e=re(window.location.href,this.get("config").sensitiveQueryParams),t=this.extractPageViewData();this.eventManager.track({type:h.PAGE_VIEW,page_url:e,...t&&{page_view:t}}),this.onTrack()}extractPageViewData(){const{pathname:e,search:t,hash:n}=window.location,{referrer:s}=document,{title:i}=document;return!s&&!i&&!e&&!t&&!n?void 0:{...s&&{referrer:s},...i&&{title:i},...e&&{pathname:e},...t&&{search:t},...n&&{hash:n}}}}class Bt extends S{eventManager;clickHandler;constructor(e){super(),this.eventManager=e}startTracking(){this.clickHandler||(this.clickHandler=e=>{const t=e,n=t.target,s=n instanceof HTMLElement?n:n instanceof Node&&n.parentElement instanceof HTMLElement?n.parentElement:null;if(!s){a.warn("ClickHandler","Click target not found or not an element");return}const i=this.findTrackingElement(s),o=this.getRelevantClickElement(s),c=this.calculateClickCoordinates(t,s);if(i){const u=this.extractTrackingData(i);if(u){const g=this.createCustomEventData(u);this.eventManager.track({type:h.CUSTOM,custom_event:{name:g.name,...g.value&&{metadata:{value:g.value}}}})}}const l=this.generateClickData(s,o,c);this.eventManager.track({type:h.CLICK,click_data:l})},window.addEventListener("click",this.clickHandler,!0))}stopTracking(){this.clickHandler&&(window.removeEventListener("click",this.clickHandler,!0),this.clickHandler=void 0)}findTrackingElement(e){return e.hasAttribute(`${G}-name`)?e:e.closest(`[${G}-name]`)||void 0}getRelevantClickElement(e){for(const t of at)try{if(e.matches(t))return e;const n=e.closest(t);if(n)return n}catch(n){a.warn("ClickHandler","Invalid selector in element search",{selector:t,error:n instanceof Error?n.message:"Unknown error"});continue}return e}clamp(e){return Math.max(0,Math.min(1,Number(e.toFixed(3))))}calculateClickCoordinates(e,t){const n=t.getBoundingClientRect(),s=e.clientX,i=e.clientY,o=n.width>0?this.clamp((s-n.left)/n.width):0,c=n.height>0?this.clamp((i-n.top)/n.height):0;return{x:s,y:i,relativeX:o,relativeY:c}}extractTrackingData(e){const t=e.getAttribute(`${G}-name`),n=e.getAttribute(`${G}-value`);if(t)return{element:e,name:t,...n&&{value:n}}}generateClickData(e,t,n){const{x:s,y:i,relativeX:o,relativeY:c}=n,l=this.getRelevantText(e,t),u=this.extractElementAttributes(t);return{x:s,y:i,relativeX:o,relativeY:c,tag:t.tagName.toLowerCase(),...t.id&&{id:t.id},...t.className&&{class:t.className},...l&&{text:l},...u.href&&{href:u.href},...u.title&&{title:u.title},...u.alt&&{alt:u.alt},...u.role&&{role:u.role},...u["aria-label"]&&{ariaLabel:u["aria-label"]},...Object.keys(u).length>0&&{dataAttributes:u}}}getRelevantText(e,t){const n=e.textContent?.trim()??"",s=t.textContent?.trim()??"";return!n&&!s?"":n&&n.length<=X?n:s.length<=X?s:s.slice(0,X-3)+"..."}extractElementAttributes(e){const t=["id","class","data-testid","aria-label","title","href","type","name","alt","role"],n={};for(const s of t){const i=e.getAttribute(s);i&&(n[s]=i)}return n}createCustomEventData(e){return{name:e.name,...e.value&&{value:e.value}}}}class Wt extends S{eventManager;containers=[];limitWarningLogged=!1;minDepthChange=ye;minIntervalMs=Te;maxEventsPerSession=Ie;constructor(e){super(),this.eventManager=e}startTracking(){this.limitWarningLogged=!1,this.applyConfigOverrides(),this.set("scrollEventCount",0);const e=this.get("config").scrollContainerSelectors,t=Array.isArray(e)?e:typeof e=="string"?[e]:[];t.length===0?this.setupScrollContainer(window):this.trySetupContainers(t,0)}stopTracking(){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}trySetupContainers(e,t){const n=e.map(s=>this.safeQuerySelector(s)).filter(s=>s instanceof HTMLElement);if(n.length>0){for(const s of n)this.containers.some(o=>o.element===s)||this.setupScrollContainer(s);return}if(t<5){setTimeout(()=>this.trySetupContainers(e,t+1),200);return}this.containers.length===0&&this.setupScrollContainer(window)}setupScrollContainer(e){if(e!==window&&!this.isElementScrollable(e))return;const t=()=>{this.get("suppressNextScroll")||(this.clearContainerTimer(s),s.debounceTimer=window.setTimeout(()=>{const i=this.calculateScrollData(s);if(i){const o=Date.now();this.processScrollEvent(s,i,o)}s.debounceTimer=null},Se))},n=this.getScrollTop(e),s={element:e,lastScrollPos:n,lastDepth:this.calculateScrollDepth(n,this.getScrollHeight(e),this.getViewportHeight(e)),lastDirection:U.DOWN,lastEventTime:0,debounceTimer:null,listener:t};this.containers.push(s),e instanceof Window?window.addEventListener("scroll",t,{passive:!0}):e.addEventListener("scroll",t,{passive:!0})}processScrollEvent(e,t,n){if(!this.shouldEmitScrollEvent(e,t,n))return;e.lastEventTime=n,e.lastDepth=t.depth,e.lastDirection=t.direction;const s=this.get("scrollEventCount")??0;this.set("scrollEventCount",s+1),this.eventManager.track({type:h.SCROLL,scroll_data:t})}shouldEmitScrollEvent(e,t,n){return this.hasReachedSessionLimit()?(this.logLimitOnce(),!1):!(!this.hasElapsedMinimumInterval(e,n)||!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("ScrollHandler","Max scroll events per session reached",{limit:this.maxEventsPerSession}))}applyConfigOverrides(){this.minDepthChange=ye,this.minIntervalMs=Te,this.maxEventsPerSession=Ie}isWindowScrollable(){return document.documentElement.scrollHeight>window.innerHeight}clearContainerTimer(e){e.debounceTimer!==null&&(clearTimeout(e.debounceTimer),e.debounceTimer=null)}getScrollDirection(e,t){return e>t?U.DOWN:U.UP}calculateScrollDepth(e,t,n){if(t<=n)return 0;const s=t-n;return Math.min(100,Math.max(0,Math.floor(e/s*100)))}calculateScrollData(e){const{element:t,lastScrollPos:n}=e,s=this.getScrollTop(t);if(Math.abs(s-n)<nt||t===window&&!this.isWindowScrollable())return null;const o=this.getViewportHeight(t),c=this.getScrollHeight(t),l=this.getScrollDirection(s,n),u=this.calculateScrollDepth(s,c,o);return e.lastScrollPos=s,{depth:u,direction:l}}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),n=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 n&&s}safeQuerySelector(e){try{return document.querySelector(e)}catch(t){return a.clientWarn("ScrollHandler","Invalid CSS selector",{selector:e,error:t instanceof Error?t.message:"Unknown error"}),null}}}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(n){a.error("GoogleAnalyticsIntegration","Initialization failed",{error:n instanceof Error?n.message:"Unknown error"})}}trackEvent(e,t){if(!(!e?.trim()||!this.isInitialized||typeof window.gtag!="function"))try{const n=Array.isArray(t)?{items:t}:t;window.gtag("event",e,n)}catch(n){a.error("GoogleAnalyticsIntegration","Event tracking failed",{error:n instanceof Error?n.message:"Unknown error"})}}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,n)=>{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=()=>n(new Error("Failed to load Google Analytics script")),document.head.appendChild(s)})}configureGtag(e,t){const n=document.createElement("script");n.innerHTML=`
1
+ (function(h){"use strict";var T=(r=>(r.Mobile="mobile",r.Tablet="tablet",r.Desktop="desktop",r.Unknown="unknown",r))(T||{});const P=15*60*1e3,Ze=500,et=1e4,Se=250,tt=24,Ee=100,pe=3,rt=5e3,ve=1e4,nt=10,ye=5,Te=500,Ie=120,b=1,st=0,it=1,O=3e4,D=864e5,_e=120,we=8*1024,Ae=10,be=10,X=255,_=1e3,q=100,Me=3,A=2,G="data-tl",at=["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"]'],ot=["utm_source","utm_medium","utm_campaign","utm_term","utm_content"],lt=2,ct=new Set(["mode","tags","samplingRate","excludedUrlPaths","ipExcluded"]),I={MISSING_PROJECT_ID:"Project ID is required",PROJECT_ID_EMPTY_AFTER_TRIM:"Project ID is required",INVALID_SESSION_TIMEOUT:`Session timeout must be between ${O}ms (30 seconds) and ${D}ms (24 hours)`,INVALID_ERROR_SAMPLING_RATE:"Error sampling must be between 0 and 1",INVALID_GOOGLE_ANALYTICS_ID:"Google Analytics measurement ID is required when integration is enabled",INVALID_SCROLL_CONTAINER_SELECTORS:"Scroll container selectors must be valid CSS selectors",INVALID_GLOBAL_METADATA:"Global metadata must be an object",INVALID_SENSITIVE_QUERY_PARAMS:"Sensitive query params must be an array of strings"},Re=[/<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi,/javascript:/gi,/on\w+\s*=/gi,/<iframe\b[^<]*(?:(?!<\/iframe>)<[^<]*)*<\/iframe>/gi,/<embed\b[^>]*>/gi,/<object\b[^<]*(?:(?!<\/object>)<[^<]*)*<\/object>/gi],k={samplingRate:b,excludedUrlPaths:[],tags:[],ipExcluded:!1},w="tl",ut=r=>r?`${w}:${r}:uid`:`${w}:uid`,dt=r=>r?`${w}:${r}:queue`:`${w}:queue`,ht=r=>r?`${w}:${r}:session`:`${w}:session`,gt=r=>r?`${w}:${r}:broadcast`:`${w}:broadcast`,Le={LCP:4e3,FCP:1800,CLS:.25,INP:200,TTFB:800,LONG_TASK:50},ft=1e3,Ne=[/\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],Ce=500,Pe=5e3,j=50,Oe=j*2,E={};function mt(){return E}class S{get(e){return E[e]}set(e,t){const n=E[e];if(e==="config"&&t){const s=t;if(s){const i=s.samplingRate??b,o=i<0||i>1?b:i;if(o!==i){const l={...s,samplingRate:o};E[e]=l}else E[e]=s}else E[e]=t}else E[e]=t;this.isCriticalStateKey(e)&&this.shouldLog(n,E[e])&&a.debug("StateManager","State updated",{key:e,oldValue:this.formatLogValue(e,n),newValue:this.formatLogValue(e,E[e])})}getState(){return{...E}}isCriticalStateKey(e){return e==="sessionId"||e==="config"||e==="hasStartSession"}shouldLog(e,t){return e!==t}formatLogValue(e,t){return e==="config"?t?"(configured)":"(not configured)":t}}class St{clientError=(e,t,n)=>this.log("CLIENT_ERROR",e,t,n);clientWarn=(e,t,n)=>this.log("CLIENT_WARN",e,t,n);info=(e,t,n)=>this.log("INFO",e,t,n);error=(e,t,n)=>this.log("ERROR",e,t,n);warn=(e,t,n)=>this.log("WARN",e,t,n);debug=(e,t,n)=>this.log("DEBUG",e,t,n);verbose=(e,t,n)=>this.log("VERBOSE",e,t,n);log(e,t,n,s){const i=mt()?.config?.mode;if(!this.shouldShow(e,i))return;const o=`[TraceLog:${t}] ${n}`,c=this.getMethod(e);s!==void 0?console[c](o,s):console[c](o)}shouldShow(e,t){return["CLIENT_ERROR","ERROR"].includes(e)?!0:t?t==="qa"?["INFO","CLIENT_ERROR","CLIENT_WARN"].includes(e):t==="debug":e==="CLIENT_WARN"}getMethod(e){return["CLIENT_ERROR","ERROR"].includes(e)?"error":["CLIENT_WARN","WARN"].includes(e)?"warn":"log"}}const a=new St;let J,De;const Et=()=>{typeof window<"u"&&!J&&(J=window.matchMedia("(pointer: coarse)"),De=window.matchMedia("(hover: none)"))},pt=()=>{try{a.debug("DeviceDetector","Starting device detection");const r=navigator;if(r.userAgentData&&typeof r.userAgentData.mobile=="boolean"){if(a.debug("DeviceDetector","Using modern User-Agent Client Hints API",{mobile:r.userAgentData.mobile,platform:r.userAgentData.platform}),r.userAgentData.platform&&/ipad|tablet/i.test(r.userAgentData.platform))return a.debug("DeviceDetector","Device detected as tablet via platform hint"),T.Tablet;const u=r.userAgentData.mobile?T.Mobile:T.Desktop;return a.debug("DeviceDetector","Device detected via User-Agent hints",{result:u}),u}a.debug("DeviceDetector","Using fallback detection methods"),Et();const e=window.innerWidth,t=J?.matches??!1,n=De?.matches??!1,s="ontouchstart"in window||navigator.maxTouchPoints>0,i=navigator.userAgent.toLowerCase(),o=/mobile|android|iphone|ipod|blackberry|iemobile|opera mini/.test(i),c=/tablet|ipad|android(?!.*mobile)/.test(i),l={width:e,hasCoarsePointer:t,hasNoHover:n,hasTouchSupport:s,isMobileUA:o,isTabletUA:c,maxTouchPoints:navigator.maxTouchPoints};return e<=767||o&&s?(a.debug("DeviceDetector","Device detected as mobile",l),T.Mobile):e>=768&&e<=1024||c||t&&n&&s?(a.debug("DeviceDetector","Device detected as tablet",l),T.Tablet):(a.debug("DeviceDetector","Device detected as desktop",l),T.Desktop)}catch(r){return a.warn("DeviceDetector","Device detection failed, defaulting to desktop",{error:r instanceof Error?r.message:r}),T.Desktop}},ke=()=>{a.debug("UTMParams","Extracting UTM parameters from URL",{url:window.location.href,search:window.location.search});const r=new URLSearchParams(window.location.search),e={};ot.forEach(n=>{const s=r.get(n);if(s){const i=n.split("utm_")[1];e[i]=s,a.debug("UTMParams","Found UTM parameter",{param:n,key:i,value:s})}});const t=Object.keys(e).length?e:void 0;return t?a.debug("UTMParams","UTM parameters extracted successfully",{parameterCount:Object.keys(t).length,parameters:Object.keys(t)}):a.debug("UTMParams","No UTM parameters found in URL"),t},vt=()=>typeof crypto<"u"&&crypto.randomUUID?crypto.randomUUID():"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g,r=>{const e=Math.random()*16|0;return(r==="x"?e:e&3|8).toString(16)});var m=(r=>(r.Skip="skip",r.Localhost="localhost:8080",r.Fail="localhost:9999",r))(m||{}),Z=(r=>(r.EVENT="event",r.QUEUE="queue",r))(Z||{}),d=(r=>(r.PAGE_VIEW="page_view",r.CLICK="click",r.SCROLL="scroll",r.SESSION_START="session_start",r.SESSION_END="session_end",r.CUSTOM="custom",r.WEB_VITALS="web_vitals",r.ERROR="error",r))(d||{}),U=(r=>(r.UP="up",r.DOWN="down",r))(U||{}),M=(r=>(r.JS_ERROR="js_error",r.PROMISE_REJECTION="promise_rejection",r))(M||{}),R=(r=>(r.QA="qa",r.DEBUG="debug",r))(R||{}),Ue=(r=>(r.AND="AND",r.OR="OR",r))(Ue||{}),xe=(r=>(r.URL_MATCHES="url_matches",r.ELEMENT_MATCHES="element_matches",r.DEVICE_TYPE="device_type",r.ELEMENT_TEXT="element_text",r.ELEMENT_ATTRIBUTE="element_attribute",r.UTM_SOURCE="utm_source",r.UTM_MEDIUM="utm_medium",r.UTM_CAMPAIGN="utm_campaign",r))(xe||{}),He=(r=>(r.EQUALS="equals",r.CONTAINS="contains",r.STARTS_WITH="starts_with",r.ENDS_WITH="ends_with",r.REGEX="regex",r.GREATER_THAN="greater_than",r.LESS_THAN="less_than",r.EXISTS="exists",r.NOT_EXISTS="not_exists",r))(He||{});class x extends Error{constructor(e,t,n){super(e),this.errorCode=t,this.layer=n,this.name=this.constructor.name,Error.captureStackTrace&&Error.captureStackTrace(this,this.constructor)}}class ee extends x{constructor(e="Project ID is required",t="config"){super(e,"PROJECT_ID_INVALID",t)}}class L extends x{constructor(e,t="config"){super(e,"APP_CONFIG_INVALID",t)}}class yt extends x{constructor(e,t="config"){super(e,"SESSION_TIMEOUT_INVALID",t)}}class Tt extends x{constructor(e,t="config"){super(e,"SAMPLING_RATE_INVALID",t)}}class Fe extends x{constructor(e,t="config"){super(e,"INTEGRATION_INVALID",t)}}const It=r=>{if(!r||typeof r!="object")throw a.clientError("ConfigValidation","Configuration must be an object",{config:r}),new L("Configuration must be an object","config");if(!("id"in r))throw a.clientError("ConfigValidation","Project ID is missing from configuration"),new ee(I.MISSING_PROJECT_ID,"config");if(r.id===null||r.id===void 0||typeof r.id!="string")throw a.clientError("ConfigValidation","Project ID must be a non-empty string",{providedId:r.id,type:typeof r.id}),new ee(I.MISSING_PROJECT_ID,"config");if(r.sessionTimeout!==void 0&&(typeof r.sessionTimeout!="number"||r.sessionTimeout<O||r.sessionTimeout>D))throw a.clientError("ConfigValidation","Invalid session timeout",{provided:r.sessionTimeout,min:O,max:D}),new yt(I.INVALID_SESSION_TIMEOUT,"config");if(r.globalMetadata!==void 0&&(typeof r.globalMetadata!="object"||r.globalMetadata===null))throw a.clientError("ConfigValidation","Global metadata must be an object",{provided:r.globalMetadata,type:typeof r.globalMetadata}),new L(I.INVALID_GLOBAL_METADATA,"config");if(r.scrollContainerSelectors!==void 0&&wt(r.scrollContainerSelectors),r.integrations&&At(r.integrations),r.sensitiveQueryParams!==void 0){if(!Array.isArray(r.sensitiveQueryParams))throw a.clientError("ConfigValidation","Sensitive query params must be an array",{provided:r.sensitiveQueryParams,type:typeof r.sensitiveQueryParams}),new L(I.INVALID_SENSITIVE_QUERY_PARAMS,"config");for(const e of r.sensitiveQueryParams)if(typeof e!="string")throw a.clientError("ConfigValidation","All sensitive query params must be strings",{param:e,type:typeof e}),new L("All sensitive query params must be strings","config")}if(r.errorSampling!==void 0&&(typeof r.errorSampling!="number"||r.errorSampling<0||r.errorSampling>1))throw a.clientError("ConfigValidation","Invalid error sampling rate",{provided:r.errorSampling,expected:"0-1"}),new Tt(I.INVALID_ERROR_SAMPLING_RATE,"config")},_t=r=>{if(r.includes("<")||r.includes(">")||/on\w+\s*=/i.test(r)||!/^[a-zA-Z0-9\-_#.[\]="':, >+~*()]+$/.test(r))return!1;let t=0;for(const s of r)if(s==="("&&t++,s===")"&&t--,t<0)return!1;if(t!==0)return!1;let n=0;for(const s of r)if(s==="["&&n++,s==="]"&&n--,n<0)return!1;return n===0},wt=r=>{const e=Array.isArray(r)?r:[r];for(const t of e){if(typeof t!="string"||t.trim()==="")throw a.clientError("ConfigValidation","Invalid scroll container selector",{selector:t,type:typeof t,isEmpty:t===""||typeof t=="string"&&t.trim()===""}),new L(I.INVALID_SCROLL_CONTAINER_SELECTORS,"config");if(!_t(t))throw a.clientError("ConfigValidation","Invalid or potentially unsafe CSS selector",{selector:t,reason:"Failed security validation"}),new L("Invalid or potentially unsafe CSS selector","config")}},At=r=>{if(r&&r.googleAnalytics){if(!r.googleAnalytics.measurementId||typeof r.googleAnalytics.measurementId!="string"||r.googleAnalytics.measurementId.trim()==="")throw a.clientError("ConfigValidation","Invalid Google Analytics measurement ID",{provided:r.googleAnalytics.measurementId,type:typeof r.googleAnalytics.measurementId}),new Fe(I.INVALID_GOOGLE_ANALYTICS_ID,"config");const e=r.googleAnalytics.measurementId.trim();if(!e.match(/^(G-|UA-)/))throw a.clientError("ConfigValidation",'Google Analytics measurement ID must start with "G-" or "UA-"',{provided:e}),new Fe('Google Analytics measurement ID must start with "G-" or "UA-"',"config")}},bt=r=>{It(r);const e={...r,id:r.id.trim(),globalMetadata:r.globalMetadata??{},sensitiveQueryParams:r.sensitiveQueryParams??[]};if(!e.id)throw a.clientError("ConfigValidation","Project ID is empty after trimming whitespace",{originalId:r.id,normalizedId:e.id}),new ee(I.PROJECT_ID_EMPTY_AFTER_TRIM,"config");return e},Ve=r=>{if(!r||typeof r!="string"||r.trim().length===0)return a.debug("Sanitize","String sanitization skipped - empty or invalid input",{value:r,type:typeof r}),"";const e=r.length;let t=r;r.length>_&&(t=r.slice(0,Math.max(0,_)),a.warn("Sanitize","String truncated due to length limit",{originalLength:e,maxLength:_,truncatedLength:t.length}));let n=0;for(const i of Re){const o=t;t=t.replace(i,""),o!==t&&n++}n>0&&a.warn("Sanitize","XSS patterns detected and removed",{patternMatches:n,originalValue:r.slice(0,100)}),t=t.replaceAll("&","&amp;").replaceAll("<","&lt;").replaceAll(">","&gt;").replaceAll('"',"&quot;").replaceAll("'","&#x27;").replaceAll("/","&#x2F;");const s=t.trim();return(e>50||n>0)&&a.debug("Sanitize","String sanitization completed",{originalLength:e,sanitizedLength:s.length,xssPatternMatches:n,wasTruncated:e>_}),s},Mt=r=>{if(typeof r!="string")return"";r.length>_&&(r=r.slice(0,Math.max(0,_)));let e=r;for(const t of Re)e=e.replace(t,"");return e=e.replaceAll("&","&amp;").replaceAll("<","&lt;").replaceAll(">","&gt;").replaceAll('"',"&quot;").replaceAll("'","&#x27;"),e.trim()},H=(r,e=0)=>{if(e>Me)return a.warn("Sanitize","Maximum object depth exceeded during sanitization",{depth:e,maxDepth:Me}),null;if(r==null)return null;if(typeof r=="string")return Ve(r);if(typeof r=="number")return!Number.isFinite(r)||r<-Number.MAX_SAFE_INTEGER||r>Number.MAX_SAFE_INTEGER?(a.warn("Sanitize","Invalid number sanitized to 0",{value:r,isFinite:Number.isFinite(r)}),0):r;if(typeof r=="boolean")return r;if(Array.isArray(r)){const t=r.length,n=r.slice(0,q);t>q&&a.warn("Sanitize","Array truncated due to length limit",{originalLength:t,maxLength:q,depth:e});const s=n.map(i=>H(i,e+1)).filter(i=>i!==null);return t>0&&s.length===0&&a.warn("Sanitize","All array items were filtered out during sanitization",{originalLength:t,depth:e}),s}if(typeof r=="object"){const t={},n=Object.entries(r),s=n.length,i=n.slice(0,20);s>20&&a.warn("Sanitize","Object keys truncated due to limit",{originalKeys:s,maxKeys:20,depth:e});let o=0;for(const[c,l]of i){const u=Ve(c);if(u){const g=H(l,e+1);g!==null?t[u]=g:o++}else o++}return o>0&&a.debug("Sanitize","Object properties filtered during sanitization",{filteredKeysCount:o,remainingKeys:Object.keys(t).length,depth:e}),t}return a.debug("Sanitize","Unknown value type sanitized to null",{type:typeof r,depth:e}),null},Rt=r=>{a.debug("Sanitize","Starting API config sanitization");const e={};if(typeof r!="object"||r===null)return a.warn("Sanitize","API config data is not an object",{data:r,type:typeof r}),e;try{const t=Object.keys(r);let n=0,s=0;for(const i of t)if(ct.has(i)){const o=r[i];if(i==="excludedUrlPaths"){const c=Array.isArray(o)?o:typeof o=="string"?[o]:[],l=c.length;e.excludedUrlPaths=c.map(g=>Mt(String(g))).filter(Boolean);const u=l-e.excludedUrlPaths.length;u>0&&a.warn("Sanitize","Some excluded URL paths were filtered during sanitization",{originalCount:l,filteredCount:u})}else if(i==="tags")Array.isArray(o)?(e.tags=o,a.debug("Sanitize","Tags processed",{count:o.length})):a.warn("Sanitize","Tags value is not an array",{value:o,type:typeof o});else if(i==="samplingRate"){const c=H(o);typeof c=="number"&&(e.samplingRate=c)}else{const c=H(o);c!==null?e[i]=c:a.warn("Sanitize","API config value sanitized to null",{key:i,originalValue:o})}n++}else s++,a.debug("Sanitize","API config key not allowed",{key:i});a.info("Sanitize","API config sanitization completed",{originalKeys:t.length,processedKeys:n,filteredKeys:s,finalKeys:Object.keys(e).length})}catch(t){throw a.error("Sanitize","API config sanitization failed",{error:t instanceof Error?t.message:t}),new Error(`API config sanitization failed: ${t instanceof Error?t.message:"Unknown error"}`)}return e},Lt=r=>{if(a.debug("Sanitize","Starting metadata sanitization",{hasMetadata:r!=null}),typeof r!="object"||r===null)return a.debug("Sanitize","Metadata is not an object, returning empty object",{metadata:r,type:typeof r}),{};try{const e=Object.keys(r).length,t=H(r),n=typeof t=="object"&&t!==null?t:{},s=Object.keys(n).length;return a.debug("Sanitize","Metadata sanitization completed",{originalKeys:e,finalKeys:s,keysFiltered:e-s}),n}catch(e){throw a.error("Sanitize","Metadata sanitization failed",{error:e instanceof Error?e.message:e}),new Error(`Metadata sanitization failed: ${e instanceof Error?e.message:"Unknown error"}`)}},Nt=r=>{if(typeof r!="object"||r===null)return!1;for(const e of Object.values(r)){if(e==null)continue;const t=typeof e;if(!(t==="string"||t==="number"||t==="boolean")){if(Array.isArray(e)){if(!e.every(n=>typeof n=="string"))return!1;continue}return!1}}return!0},Ct=r=>typeof r!="string"?{valid:!1,error:"Event name must be a string"}:r.length===0?{valid:!1,error:"Event name cannot be empty"}:r.length>_e?{valid:!1,error:`Event name is too long (max ${_e} characters)`}:r.includes("<")||r.includes(">")||r.includes("&")?{valid:!1,error:"Event name contains invalid characters"}:["constructor","prototype","__proto__","eval","function","var","let","const"].includes(r.toLowerCase())?{valid:!1,error:"Event name cannot be a reserved word"}:{valid:!0},ze=(r,e,t)=>{const n=Lt(e),s=`${t} "${r}" metadata error`;if(!Nt(n))return{valid:!1,error:`${s}: object has invalid types. Valid types are string, number, boolean or string arrays.`};let i;try{i=JSON.stringify(n)}catch{return{valid:!1,error:`${s}: object contains circular references or cannot be serialized.`}}if(i.length>we)return{valid:!1,error:`${s}: object is too large (max ${we/1024} KB).`};if(Object.keys(n).length>Ae)return{valid:!1,error:`${s}: object has too many keys (max ${Ae} keys).`};for(const[c,l]of Object.entries(n)){if(Array.isArray(l)){if(l.length>be)return{valid:!1,error:`${s}: array property "${c}" is too large (max ${be} items).`};for(const u of l)if(typeof u=="string"&&u.length>500)return{valid:!1,error:`${s}: array property "${c}" contains strings that are too long (max 500 characters).`}}if(typeof l=="string"&&l.length>_)return{valid:!1,error:`${s}: property "${c}" is too long (max ${_} characters).`}}return{valid:!0,sanitizedMetadata:n}},Pt=(r,e,t)=>{if(Array.isArray(e)){const n=[],s=`${t} "${r}" 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 c=ze(r,o,t);if(!c.valid)return{valid:!1,error:`${s}: array item at index ${i} is invalid: ${c.error}`};c.sanitizedMetadata&&n.push(c.sanitizedMetadata)}return{valid:!0,sanitizedMetadata:n}}return ze(r,e,t)},Ot=(r,e)=>{const t=Ct(r);if(!t.valid)return a.clientError("EventValidation","Event name validation failed",{eventName:r,error:t.error}),t;if(!e)return{valid:!0};const n=Pt(r,e,"customEvent");return n.valid||a.clientError("EventValidation","Event metadata validation failed",{eventName:r,error:n.error}),n},te=(r,e=!1)=>{try{const t=new URL(r),n=t.protocol==="https:",s=t.protocol==="http:";return n||e&&s}catch{return!1}},Dt=(r,e=!1)=>{const t=new URL(window.location.href),n=t.hostname,s=n.split(".");if(s.length===0)throw a.clientError("URLUtils","Invalid hostname - no domain parts found",{hostname:n}),new Error("Invalid URL");const i=s.slice(-2).join("."),c=`${e&&t.protocol==="http:"?"http":"https"}://${r}.${i}`;if(!te(c,e))throw a.clientError("URLUtils","Generated API URL failed validation",{apiUrl:c,allowHttp:e}),new Error("Invalid URL");return c},re=(r,e=[])=>{try{const t=new URL(r),n=t.searchParams,s=Array.from(n.keys()).length;let i=!1;const o=[];return e.forEach(l=>{n.has(l)&&(n.delete(l),i=!0,o.push(l))}),i&&a.debug("URLUtils","Sensitive parameters removed from URL",{removedParams:o,originalParamCount:s,finalParamCount:Array.from(n.keys()).length}),!i&&r.includes("?")?r:(t.search=n.toString(),t.toString())}catch(t){return a.warn("URLUtils","URL normalization failed, returning original",{url:r.slice(0,100),error:t instanceof Error?t.message:t}),r}},kt=(r,e=[])=>{if(e.length===0)return!1;let t;try{const l=new URL(r,window.location.origin);t=l.pathname+(l.hash??"")}catch(l){return a.warn("URLUtils","Failed to parse URL for path exclusion check",{url:r.slice(0,100),error:l instanceof Error?l.message:l}),!1}const n=l=>typeof l=="object"&&l!==void 0&&typeof l.test=="function",s=l=>l.replaceAll(/[$()*+.?[\\\]^{|}]/g,"\\$&"),i=l=>new RegExp("^"+l.split("*").map(u=>s(u)).join(".+")+"$");return!!e.find(l=>{try{return n(l)?l.test(t):l.includes("*")?i(l).test(t):l===t}catch(u){return a.warn("URLUtils","Error testing exclusion pattern",{pattern:l,path:t,error:u instanceof Error?u.message:u}),!1}})};async function Ut(r,e={}){const{timeout:t=1e4,...n}=e,s=new AbortController,i=setTimeout(()=>{s.abort()},t);try{const o=await fetch(r,{...n,signal:s.signal});return clearTimeout(i),o}catch(o){throw clearTimeout(i),o instanceof Error&&o.name==="AbortError"?new Error(`Request timeout after ${t}ms`):o}}class xt{listeners=new Map;on(e,t){this.listeners.has(e)||this.listeners.set(e,[]),this.listeners.get(e).push(t)}off(e,t){const n=this.listeners.get(e);if(n){const s=n.indexOf(t);s>-1&&n.splice(s,1)}}emit(e,t){const n=this.listeners.get(e);n&&n.forEach(s=>s(t))}removeAllListeners(){this.listeners.clear()}}function Ht(r,e=!1){try{if(r===m.Localhost||r===m.Fail){const n=`http://${r}`;if(!te(n,!0))throw new Error(`Invalid localhost URL format: ${r}`);return n}const t=Dt(r,e);if(!te(t,e))throw new Error(`Generated API URL failed validation: ${t}`);return t}catch(t){throw a.error("ApiManager","API URL generation failed",{projectId:r,allowHttp:e,error:t instanceof Error?t.message:t}),t}}class Ge{static build(e,t={}){const n=this.resolveMode(e,t.mode),s={id:e.id,sessionTimeout:this.resolveSessionTimeout(e.sessionTimeout),mode:n,samplingRate:this.resolveSamplingRate(t.samplingRate,e.samplingRate),errorSampling:this.resolveErrorSampling(e.errorSampling,n),excludedUrlPaths:t.excludedUrlPaths??e.excludedUrlPaths??[],tags:t.tags??[],ipExcluded:t.ipExcluded??!1,globalMetadata:e.globalMetadata??{},scrollContainerSelectors:e.scrollContainerSelectors,sensitiveQueryParams:e.sensitiveQueryParams??[],integrations:e.integrations,allowHttp:e.allowHttp??!1};return a.debug("ConfigBuilder","Configuration built",{projectId:s.id,mode:s.mode,samplingRate:s.samplingRate,errorSampling:s.errorSampling,hasTags:!!s.tags?.length,hasExclusions:!!s.excludedUrlPaths?.length}),s}static resolveSessionTimeout(e){return e===void 0?P:e<O||e>D?(a.warn("ConfigBuilder","Invalid session timeout, using default",{provided:e,min:O,max:D,default:P}),P):e}static resolveSamplingRate(e,t){const n=e??t;return n===void 0?b:n<st||n>it?(a.warn("ConfigBuilder","Invalid sampling rate, using default",{provided:n,default:b}),b):n}static resolveErrorSampling(e,t){return t===R.DEBUG||t===R.QA?e??1:e??.1}static resolveMode(e,t){return e.id===m.Skip||e.id===m.Fail||e.id.toLowerCase().startsWith("skip-")?R.DEBUG:t??e.mode}}class Ft{static PRODUCTION_DOMAINS=[/^https:\/\/.*\.tracelog\.app$/,/^https:\/\/.*\.tracelog\.dev$/];async get(e,t){if(t.id===m.Skip||t.id===m.Fail||t.id.toLowerCase().startsWith("skip-"))return this.createDefaultConfig(t);const n=await this.loadFromApi(e,t),s=this.applyQaModeIfEnabled(n),i=Ge.build(t,s);return a.info("ConfigManager","Configuration loaded",{projectId:i.id,mode:i.mode,hasTags:!!i.tags?.length,hasExclusions:!!i.excludedUrlPaths?.length}),i}async loadFromApi(e,t){try{const n=this.buildConfigUrl(e,t),s=this.buildHeaders(t),i=await Ut(n,{method:"GET",headers:s,timeout:ve});if(!i.ok)throw new Error(`HTTP ${i.status}: ${i.statusText}`);const o=await this.parseJsonResponse(i),c=Rt(o);return{...c,excludedUrlPaths:c.excludedUrlPaths??k.excludedUrlPaths,tags:c.tags??k.tags}}catch(n){const s=n instanceof Error?n.message:"Unknown error";throw a.error("ConfigManager","Failed to load configuration",{error:s,apiUrl:e,projectId:t.id}),new Error(`Configuration load failed: ${s}`)}}buildConfigUrl(e,t){if(t.id===m.Localhost||t.id===m.Fail)return`http://${t.id}/config`;const s=`${e}/config`;return this.isQaModeEnabled()?`${s}?qaMode=true`:s}buildHeaders(e){return{"Content-Type":"application/json","X-TraceLog-Project":e.id}}async parseJsonResponse(e){if(!e.headers.get("content-type")?.includes("application/json"))throw new Error("Invalid response content-type, expected JSON");const n=await e.json();if(!n||typeof n!="object"||Array.isArray(n))throw new Error("Invalid response format, expected object");return n}isQaModeEnabled(){return new URLSearchParams(window.location.search).get("qaMode")==="true"}applyQaModeIfEnabled(e){return this.isQaModeEnabled()&&!e.mode?(a.info("ConfigManager","QA mode enabled via URL parameter"),{...e,mode:R.QA}):e}createDefaultConfig(e){const t={tags:k.tags,ipExcluded:k.ipExcluded,...e.samplingRate===void 0&&{samplingRate:k.samplingRate}};return Ge.build(e,t)}}class Vt extends S{storeManager;retryTimeoutId=null;retryCount=0;isRetrying=!1;constructor(e){super(),this.storeManager=e}getQueueStorageKey(){const e=this.get("config")?.id||"default",t=this.get("userId")||"anonymous";return`${dt(e)}:${t}`}sendEventsQueueSync(e){if(this.shouldSkipSend())return this.resetRetryState(),!0;if(this.get("config")?.id===m.Fail)return a.warn("SenderManager","Fail mode: simulating network failure (sync)",{events:e.events.length}),!1;const n=this.sendQueueSyncInternal(e);return n&&this.resetRetryState(),n}async sendEventsQueue(e,t){!this.persistEvents(e)&&!this.shouldSkipSend()&&a.warn("SenderManager","Failed to persist events, attempting immediate send");const s=await this.send(e);return s?(this.clearPersistedEvents(),this.resetRetryState(),t?.onSuccess?.(e.events.length,e.events,e)):(this.scheduleRetry(e,t),t?.onFailure?.()),s}async recoverPersistedEvents(e){try{const t=this.getPersistedData();if(!t||!this.isDataRecent(t)||t.events.length===0){this.clearPersistedEvents();return}const n=this.createRecoveryBody(t);await this.send(n)?(this.clearPersistedEvents(),this.resetRetryState(),e?.onSuccess?.(t.events.length,t.events,n)):(this.scheduleRetry(n,e),e?.onFailure?.())}catch(t){a.error("SenderManager","Failed to recover persisted events",{error:t}),this.clearPersistedEvents()}}persistEventsForRecovery(e){return this.persistEvents(e)}async sendEventsQueueAsync(e){return this.sendEventsQueue(e)}stop(){this.clearRetryTimeout(),this.resetRetryState()}async send(e){if(this.shouldSkipSend())return this.simulateSuccessfulSend();if(this.get("config")?.id===m.Fail)return a.warn("SenderManager","Fail mode: simulating network failure",{events:e.events.length}),!1;const{url:n,payload:s}=this.prepareRequest(e);try{return(await this.sendWithTimeout(n,s)).ok}catch(i){const o=i instanceof Error?i.message:String(i);return a.error("SenderManager","Send request failed",{error:o,events:e.events.length,url:n.replace(/\/\/[^/]+/,"//[DOMAIN]")}),!1}}async sendWithTimeout(e,t){const n=new AbortController,s=setTimeout(()=>n.abort(),ve),i=this.get("config");try{const o=await fetch(e,{method:"POST",headers:{"Content-Type":"application/json","X-TraceLog-Project":i?.id||"unknown"},body:t,keepalive:!0,credentials:"include",signal:n.signal});if(!o.ok)throw new Error(`HTTP ${o.status}: ${o.statusText}`);return o}finally{clearTimeout(s)}}sendQueueSyncInternal(e){const{url:t,payload:n}=this.prepareRequest(e),s=new Blob([n],{type:"application/json"});if(this.isSendBeaconAvailable()){if(navigator.sendBeacon(t,s))return!0;a.warn("SenderManager","sendBeacon failed, persisting events for recovery")}else a.warn("SenderManager","sendBeacon not available, persisting events for recovery");return this.persistEventsForRecovery(e),!1}prepareRequest(e){const t=`${this.get("apiUrl")}/collect`,n={...e,_metadata:{referer:typeof window<"u"?window.location.href:void 0,timestamp:Date.now()}};return{url:t,payload:JSON.stringify(n)}}getPersistedData(){try{const e=this.getQueueStorageKey(),t=this.storeManager.getItem(e);if(t)return JSON.parse(t)}catch(e){a.warn("SenderManager","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)<tt}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}},n=this.getQueueStorageKey();return this.storeManager.setItem(n,JSON.stringify(t)),!!this.storeManager.getItem(n)}catch(t){return a.warn("SenderManager","Failed to persist events",{error:t}),!1}}clearPersistedEvents(){try{const e=this.getQueueStorageKey();this.storeManager.removeItem(e)}catch(e){a.warn("SenderManager","Failed to clear persisted events",{error:e})}}resetRetryState(){this.retryCount=0,this.isRetrying=!1,this.clearRetryTimeout()}scheduleRetry(e,t){if(this.retryTimeoutId!==null||this.isRetrying)return;if(this.retryCount>=pe){a.warn("SenderManager","Max retries reached, giving up",{retryCount:this.retryCount}),this.clearPersistedEvents(),this.resetRetryState(),t?.onFailure?.();return}const n=rt*Math.pow(2,this.retryCount);this.isRetrying=!0,this.retryTimeoutId=window.setTimeout(async()=>{this.retryTimeoutId=null,this.retryCount++;try{await this.send(e)?(this.clearPersistedEvents(),this.resetRetryState(),t?.onSuccess?.(e.events.length)):this.retryCount>=pe?(this.clearPersistedEvents(),this.resetRetryState(),t?.onFailure?.()):this.scheduleRetry(e,t)}finally{this.isRetrying=!1}},n),a.debug("SenderManager","Retry scheduled",{attempt:this.retryCount+1,delay:n,events:e.events.length})}shouldSkipSend(){const e=this.get("config"),{id:t}=e||{};return t===m.Skip}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"}clearRetryTimeout(){this.retryTimeoutId!==null&&(clearTimeout(this.retryTimeoutId),this.retryTimeoutId=null)}}class zt extends S{googleAnalytics;dataSender;emitter;eventsQueue=[];lastEventFingerprint=null;lastEventTime=0;sendIntervalId=null;constructor(e,t=null,n=null){super(),this.googleAnalytics=t,this.dataSender=new Vt(e),this.emitter=n}async recoverPersistedEvents(){await this.dataSender.recoverPersistedEvents({onSuccess:(e,t,n)=>{if(t&&t.length>0){const s=t.map(i=>i.timestamp+"_"+i.type);this.removeProcessedEvents(s),n&&this.emitEventsQueue(n)}},onFailure:async()=>{a.warn("EventManager","Failed to recover persisted events")}})}track({type:e,page_url:t,from_page_url:n,scroll_data:s,click_data:i,custom_event:o,web_vitals:c,error_data:l,session_end_reason:u}){if(!e){a.warn("EventManager","Event type is required");return}const g=e,z=g===d.SESSION_START,Nr=g===d.SESSION_END,Cr=z||Nr,Pr=t||this.get("pageUrl"),me=this.buildEventPayload({type:g,page_url:Pr,from_page_url:n,scroll_data:s,click_data:i,custom_event:o,web_vitals:c,error_data:l,session_end_reason:u});if(!this.isEventExcluded(me)&&!(!Cr&&!this.shouldSample())){if(z){const Je=this.get("sessionId");if(!Je){a.warn("EventManager","Session start event ignored: missing sessionId");return}if(this.get("hasStartSession")){a.warn("EventManager","Duplicate session_start detected",{sessionId:Je});return}this.set("hasStartSession",!0)}this.isDuplicateEvent(me)||this.addToQueue(me)}}stop(){this.sendIntervalId&&(clearInterval(this.sendIntervalId),this.sendIntervalId=null),this.eventsQueue=[],this.lastEventFingerprint=null,this.lastEventTime=0,this.dataSender.stop()}async flushImmediately(){return this.flushEvents(!1)}flushImmediatelySync(){return this.flushEvents(!0)}getQueueLength(){return this.eventsQueue.length}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(),n=[...this.eventsQueue],s=n.map(i=>`${i.timestamp}_${i.type}`);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("EventManager","Async flush failed",{eventCount:n.length})}})}async sendEventsQueue(){if(!this.get("sessionId")||this.eventsQueue.length===0)return;const e=this.buildEventsPayload(),t=[...this.eventsQueue],n=t.map(s=>`${s.timestamp}_${s.type}`);await this.dataSender.sendEventsQueue(e,{onSuccess:()=>{this.removeProcessedEvents(n),this.emitEventsQueue(e)},onFailure:async()=>{a.warn("EventManager","Events send failed, keeping in queue",{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 n=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:n,...this.get("config")?.globalMetadata&&{global_metadata:this.get("config")?.globalMetadata}}}buildEventPayload(e){const t=e.type===d.SESSION_START,n=e.page_url??this.get("pageUrl"),s={type:e.type,page_url:n,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},...t&&ke()&&{utm:ke()}},i=this.get("config")?.tags;return i?.length&&(s.tags=i),s}isEventExcluded(e){const t=this.get("config"),n=kt(e.page_url,t?.excludedUrlPaths??[]),s=this.get("hasStartSession"),i=e.type===d.SESSION_END,o=e.type===d.SESSION_START;return n&&!o&&!(i&&s)?!0:t?.ipExcluded===!0}isDuplicateEvent(e){const t=Date.now(),n=this.createEventFingerprint(e);return this.lastEventFingerprint===n&&t-this.lastEventTime<Ze?!0:(this.lastEventFingerprint=n,this.lastEventTime=t,!1)}createEventFingerprint(e){let t=`${e.type}_${e.page_url}`;if(e.click_data){const n=Math.round((e.click_data.x||0)/10)*10,s=Math.round((e.click_data.y||0)/10)*10;t+=`_click_${n}_${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>Ee){const t=this.eventsQueue.findIndex(s=>s.type!==d.SESSION_START&&s.type!==d.SESSION_END),n=t>=0?this.eventsQueue.splice(t,1)[0]:this.eventsQueue.shift();a.warn("EventManager","Event queue overflow, oldest non-critical event removed",{maxLength:Ee,currentLength:this.eventsQueue.length,removedEventType:n?.type,wasCritical:n?.type===d.SESSION_START||n?.type===d.SESSION_END})}this.sendIntervalId||this.startSendInterval(),this.handleGoogleAnalyticsIntegration(e)}startSendInterval(){this.sendIntervalId=window.setInterval(()=>{this.eventsQueue.length>0&&this.sendEventsQueue()},et)}handleGoogleAnalyticsIntegration(e){if(this.googleAnalytics&&e.type===d.CUSTOM&&e.custom_event){if(this.get("config")?.mode==="qa"||this.get("config")?.mode==="debug")return;this.googleAnalytics.trackEvent(e.custom_event.name,e.custom_event.metadata??{})}}shouldSample(){const e=this.get("config")?.samplingRate??1;return Math.random()<e}removeProcessedEvents(e){const t=new Set(e);this.eventsQueue=this.eventsQueue.filter(n=>{const s=`${n.timestamp}_${n.type}`;return!t.has(s)})}emitEvent(e){this.emitter&&this.emitter.emit(Z.EVENT,e)}emitEventsQueue(e){this.emitter&&this.emitter.emit(Z.QUEUE,e)}}class Gt{static getId(e,t){const n=ut(t??""),s=e.getItem(n);if(s)return s;const i=vt();return e.setItem(n,i),i}}class jt extends S{storageManager;eventManager;projectId;sessionTimeoutId=null;broadcastChannel=null;activityHandler=null;visibilityChangeHandler=null;beforeUnloadHandler=null;isTracking=!1;constructor(e,t,n){super(),this.storageManager=e,this.eventManager=t,this.projectId=n}initCrossTabSync(){if(typeof BroadcastChannel>"u"){a.warn("SessionManager","BroadcastChannel not supported");return}const e=this.getProjectId();this.broadcastChannel=new BroadcastChannel(gt(e)),this.broadcastChannel.onmessage=t=>{const{action:n,sessionId:s,timestamp:i,projectId:o}=t.data??{};if(o===e){if(n==="session_end"){a.debug("SessionManager","Session end synced from another tab"),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(),a.debug("SessionManager","Session synced from another tab",{sessionId:s}))}}}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){e&&this.broadcastChannel&&typeof this.broadcastChannel.postMessage=="function"&&this.broadcastChannel.postMessage({action:"session_end",projectId:this.getProjectId(),sessionId:e,reason:t,timestamp:Date.now()})}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??P;return Date.now()-e.lastActivity>t?(a.debug("SessionManager","Stored session expired"),this.clearStoredSession(),null):(a.info("SessionManager","Session recovered from storage",{sessionId:e.id}),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 n=JSON.parse(t);return!n.id||typeof n.lastActivity!="number"?null:n}catch{return this.storageManager.removeItem(e),null}}saveStoredSession(e){const t=this.getSessionStorageKey();this.storageManager.setItem(t,JSON.stringify(e))}getSessionStorageKey(){return ht(this.getProjectId())}getProjectId(){return this.projectId}async startTracking(){if(this.isTracking){a.warn("SessionManager","Session tracking already active");return}const e=this.recoverSession(),t=e??this.generateSessionId(),n=!!e;this.isTracking=!0;try{this.set("sessionId",t),this.persistSession(t),n||this.eventManager.track({type:d.SESSION_START}),this.initCrossTabSync(),this.shareSession(t),this.setupSessionTimeout(),this.setupActivityListeners(),this.setupLifecycleListeners(),a.info("SessionManager","Session tracking started",{sessionId:t,recovered:n})}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??P;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)}async endSession(e){const t=this.get("sessionId");if(!t){a.warn("SessionManager","endSession called without active session",{reason:e}),this.resetSessionState(e);return}a.info("SessionManager","Ending session",{sessionId:t,reason:e}),this.eventManager.track({type:d.SESSION_END,session_end_reason:e});const n=()=>{this.broadcastSessionEnd(t,e),this.resetSessionState(e)};if(this.eventManager.flushImmediatelySync()){n();return}try{await this.eventManager.flushImmediately(),n()}catch(i){a.warn("SessionManager","Async flush failed during session end",{error:i instanceof Error?i.message:"Unknown error"}),n()}}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}async stopTracking(){await this.endSession("manual_stop")}destroy(){this.clearSessionTimeout(),this.cleanupActivityListeners(),this.cleanupCrossTabSync(),this.cleanupLifecycleListeners(),this.isTracking=!1,this.set("hasStartSession",!1)}}class $t extends S{eventManager;storageManager;sessionManager=null;destroyed=!1;constructor(e,t){super(),this.eventManager=t,this.storageManager=e}async startTracking(){if(this.isActive())return;if(this.destroyed){a.warn("SessionHandler","Cannot start tracking on destroyed handler");return}const e=this.get("config")?.id;if(!e)throw new Error("Cannot start session tracking: config not available");try{this.sessionManager=new jt(this.storageManager,this.eventManager,e),await this.sessionManager.startTracking()}catch(t){if(this.sessionManager){try{this.sessionManager.destroy()}catch{}this.sessionManager=null}throw a.error("SessionHandler","Failed to start session tracking",{error:t instanceof Error?t.message:"Unknown error"}),t}}isActive(){return this.sessionManager!==null&&!this.destroyed}async cleanupSessionManager(){this.sessionManager&&(await this.sessionManager.stopTracking(),this.sessionManager.destroy(),this.sessionManager=null)}async stopTracking(){await this.cleanupSessionManager()}destroy(){this.destroyed||(this.sessionManager&&(this.sessionManager.destroy(),this.sessionManager=null),this.destroyed=!0,this.set("hasStartSession",!1))}}class Qt extends S{eventManager;onTrack;originalPushState;originalReplaceState;constructor(e,t){super(),this.eventManager=e,this.onTrack=t}startTracking(){a.debug("PageViewHandler","Starting page view tracking"),this.trackInitialPageView(),window.addEventListener("popstate",this.trackCurrentPage,!0),window.addEventListener("hashchange",this.trackCurrentPage,!0),this.patchHistory("pushState"),this.patchHistory("replaceState")}stopTracking(){a.debug("PageViewHandler","Stopping page view tracking"),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)}patchHistory(e){const t=window.history[e];e==="pushState"&&!this.originalPushState?this.originalPushState=t:e==="replaceState"&&!this.originalReplaceState&&(this.originalReplaceState=t),window.history[e]=(...n)=>{t.apply(window.history,n),this.trackCurrentPage()}}trackCurrentPage=async()=>{const e=window.location.href,t=re(e,this.get("config").sensitiveQueryParams);if(this.get("pageUrl")===t)return;this.onTrack();const n=this.get("pageUrl");a.debug("PageViewHandler","Page navigation detected",{from:n,to:t}),this.set("pageUrl",t);const s=this.extractPageViewData();this.eventManager.track({type:d.PAGE_VIEW,page_url:this.get("pageUrl"),from_page_url:n,...s&&{page_view:s}})};trackInitialPageView(){const e=re(window.location.href,this.get("config").sensitiveQueryParams),t=this.extractPageViewData();this.eventManager.track({type:d.PAGE_VIEW,page_url:e,...t&&{page_view:t}}),this.onTrack()}extractPageViewData(){const{pathname:e,search:t,hash:n}=window.location,{referrer:s}=document,{title:i}=document;return!s&&!i&&!e&&!t&&!n?void 0:{...s&&{referrer:s},...i&&{title:i},...e&&{pathname:e},...t&&{search:t},...n&&{hash:n}}}}class Bt extends S{eventManager;clickHandler;constructor(e){super(),this.eventManager=e}startTracking(){this.clickHandler||(this.clickHandler=e=>{const t=e,n=t.target,s=n instanceof HTMLElement?n:n instanceof Node&&n.parentElement instanceof HTMLElement?n.parentElement:null;if(!s){a.warn("ClickHandler","Click target not found or not an element");return}const i=this.findTrackingElement(s),o=this.getRelevantClickElement(s),c=this.calculateClickCoordinates(t,s);if(i){const u=this.extractTrackingData(i);if(u){const g=this.createCustomEventData(u);this.eventManager.track({type:d.CUSTOM,custom_event:{name:g.name,...g.value&&{metadata:{value:g.value}}}})}}const l=this.generateClickData(s,o,c);this.eventManager.track({type:d.CLICK,click_data:l})},window.addEventListener("click",this.clickHandler,!0))}stopTracking(){this.clickHandler&&(window.removeEventListener("click",this.clickHandler,!0),this.clickHandler=void 0)}findTrackingElement(e){return e.hasAttribute(`${G}-name`)?e:e.closest(`[${G}-name]`)||void 0}getRelevantClickElement(e){for(const t of at)try{if(e.matches(t))return e;const n=e.closest(t);if(n)return n}catch(n){a.warn("ClickHandler","Invalid selector in element search",{selector:t,error:n instanceof Error?n.message:"Unknown error"});continue}return e}clamp(e){return Math.max(0,Math.min(1,Number(e.toFixed(3))))}calculateClickCoordinates(e,t){const n=t.getBoundingClientRect(),s=e.clientX,i=e.clientY,o=n.width>0?this.clamp((s-n.left)/n.width):0,c=n.height>0?this.clamp((i-n.top)/n.height):0;return{x:s,y:i,relativeX:o,relativeY:c}}extractTrackingData(e){const t=e.getAttribute(`${G}-name`),n=e.getAttribute(`${G}-value`);if(t)return{element:e,name:t,...n&&{value:n}}}generateClickData(e,t,n){const{x:s,y:i,relativeX:o,relativeY:c}=n,l=this.getRelevantText(e,t),u=this.extractElementAttributes(t);return{x:s,y:i,relativeX:o,relativeY:c,tag:t.tagName.toLowerCase(),...t.id&&{id:t.id},...t.className&&{class:t.className},...l&&{text:l},...u.href&&{href:u.href},...u.title&&{title:u.title},...u.alt&&{alt:u.alt},...u.role&&{role:u.role},...u["aria-label"]&&{ariaLabel:u["aria-label"]},...Object.keys(u).length>0&&{dataAttributes:u}}}getRelevantText(e,t){const n=e.textContent?.trim()??"",s=t.textContent?.trim()??"";return!n&&!s?"":n&&n.length<=X?n:s.length<=X?s:s.slice(0,X-3)+"..."}extractElementAttributes(e){const t=["id","class","data-testid","aria-label","title","href","type","name","alt","role"],n={};for(const s of t){const i=e.getAttribute(s);i&&(n[s]=i)}return n}createCustomEventData(e){return{name:e.name,...e.value&&{value:e.value}}}}class Wt extends S{eventManager;containers=[];limitWarningLogged=!1;minDepthChange=ye;minIntervalMs=Te;maxEventsPerSession=Ie;constructor(e){super(),this.eventManager=e}startTracking(){this.limitWarningLogged=!1,this.applyConfigOverrides(),this.set("scrollEventCount",0);const e=this.get("config").scrollContainerSelectors,t=Array.isArray(e)?e:typeof e=="string"?[e]:[];t.length===0?this.setupScrollContainer(window):this.trySetupContainers(t,0)}stopTracking(){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}trySetupContainers(e,t){const n=e.map(s=>this.safeQuerySelector(s)).filter(s=>s instanceof HTMLElement);if(n.length>0){for(const s of n)this.containers.some(o=>o.element===s)||this.setupScrollContainer(s);return}if(t<5){setTimeout(()=>this.trySetupContainers(e,t+1),200);return}this.containers.length===0&&this.setupScrollContainer(window)}setupScrollContainer(e){if(e!==window&&!this.isElementScrollable(e))return;const t=()=>{this.get("suppressNextScroll")||(this.clearContainerTimer(s),s.debounceTimer=window.setTimeout(()=>{const i=this.calculateScrollData(s);if(i){const o=Date.now();this.processScrollEvent(s,i,o)}s.debounceTimer=null},Se))},n=this.getScrollTop(e),s={element:e,lastScrollPos:n,lastDepth:this.calculateScrollDepth(n,this.getScrollHeight(e),this.getViewportHeight(e)),lastDirection:U.DOWN,lastEventTime:0,debounceTimer:null,listener:t};this.containers.push(s),e instanceof Window?window.addEventListener("scroll",t,{passive:!0}):e.addEventListener("scroll",t,{passive:!0})}processScrollEvent(e,t,n){if(!this.shouldEmitScrollEvent(e,t,n))return;e.lastEventTime=n,e.lastDepth=t.depth,e.lastDirection=t.direction;const s=this.get("scrollEventCount")??0;this.set("scrollEventCount",s+1),this.eventManager.track({type:d.SCROLL,scroll_data:t})}shouldEmitScrollEvent(e,t,n){return this.hasReachedSessionLimit()?(this.logLimitOnce(),!1):!(!this.hasElapsedMinimumInterval(e,n)||!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("ScrollHandler","Max scroll events per session reached",{limit:this.maxEventsPerSession}))}applyConfigOverrides(){this.minDepthChange=ye,this.minIntervalMs=Te,this.maxEventsPerSession=Ie}isWindowScrollable(){return document.documentElement.scrollHeight>window.innerHeight}clearContainerTimer(e){e.debounceTimer!==null&&(clearTimeout(e.debounceTimer),e.debounceTimer=null)}getScrollDirection(e,t){return e>t?U.DOWN:U.UP}calculateScrollDepth(e,t,n){if(t<=n)return 0;const s=t-n;return Math.min(100,Math.max(0,Math.floor(e/s*100)))}calculateScrollData(e){const{element:t,lastScrollPos:n}=e,s=this.getScrollTop(t);if(Math.abs(s-n)<nt||t===window&&!this.isWindowScrollable())return null;const o=this.getViewportHeight(t),c=this.getScrollHeight(t),l=this.getScrollDirection(s,n),u=this.calculateScrollDepth(s,c,o);return e.lastScrollPos=s,{depth:u,direction:l}}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),n=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 n&&s}safeQuerySelector(e){try{return document.querySelector(e)}catch(t){return a.clientWarn("ScrollHandler","Invalid CSS selector",{selector:e,error:t instanceof Error?t.message:"Unknown error"}),null}}}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(n){a.error("GoogleAnalyticsIntegration","Initialization failed",{error:n instanceof Error?n.message:"Unknown error"})}}trackEvent(e,t){if(!(!e?.trim()||!this.isInitialized||typeof window.gtag!="function"))try{const n=Array.isArray(t)?{items:t}:t;window.gtag("event",e,n)}catch(n){a.error("GoogleAnalyticsIntegration","Event tracking failed",{error:n instanceof Error?n.message:"Unknown error"})}}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,n)=>{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=()=>n(new Error("Failed to load Google Analytics script")),document.head.appendChild(s)})}configureGtag(e,t){const n=document.createElement("script");n.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(n)}}class Kt{storage;fallbackStorage=new Map;hasQuotaExceededError=!1;constructor(){this.storage=this.initializeStorage(),this.storage||a.warn("StorageManager","localStorage not available, using memory fallback")}getItem(e){try{return this.storage?this.storage.getItem(e):this.fallbackStorage.get(e)??null}catch(t){return a.warn("StorageManager","Failed to get item, using fallback",{key:e,error:t}),this.fallbackStorage.get(e)??null}}setItem(e,t){try{if(this.storage){this.storage.setItem(e,t);return}}catch(n){n instanceof DOMException&&n.name==="QuotaExceededError"?(this.hasQuotaExceededError=!0,a.error("StorageManager","localStorage quota exceeded - data will not persist after reload",{key:e,valueSize:t.length})):a.warn("StorageManager","Failed to set item, using fallback",{key:e,error:n})}this.fallbackStorage.set(e,t)}removeItem(e){try{this.storage&&this.storage.removeItem(e)}catch(t){a.warn("StorageManager","Failed to remove item",{key:e,error:t})}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 n=this.storage.key(t);n?.startsWith("tracelog_")&&e.push(n)}e.forEach(t=>this.storage.removeItem(t)),this.fallbackStorage.clear(),a.debug("StorageManager","Cleared storage",{itemsRemoved:e.length})}catch(e){a.error("StorageManager","Failed to clear storage",{error:e}),this.fallbackStorage.clear()}}isAvailable(){return this.storage!==null}hasQuotaError(){return this.hasQuotaExceededError}initializeStorage(){if(typeof window>"u")return null;try{const e=window.localStorage,t="__tracelog_test__";return e.setItem(t,"test"),e.removeItem(t),e}catch{return null}}}class Xt extends S{eventManager;reportedByNav=new Map;observers=[];lastLongTaskSentAt=0;vitalThresholds=Le;constructor(e){super(),this.eventManager=e}async startTracking(){await this.initWebVitals(),this.observeLongTasks()}stopTracking(){this.observers.forEach((e,t)=>{try{e.disconnect()}catch(n){a.warn("PerformanceHandler","Failed to disconnect performance observer",{error:n instanceof Error?n.message:"Unknown error",observerIndex:t})}}),this.observers.length=0,this.reportedByNav.clear()}observeWebVitalsFallback(){this.reportTTFB(),this.safeObserve("largest-contentful-paint",n=>{const s=n.getEntries(),i=s[s.length-1];i&&this.sendVital({type:"LCP",value:Number(i.startTime.toFixed(A))})},{type:"largest-contentful-paint",buffered:!0},!0);let e=0,t=this.getNavigationId();this.safeObserve("layout-shift",n=>{const s=this.getNavigationId();s!==t&&(e=0,t=s);const i=n.getEntries();for(const o of i){if(o.hadRecentInput===!0)continue;const c=typeof o.value=="number"?o.value:0;e+=c}this.sendVital({type:"CLS",value:Number(e.toFixed(A))})},{type:"layout-shift",buffered:!0}),this.safeObserve("paint",n=>{for(const s of n.getEntries())s.name==="first-contentful-paint"&&this.sendVital({type:"FCP",value:Number(s.startTime.toFixed(A))})},{type:"paint",buffered:!0},!0),this.safeObserve("event",n=>{let s=0;const i=n.getEntries();for(const o of i){const c=(o.processingEnd??0)-(o.startTime??0);s=Math.max(s,c)}s>0&&this.sendVital({type:"INP",value:Number(s.toFixed(A))})},{type:"event",buffered:!0})}async initWebVitals(){try{const{onLCP:e,onCLS:t,onFCP:n,onTTFB:s,onINP:i}=await Promise.resolve().then(()=>Lr),o=c=>l=>{const u=Number(l.value.toFixed(A));this.sendVital({type:c,value:u})};e(o("LCP")),t(o("CLS")),n(o("FCP")),s(o("TTFB")),i(o("INP"))}catch(e){a.warn("PerformanceHandler","Failed to load web-vitals library, using fallback",{error:e instanceof Error?e.message:"Unknown error"}),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(A))})}catch(e){a.warn("PerformanceHandler","Failed to report TTFB",{error:e instanceof Error?e.message:"Unknown error"})}}observeLongTasks(){this.safeObserve("longtask",e=>{const t=e.getEntries();for(const n of t){const s=Number(n.duration.toFixed(A)),i=Date.now();i-this.lastLongTaskSentAt>=ft&&(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 n=this.reportedByNav.get(t);if(n?.has(e.type))return;n?n.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("PerformanceHandler","Invalid web vital value",{type:e,value:t});return}this.eventManager.track({type:h.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(),n=Math.random().toString(36).substr(2,5);return`${t.toFixed(2)}_${window.location.pathname}_${n}`}catch(e){return a.warn("PerformanceHandler","Failed to get navigation ID",{error:e instanceof Error?e.message:"Unknown error"}),null}}isObserverSupported(e){if(typeof PerformanceObserver>"u")return!1;const t=PerformanceObserver.supportedEntryTypes;return!t||t.includes(e)}safeObserve(e,t,n,s=!1){try{if(!this.isObserverSupported(e))return!1;const i=new PerformanceObserver((o,c)=>{try{t(o,c)}catch(l){a.warn("PerformanceHandler","Observer callback failed",{type:e,error:l instanceof Error?l.message:"Unknown error"})}if(s)try{c.disconnect()}catch{}});return i.observe(n??{type:e,buffered:!0}),s||this.observers.push(i),!0}catch(i){return a.warn("PerformanceHandler","Failed to create performance observer",{type:e,error:i instanceof Error?i.message:"Unknown error"}),!1}}shouldSendVital(e,t){if(typeof t!="number"||!Number.isFinite(t))return a.warn("PerformanceHandler","Invalid web vital value",{type:e,value:t}),!1;const n=this.vitalThresholds[e];return typeof n=="number"&&t<=n?(a.debug("PerformanceHandler","Web vital below threshold, skipping",{type:e,value:t,threshold:n}),!1):!0}}class qt extends S{eventManager;recentErrors=new Map;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()}shouldSample(){const t=this.get("config")?.errorSampling??.1;return Math.random()<t}handleError=e=>{if(!this.shouldSample())return;const t=this.sanitize(e.message||"Unknown error");this.shouldSuppressError(M.JS_ERROR,t)||(a.warn("ErrorHandler","JS error captured",{message:t,filename:e.filename,line:e.lineno}),this.eventManager.track({type:h.ERROR,error_data:{type:M.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),n=this.sanitize(t);this.shouldSuppressError(M.PROMISE_REJECTION,n)||(a.warn("ErrorHandler","Promise rejection captured",{message:n}),this.eventManager.track({type:h.ERROR,error_data:{type:M.PROMISE_REJECTION,message:n}}))};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>Ce?e.slice(0,Ce)+"...":e;for(const n of Ne){const s=new RegExp(n.source,n.flags);t=t.replace(s,"[REDACTED]")}return t}shouldSuppressError(e,t){const n=Date.now(),s=`${e}:${t}`,i=this.recentErrors.get(s);return i&&n-i<Pe?(this.recentErrors.set(s,n),!0):(this.recentErrors.set(s,n),this.recentErrors.size>Oe?(a.warn("ErrorHandler","Hard limit exceeded, clearing all tracked errors",{size:this.recentErrors.size,limit:Oe}),this.recentErrors.clear(),this.recentErrors.set(s,n),!1):(this.recentErrors.size>j&&this.pruneOldErrors(),!1))}pruneOldErrors(){const e=Date.now();for(const[s,i]of this.recentErrors.entries())e-i>Pe&&this.recentErrors.delete(s);if(this.recentErrors.size<=j)return;const t=Array.from(this.recentErrors.entries()).sort((s,i)=>s[1]-i[1]),n=this.recentErrors.size-j;for(let s=0;s<n;s+=1){const i=t[s];i&&this.recentErrors.delete(i[0])}}}class Jt extends S{isInitialized=!1;suppressNextScrollTimer=null;emitter=new xt;managers={};handlers={};integrations={};get initialized(){return this.isInitialized}async init(e){if(!this.isInitialized){if(!e.id?.trim())throw new Error("Project ID is required");this.managers.storage=new Kt;try{await this.setupState(e),await this.setupIntegrations(),this.managers.event=new zt(this.managers.storage,this.integrations.googleAnalytics,this.emitter),this.initializeHandlers(),await this.managers.event.recoverPersistedEvents().catch(()=>{a.warn("App","Failed to recover persisted events")}),this.isInitialized=!0}catch(t){throw await this.destroy(!0),new Error(`TraceLog initialization failed: ${t}`)}}}sendCustomEvent(e,t){if(!this.managers.event)return;const{valid:n,error:s,sanitizedMetadata:i}=Ot(e,t);if(!n){const o=this.get("config");if(o?.mode==="qa"||o?.mode==="debug")throw new Error(`Custom event "${e}" validation failed: ${s}`);return}this.managers.event.track({type:h.CUSTOM,custom_event:{name:e,...i&&{metadata:i}}})}on(e,t){this.emitter.on(e,t)}off(e,t){this.emitter.off(e,t)}async destroy(e=!1){if(!this.isInitialized&&!e)return;this.integrations.googleAnalytics?.cleanup();const t=Object.values(this.handlers).filter(Boolean).map(async n=>{try{await n.stopTracking()}catch{a.warn("App","Failed to stop tracking")}});await Promise.allSettled(t),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={}}async setupState(e){const t=Ht(e.id,e.allowHttp);this.set("apiUrl",t);const s=await new Ft().get(t,e);this.set("config",s);const i=Gt.getId(this.managers.storage,s.id);this.set("userId",i),this.set("device",pt());const o=re(window.location.href,s.sensitiveQueryParams);this.set("pageUrl",o)}async setupIntegrations(){const e=this.get("config"),t=e.integrations?.googleAnalytics?.measurementId;if(!e.ipExcluded&&t?.trim())try{this.integrations.googleAnalytics=new Yt,await this.integrations.googleAnalytics.initialize()}catch{this.integrations.googleAnalytics=void 0}}initializeHandlers(){this.handlers.session=new $t(this.managers.storage,this.managers.event),this.handlers.session.startTracking().catch(t=>{a.error("App","Session handler failed to start",{message:t instanceof Error?t.message:"Unknown error"})});const e=()=>{this.set("suppressNextScroll",!0),this.suppressNextScrollTimer&&clearTimeout(this.suppressNextScrollTimer),this.suppressNextScrollTimer=window.setTimeout(()=>{this.set("suppressNextScroll",!1)},Se*lt)};this.handlers.pageView=new Qt(this.managers.event,e),this.handlers.pageView.startTracking(),this.handlers.click=new Bt(this.managers.event),this.handlers.click.startTracking(),this.handlers.scroll=new Wt(this.managers.event),this.handlers.scroll.startTracking(),this.handlers.performance=new Xt(this.managers.event),this.handlers.performance.startTracking().catch(()=>{a.warn("App","Failed to start performance tracking")}),this.handlers.error=new qt(this.managers.event),this.handlers.error.startTracking()}}let f=null,F=!1,ne=!1;const Zt=async r=>{if(typeof window>"u"||typeof document>"u")throw new Error("This library can only be used in a browser environment");if(!window.__traceLogDisabled){if(f){a.debug("API","Library already initialized, skipping duplicate initialization");return}if(F)throw a.warn("API","Initialization already in progress"),new Error("Initialization already in progress");F=!0;try{a.info("API","Initializing TraceLog",{projectId:r.id});const e=bt(r),t=new Jt;try{await t.init(e),f=t,a.info("API","TraceLog initialized successfully",{projectId:e.id})}catch(n){try{await t.destroy(!0)}catch(s){a.warn("API","Failed to cleanup partially initialized app",{cleanupError:s})}throw n}}catch(e){throw f=null,a.error("API","Initialization failed",{error:e}),e}finally{F=!1}}},er=(r,e)=>{if(!f)throw new Error("TraceLog not initialized. Please call init() first.");try{f.sendCustomEvent(r,e)}catch(t){throw a.error("API","Failed to send custom event",{eventName:r,error:t}),t}},tr=(r,e)=>{if(!f)throw new Error("TraceLog not initialized. Please call init() first.");f.on(r,e)},rr=(r,e)=>{if(!f)throw new Error("TraceLog not initialized. Please call init() first.");f.off(r,e)},nr=()=>f!==null,sr=async()=>{if(!f)throw new Error("App not initialized");if(ne)throw new Error("Destroy operation already in progress");ne=!0;try{a.info("API","Destroying TraceLog instance"),await f.destroy(),f=null,F=!1,a.info("API","TraceLog destroyed successfully")}catch(r){throw f=null,F=!1,a.error("API","Error during destroy, forced cleanup",{error:r}),r}finally{ne=!1}},ir={WEB_VITALS_THRESHOLDS:Le},ar={PII_PATTERNS:Ne},or={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},lr={INACTIVITY_TIMEOUT_MS:30*60*1e3,SHORT_SESSION_THRESHOLD_MS:30*1e3,MEDIUM_SESSION_THRESHOLD_MS:5*60*1e3,LONG_SESSION_THRESHOLD_MS:30*60*1e3,MAX_REALISTIC_SESSION_DURATION_MS:8*60*60*1e3},cr={MOBILE_MAX_WIDTH:768,TABLET_MAX_WIDTH:1024,MOBILE_PERFORMANCE_FACTOR:1.5,TABLET_PERFORMANCE_FACTOR:1.2},ur={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},dr={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},hr={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},gr={MIN_SEGMENT_SIZE:10,MIN_COHORT_SIZE:5,COHORT_ANALYSIS_DAYS:[1,3,7,14,30],MIN_FUNNEL_EVENTS:20},fr={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},mr={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},Sr={PAGE_URL_EXCLUDED:"excluded",PAGE_URL_UNKNOWN:"unknown"},Er={init:Zt,event:er,on:tr,off:rr,isInitialized:nr,destroy:sr};var se,je=-1,N=function(r){addEventListener("pageshow",function(e){e.persisted&&(je=e.timeStamp,r(e))},!0)},ie=function(){var r=self.performance&&performance.getEntriesByType&&performance.getEntriesByType("navigation")[0];if(r&&r.responseStart>0&&r.responseStart<performance.now())return r},$=function(){var r=ie();return r&&r.activationStart||0},p=function(r,e){var t=ie(),n="navigate";return je>=0?n="back-forward-cache":t&&(document.prerendering||$()>0?n="prerender":document.wasDiscarded?n="restore":t.type&&(n=t.type.replace(/_/g,"-"))),{name:r,value:e===void 0?-1:e,rating:"good",delta:0,entries:[],id:"v4-".concat(Date.now(),"-").concat(Math.floor(8999999999999*Math.random())+1e12),navigationType:n}},V=function(r,e,t){try{if(PerformanceObserver.supportedEntryTypes.includes(r)){var n=new PerformanceObserver(function(s){Promise.resolve().then(function(){e(s.getEntries())})});return n.observe(Object.assign({type:r,buffered:!0},t||{})),n}}catch{}},v=function(r,e,t,n){var s,i;return function(o){e.value>=0&&(o||n)&&((i=e.value-(s||0))||s===void 0)&&(s=e.value,e.delta=i,e.rating=function(c,l){return c>l[1]?"poor":c>l[0]?"needs-improvement":"good"}(e.value,t),r(e))}},ae=function(r){requestAnimationFrame(function(){return requestAnimationFrame(function(){return r()})})},Q=function(r){document.addEventListener("visibilitychange",function(){document.visibilityState==="hidden"&&r()})},oe=function(r){var e=!1;return function(){e||(r(),e=!0)}},C=-1,$e=function(){return document.visibilityState!=="hidden"||document.prerendering?1/0:0},B=function(r){document.visibilityState==="hidden"&&C>-1&&(C=r.type==="visibilitychange"?r.timeStamp:0,pr())},Qe=function(){addEventListener("visibilitychange",B,!0),addEventListener("prerenderingchange",B,!0)},pr=function(){removeEventListener("visibilitychange",B,!0),removeEventListener("prerenderingchange",B,!0)},Be=function(){return C<0&&(C=$e(),Qe(),N(function(){setTimeout(function(){C=$e(),Qe()},0)})),{get firstHiddenTime(){return C}}},W=function(r){document.prerendering?addEventListener("prerenderingchange",function(){return r()},!0):r()},le=[1800,3e3],We=function(r,e){e=e||{},W(function(){var t,n=Be(),s=p("FCP"),i=V("paint",function(o){o.forEach(function(c){c.name==="first-contentful-paint"&&(i.disconnect(),c.startTime<n.firstHiddenTime&&(s.value=Math.max(c.startTime-$(),0),s.entries.push(c),t(!0)))})});i&&(t=v(r,s,le,e.reportAllChanges),N(function(o){s=p("FCP"),t=v(r,s,le,e.reportAllChanges),ae(function(){s.value=performance.now()-o.timeStamp,t(!0)})}))})},ce=[.1,.25],vr=function(r,e){e=e||{},We(oe(function(){var t,n=p("CLS",0),s=0,i=[],o=function(l){l.forEach(function(u){if(!u.hadRecentInput){var g=i[0],z=i[i.length-1];s&&u.startTime-z.startTime<1e3&&u.startTime-g.startTime<5e3?(s+=u.value,i.push(u)):(s=u.value,i=[u])}}),s>n.value&&(n.value=s,n.entries=i,t())},c=V("layout-shift",o);c&&(t=v(r,n,ce,e.reportAllChanges),Q(function(){o(c.takeRecords()),t(!0)}),N(function(){s=0,n=p("CLS",0),t=v(r,n,ce,e.reportAllChanges),ae(function(){return t()})}),setTimeout(t,0))}))},Ye=0,ue=1/0,Y=0,yr=function(r){r.forEach(function(e){e.interactionId&&(ue=Math.min(ue,e.interactionId),Y=Math.max(Y,e.interactionId),Ye=Y?(Y-ue)/7+1:0)})},Ke=function(){return se?Ye:performance.interactionCount||0},Tr=function(){"interactionCount"in performance||se||(se=V("event",yr,{type:"event",buffered:!0,durationThreshold:0}))},y=[],K=new Map,Xe=0,Ir=function(){var r=Math.min(y.length-1,Math.floor((Ke()-Xe)/50));return y[r]},_r=[],wr=function(r){if(_r.forEach(function(s){return s(r)}),r.interactionId||r.entryType==="first-input"){var e=y[y.length-1],t=K.get(r.interactionId);if(t||y.length<10||r.duration>e.latency){if(t)r.duration>t.latency?(t.entries=[r],t.latency=r.duration):r.duration===t.latency&&r.startTime===t.entries[0].startTime&&t.entries.push(r);else{var n={id:r.interactionId,latency:r.duration,entries:[r]};K.set(n.id,n),y.push(n)}y.sort(function(s,i){return i.latency-s.latency}),y.length>10&&y.splice(10).forEach(function(s){return K.delete(s.id)})}}},qe=function(r){var e=self.requestIdleCallback||self.setTimeout,t=-1;return r=oe(r),document.visibilityState==="hidden"?r():(t=e(r),Q(r)),t},de=[200,500],Ar=function(r,e){"PerformanceEventTiming"in self&&"interactionId"in PerformanceEventTiming.prototype&&(e=e||{},W(function(){var t;Tr();var n,s=p("INP"),i=function(c){qe(function(){c.forEach(wr);var l=Ir();l&&l.latency!==s.value&&(s.value=l.latency,s.entries=l.entries,n())})},o=V("event",i,{durationThreshold:(t=e.durationThreshold)!==null&&t!==void 0?t:40});n=v(r,s,de,e.reportAllChanges),o&&(o.observe({type:"first-input",buffered:!0}),Q(function(){i(o.takeRecords()),n(!0)}),N(function(){Xe=Ke(),y.length=0,K.clear(),s=p("INP"),n=v(r,s,de,e.reportAllChanges)}))}))},he=[2500,4e3],ge={},br=function(r,e){e=e||{},W(function(){var t,n=Be(),s=p("LCP"),i=function(l){e.reportAllChanges||(l=l.slice(-1)),l.forEach(function(u){u.startTime<n.firstHiddenTime&&(s.value=Math.max(u.startTime-$(),0),s.entries=[u],t())})},o=V("largest-contentful-paint",i);if(o){t=v(r,s,he,e.reportAllChanges);var c=oe(function(){ge[s.id]||(i(o.takeRecords()),o.disconnect(),ge[s.id]=!0,t(!0))});["keydown","click"].forEach(function(l){addEventListener(l,function(){return qe(c)},{once:!0,capture:!0})}),Q(c),N(function(l){s=p("LCP"),t=v(r,s,he,e.reportAllChanges),ae(function(){s.value=performance.now()-l.timeStamp,ge[s.id]=!0,t(!0)})})}})},fe=[800,1800],Mr=function r(e){document.prerendering?W(function(){return r(e)}):document.readyState!=="complete"?addEventListener("load",function(){return r(e)},!0):setTimeout(e,0)},Rr=function(r,e){e=e||{};var t=p("TTFB"),n=v(r,t,fe,e.reportAllChanges);Mr(function(){var s=ie();s&&(t.value=Math.max(s.responseStart-$(),0),t.entries=[s],n(!0),N(function(){t=p("TTFB",0),(n=v(r,t,fe,e.reportAllChanges))(!0)}))})};const Lr=Object.freeze(Object.defineProperty({__proto__:null,CLSThresholds:ce,FCPThresholds:le,INPThresholds:de,LCPThresholds:he,TTFBThresholds:fe,onCLS:vr,onFCP:We,onINP:Ar,onLCP:br,onTTFB:Rr},Symbol.toStringTag,{value:"Module"}));return d.ANALYTICS_QUERY_LIMITS=fr,d.ANOMALY_DETECTION=mr,d.CONTENT_ANALYTICS=ur,d.DATA_PROTECTION=ar,d.DEVICE_ANALYTICS=cr,d.DeviceType=T,d.ENGAGEMENT_THRESHOLDS=or,d.ErrorType=M,d.EventType=h,d.INSIGHT_THRESHOLDS=dr,d.Mode=R,d.PERFORMANCE_CONFIG=ir,d.SEGMENTATION_ANALYTICS=gr,d.SESSION_ANALYTICS=lr,d.SPECIAL_PAGE_URLS=Sr,d.ScrollDirection=U,d.TEMPORAL_ANALYSIS=hr,d.TagConditionOperator=He,d.TagConditionType=xe,d.TagLogicalOperator=Ue,d.tracelog=Er,Object.defineProperty(d,Symbol.toStringTag,{value:"Module"}),d}({});
8
+ `,document.head.appendChild(n)}}class Kt{storage;fallbackStorage=new Map;hasQuotaExceededError=!1;constructor(){this.storage=this.initializeStorage(),this.storage||a.warn("StorageManager","localStorage not available, using memory fallback")}getItem(e){try{return this.storage?this.storage.getItem(e):this.fallbackStorage.get(e)??null}catch(t){return a.warn("StorageManager","Failed to get item, using fallback",{key:e,error:t}),this.fallbackStorage.get(e)??null}}setItem(e,t){try{if(this.storage){this.storage.setItem(e,t);return}}catch(n){n instanceof DOMException&&n.name==="QuotaExceededError"?(this.hasQuotaExceededError=!0,a.error("StorageManager","localStorage quota exceeded - data will not persist after reload",{key:e,valueSize:t.length})):a.warn("StorageManager","Failed to set item, using fallback",{key:e,error:n})}this.fallbackStorage.set(e,t)}removeItem(e){try{this.storage&&this.storage.removeItem(e)}catch(t){a.warn("StorageManager","Failed to remove item",{key:e,error:t})}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 n=this.storage.key(t);n?.startsWith("tracelog_")&&e.push(n)}e.forEach(t=>this.storage.removeItem(t)),this.fallbackStorage.clear(),a.debug("StorageManager","Cleared storage",{itemsRemoved:e.length})}catch(e){a.error("StorageManager","Failed to clear storage",{error:e}),this.fallbackStorage.clear()}}isAvailable(){return this.storage!==null}hasQuotaError(){return this.hasQuotaExceededError}initializeStorage(){if(typeof window>"u")return null;try{const e=window.localStorage,t="__tracelog_test__";return e.setItem(t,"test"),e.removeItem(t),e}catch{return null}}}class Xt extends S{eventManager;reportedByNav=new Map;observers=[];lastLongTaskSentAt=0;vitalThresholds=Le;constructor(e){super(),this.eventManager=e}async startTracking(){await this.initWebVitals(),this.observeLongTasks()}stopTracking(){this.observers.forEach((e,t)=>{try{e.disconnect()}catch(n){a.warn("PerformanceHandler","Failed to disconnect performance observer",{error:n instanceof Error?n.message:"Unknown error",observerIndex:t})}}),this.observers.length=0,this.reportedByNav.clear()}observeWebVitalsFallback(){this.reportTTFB(),this.safeObserve("largest-contentful-paint",n=>{const s=n.getEntries(),i=s[s.length-1];i&&this.sendVital({type:"LCP",value:Number(i.startTime.toFixed(A))})},{type:"largest-contentful-paint",buffered:!0},!0);let e=0,t=this.getNavigationId();this.safeObserve("layout-shift",n=>{const s=this.getNavigationId();s!==t&&(e=0,t=s);const i=n.getEntries();for(const o of i){if(o.hadRecentInput===!0)continue;const c=typeof o.value=="number"?o.value:0;e+=c}this.sendVital({type:"CLS",value:Number(e.toFixed(A))})},{type:"layout-shift",buffered:!0}),this.safeObserve("paint",n=>{for(const s of n.getEntries())s.name==="first-contentful-paint"&&this.sendVital({type:"FCP",value:Number(s.startTime.toFixed(A))})},{type:"paint",buffered:!0},!0),this.safeObserve("event",n=>{let s=0;const i=n.getEntries();for(const o of i){const c=(o.processingEnd??0)-(o.startTime??0);s=Math.max(s,c)}s>0&&this.sendVital({type:"INP",value:Number(s.toFixed(A))})},{type:"event",buffered:!0})}async initWebVitals(){try{const{onLCP:e,onCLS:t,onFCP:n,onTTFB:s,onINP:i}=await Promise.resolve().then(()=>Lr),o=c=>l=>{const u=Number(l.value.toFixed(A));this.sendVital({type:c,value:u})};e(o("LCP")),t(o("CLS")),n(o("FCP")),s(o("TTFB")),i(o("INP"))}catch(e){a.warn("PerformanceHandler","Failed to load web-vitals library, using fallback",{error:e instanceof Error?e.message:"Unknown error"}),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(A))})}catch(e){a.warn("PerformanceHandler","Failed to report TTFB",{error:e instanceof Error?e.message:"Unknown error"})}}observeLongTasks(){this.safeObserve("longtask",e=>{const t=e.getEntries();for(const n of t){const s=Number(n.duration.toFixed(A)),i=Date.now();i-this.lastLongTaskSentAt>=ft&&(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 n=this.reportedByNav.get(t);if(n?.has(e.type))return;n?n.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("PerformanceHandler","Invalid web vital value",{type:e,value:t});return}this.eventManager.track({type:d.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(),n=Math.random().toString(36).substr(2,5);return`${t.toFixed(2)}_${window.location.pathname}_${n}`}catch(e){return a.warn("PerformanceHandler","Failed to get navigation ID",{error:e instanceof Error?e.message:"Unknown error"}),null}}isObserverSupported(e){if(typeof PerformanceObserver>"u")return!1;const t=PerformanceObserver.supportedEntryTypes;return!t||t.includes(e)}safeObserve(e,t,n,s=!1){try{if(!this.isObserverSupported(e))return!1;const i=new PerformanceObserver((o,c)=>{try{t(o,c)}catch(l){a.warn("PerformanceHandler","Observer callback failed",{type:e,error:l instanceof Error?l.message:"Unknown error"})}if(s)try{c.disconnect()}catch{}});return i.observe(n??{type:e,buffered:!0}),s||this.observers.push(i),!0}catch(i){return a.warn("PerformanceHandler","Failed to create performance observer",{type:e,error:i instanceof Error?i.message:"Unknown error"}),!1}}shouldSendVital(e,t){if(typeof t!="number"||!Number.isFinite(t))return a.warn("PerformanceHandler","Invalid web vital value",{type:e,value:t}),!1;const n=this.vitalThresholds[e];return typeof n=="number"&&t<=n?(a.debug("PerformanceHandler","Web vital below threshold, skipping",{type:e,value:t,threshold:n}),!1):!0}}class qt extends S{eventManager;recentErrors=new Map;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()}shouldSample(){const t=this.get("config")?.errorSampling??.1;return Math.random()<t}handleError=e=>{if(!this.shouldSample())return;const t=this.sanitize(e.message||"Unknown error");this.shouldSuppressError(M.JS_ERROR,t)||(a.warn("ErrorHandler","JS error captured",{message:t,filename:e.filename,line:e.lineno}),this.eventManager.track({type:d.ERROR,error_data:{type:M.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),n=this.sanitize(t);this.shouldSuppressError(M.PROMISE_REJECTION,n)||(a.warn("ErrorHandler","Promise rejection captured",{message:n}),this.eventManager.track({type:d.ERROR,error_data:{type:M.PROMISE_REJECTION,message:n}}))};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>Ce?e.slice(0,Ce)+"...":e;for(const n of Ne){const s=new RegExp(n.source,n.flags);t=t.replace(s,"[REDACTED]")}return t}shouldSuppressError(e,t){const n=Date.now(),s=`${e}:${t}`,i=this.recentErrors.get(s);return i&&n-i<Pe?(this.recentErrors.set(s,n),!0):(this.recentErrors.set(s,n),this.recentErrors.size>Oe?(a.warn("ErrorHandler","Hard limit exceeded, clearing all tracked errors",{size:this.recentErrors.size,limit:Oe}),this.recentErrors.clear(),this.recentErrors.set(s,n),!1):(this.recentErrors.size>j&&this.pruneOldErrors(),!1))}pruneOldErrors(){const e=Date.now();for(const[s,i]of this.recentErrors.entries())e-i>Pe&&this.recentErrors.delete(s);if(this.recentErrors.size<=j)return;const t=Array.from(this.recentErrors.entries()).sort((s,i)=>s[1]-i[1]),n=this.recentErrors.size-j;for(let s=0;s<n;s+=1){const i=t[s];i&&this.recentErrors.delete(i[0])}}}class Jt extends S{isInitialized=!1;suppressNextScrollTimer=null;emitter=new xt;managers={};handlers={};integrations={};get initialized(){return this.isInitialized}async init(e){if(!this.isInitialized){if(!e.id?.trim())throw new Error("Project ID is required");this.managers.storage=new Kt;try{await this.setupState(e),await this.setupIntegrations(),this.managers.event=new zt(this.managers.storage,this.integrations.googleAnalytics,this.emitter),this.initializeHandlers(),await this.managers.event.recoverPersistedEvents().catch(()=>{a.warn("App","Failed to recover persisted events")}),this.isInitialized=!0}catch(t){throw await this.destroy(!0),new Error(`TraceLog initialization failed: ${t}`)}}}sendCustomEvent(e,t){if(!this.managers.event)return;const{valid:n,error:s,sanitizedMetadata:i}=Ot(e,t);if(!n){const o=this.get("config");if(o?.mode==="qa"||o?.mode==="debug")throw new Error(`Custom event "${e}" validation failed: ${s}`);return}this.managers.event.track({type:d.CUSTOM,custom_event:{name:e,...i&&{metadata:i}}})}on(e,t){this.emitter.on(e,t)}off(e,t){this.emitter.off(e,t)}async destroy(e=!1){if(!this.isInitialized&&!e)return;this.integrations.googleAnalytics?.cleanup();const t=Object.values(this.handlers).filter(Boolean).map(async n=>{try{await n.stopTracking()}catch{a.warn("App","Failed to stop tracking")}});await Promise.allSettled(t),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={}}async setupState(e){const t=Ht(e.id,e.allowHttp);this.set("apiUrl",t);const s=await new Ft().get(t,e);this.set("config",s);const i=Gt.getId(this.managers.storage,s.id);this.set("userId",i),this.set("device",pt());const o=re(window.location.href,s.sensitiveQueryParams);this.set("pageUrl",o)}async setupIntegrations(){const e=this.get("config"),t=e.integrations?.googleAnalytics?.measurementId;if(!e.ipExcluded&&t?.trim())try{this.integrations.googleAnalytics=new Yt,await this.integrations.googleAnalytics.initialize()}catch{this.integrations.googleAnalytics=void 0}}initializeHandlers(){this.handlers.session=new $t(this.managers.storage,this.managers.event),this.handlers.session.startTracking().catch(t=>{a.error("App","Session handler failed to start",{message:t instanceof Error?t.message:"Unknown error"})});const e=()=>{this.set("suppressNextScroll",!0),this.suppressNextScrollTimer&&clearTimeout(this.suppressNextScrollTimer),this.suppressNextScrollTimer=window.setTimeout(()=>{this.set("suppressNextScroll",!1)},Se*lt)};this.handlers.pageView=new Qt(this.managers.event,e),this.handlers.pageView.startTracking(),this.handlers.click=new Bt(this.managers.event),this.handlers.click.startTracking(),this.handlers.scroll=new Wt(this.managers.event),this.handlers.scroll.startTracking(),this.handlers.performance=new Xt(this.managers.event),this.handlers.performance.startTracking().catch(()=>{a.warn("App","Failed to start performance tracking")}),this.handlers.error=new qt(this.managers.event),this.handlers.error.startTracking()}}let f=null,F=!1,ne=!1;const Zt=async r=>{if(typeof window>"u"||typeof document>"u")throw new Error("This library can only be used in a browser environment");if(!window.__traceLogDisabled){if(f){a.debug("API","Library already initialized, skipping duplicate initialization");return}if(F)throw a.warn("API","Initialization already in progress"),new Error("Initialization already in progress");F=!0;try{a.info("API","Initializing TraceLog",{projectId:r.id});const e=bt(r),t=new Jt;try{await t.init(e),f=t,a.info("API","TraceLog initialized successfully",{projectId:e.id})}catch(n){try{await t.destroy(!0)}catch(s){a.warn("API","Failed to cleanup partially initialized app",{cleanupError:s})}throw n}}catch(e){throw f=null,a.error("API","Initialization failed",{error:e}),e}finally{F=!1}}},er=(r,e)=>{if(!f)throw new Error("TraceLog not initialized. Please call init() first.");try{f.sendCustomEvent(r,e)}catch(t){throw a.error("API","Failed to send custom event",{eventName:r,error:t}),t}},tr=(r,e)=>{if(!f)throw new Error("TraceLog not initialized. Please call init() first.");f.on(r,e)},rr=(r,e)=>{if(!f)throw new Error("TraceLog not initialized. Please call init() first.");f.off(r,e)},nr=()=>f!==null,sr=async()=>{if(!f)throw new Error("App not initialized");if(ne)throw new Error("Destroy operation already in progress");ne=!0;try{a.info("API","Destroying TraceLog instance"),await f.destroy(),f=null,F=!1,a.info("API","TraceLog destroyed successfully")}catch(r){throw f=null,F=!1,a.error("API","Error during destroy, forced cleanup",{error:r}),r}finally{ne=!1}},ir={WEB_VITALS_THRESHOLDS:Le},ar={PII_PATTERNS:Ne},or={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},lr={INACTIVITY_TIMEOUT_MS:30*60*1e3,SHORT_SESSION_THRESHOLD_MS:30*1e3,MEDIUM_SESSION_THRESHOLD_MS:5*60*1e3,LONG_SESSION_THRESHOLD_MS:30*60*1e3,MAX_REALISTIC_SESSION_DURATION_MS:8*60*60*1e3},cr={MOBILE_MAX_WIDTH:768,TABLET_MAX_WIDTH:1024,MOBILE_PERFORMANCE_FACTOR:1.5,TABLET_PERFORMANCE_FACTOR:1.2},ur={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},dr={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},hr={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},gr={MIN_SEGMENT_SIZE:10,MIN_COHORT_SIZE:5,COHORT_ANALYSIS_DAYS:[1,3,7,14,30],MIN_FUNNEL_EVENTS:20},fr={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},mr={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},Sr={PAGE_URL_EXCLUDED:"excluded",PAGE_URL_UNKNOWN:"unknown"},Er={init:Zt,event:er,on:tr,off:rr,isInitialized:nr,destroy:sr};var se,je=-1,N=function(r){addEventListener("pageshow",function(e){e.persisted&&(je=e.timeStamp,r(e))},!0)},ie=function(){var r=self.performance&&performance.getEntriesByType&&performance.getEntriesByType("navigation")[0];if(r&&r.responseStart>0&&r.responseStart<performance.now())return r},$=function(){var r=ie();return r&&r.activationStart||0},p=function(r,e){var t=ie(),n="navigate";return je>=0?n="back-forward-cache":t&&(document.prerendering||$()>0?n="prerender":document.wasDiscarded?n="restore":t.type&&(n=t.type.replace(/_/g,"-"))),{name:r,value:e===void 0?-1:e,rating:"good",delta:0,entries:[],id:"v4-".concat(Date.now(),"-").concat(Math.floor(8999999999999*Math.random())+1e12),navigationType:n}},V=function(r,e,t){try{if(PerformanceObserver.supportedEntryTypes.includes(r)){var n=new PerformanceObserver(function(s){Promise.resolve().then(function(){e(s.getEntries())})});return n.observe(Object.assign({type:r,buffered:!0},t||{})),n}}catch{}},v=function(r,e,t,n){var s,i;return function(o){e.value>=0&&(o||n)&&((i=e.value-(s||0))||s===void 0)&&(s=e.value,e.delta=i,e.rating=function(c,l){return c>l[1]?"poor":c>l[0]?"needs-improvement":"good"}(e.value,t),r(e))}},ae=function(r){requestAnimationFrame(function(){return requestAnimationFrame(function(){return r()})})},Q=function(r){document.addEventListener("visibilitychange",function(){document.visibilityState==="hidden"&&r()})},oe=function(r){var e=!1;return function(){e||(r(),e=!0)}},C=-1,$e=function(){return document.visibilityState!=="hidden"||document.prerendering?1/0:0},B=function(r){document.visibilityState==="hidden"&&C>-1&&(C=r.type==="visibilitychange"?r.timeStamp:0,pr())},Qe=function(){addEventListener("visibilitychange",B,!0),addEventListener("prerenderingchange",B,!0)},pr=function(){removeEventListener("visibilitychange",B,!0),removeEventListener("prerenderingchange",B,!0)},Be=function(){return C<0&&(C=$e(),Qe(),N(function(){setTimeout(function(){C=$e(),Qe()},0)})),{get firstHiddenTime(){return C}}},W=function(r){document.prerendering?addEventListener("prerenderingchange",function(){return r()},!0):r()},le=[1800,3e3],We=function(r,e){e=e||{},W(function(){var t,n=Be(),s=p("FCP"),i=V("paint",function(o){o.forEach(function(c){c.name==="first-contentful-paint"&&(i.disconnect(),c.startTime<n.firstHiddenTime&&(s.value=Math.max(c.startTime-$(),0),s.entries.push(c),t(!0)))})});i&&(t=v(r,s,le,e.reportAllChanges),N(function(o){s=p("FCP"),t=v(r,s,le,e.reportAllChanges),ae(function(){s.value=performance.now()-o.timeStamp,t(!0)})}))})},ce=[.1,.25],vr=function(r,e){e=e||{},We(oe(function(){var t,n=p("CLS",0),s=0,i=[],o=function(l){l.forEach(function(u){if(!u.hadRecentInput){var g=i[0],z=i[i.length-1];s&&u.startTime-z.startTime<1e3&&u.startTime-g.startTime<5e3?(s+=u.value,i.push(u)):(s=u.value,i=[u])}}),s>n.value&&(n.value=s,n.entries=i,t())},c=V("layout-shift",o);c&&(t=v(r,n,ce,e.reportAllChanges),Q(function(){o(c.takeRecords()),t(!0)}),N(function(){s=0,n=p("CLS",0),t=v(r,n,ce,e.reportAllChanges),ae(function(){return t()})}),setTimeout(t,0))}))},Ye=0,ue=1/0,Y=0,yr=function(r){r.forEach(function(e){e.interactionId&&(ue=Math.min(ue,e.interactionId),Y=Math.max(Y,e.interactionId),Ye=Y?(Y-ue)/7+1:0)})},Ke=function(){return se?Ye:performance.interactionCount||0},Tr=function(){"interactionCount"in performance||se||(se=V("event",yr,{type:"event",buffered:!0,durationThreshold:0}))},y=[],K=new Map,Xe=0,Ir=function(){var r=Math.min(y.length-1,Math.floor((Ke()-Xe)/50));return y[r]},_r=[],wr=function(r){if(_r.forEach(function(s){return s(r)}),r.interactionId||r.entryType==="first-input"){var e=y[y.length-1],t=K.get(r.interactionId);if(t||y.length<10||r.duration>e.latency){if(t)r.duration>t.latency?(t.entries=[r],t.latency=r.duration):r.duration===t.latency&&r.startTime===t.entries[0].startTime&&t.entries.push(r);else{var n={id:r.interactionId,latency:r.duration,entries:[r]};K.set(n.id,n),y.push(n)}y.sort(function(s,i){return i.latency-s.latency}),y.length>10&&y.splice(10).forEach(function(s){return K.delete(s.id)})}}},qe=function(r){var e=self.requestIdleCallback||self.setTimeout,t=-1;return r=oe(r),document.visibilityState==="hidden"?r():(t=e(r),Q(r)),t},de=[200,500],Ar=function(r,e){"PerformanceEventTiming"in self&&"interactionId"in PerformanceEventTiming.prototype&&(e=e||{},W(function(){var t;Tr();var n,s=p("INP"),i=function(c){qe(function(){c.forEach(wr);var l=Ir();l&&l.latency!==s.value&&(s.value=l.latency,s.entries=l.entries,n())})},o=V("event",i,{durationThreshold:(t=e.durationThreshold)!==null&&t!==void 0?t:40});n=v(r,s,de,e.reportAllChanges),o&&(o.observe({type:"first-input",buffered:!0}),Q(function(){i(o.takeRecords()),n(!0)}),N(function(){Xe=Ke(),y.length=0,K.clear(),s=p("INP"),n=v(r,s,de,e.reportAllChanges)}))}))},he=[2500,4e3],ge={},br=function(r,e){e=e||{},W(function(){var t,n=Be(),s=p("LCP"),i=function(l){e.reportAllChanges||(l=l.slice(-1)),l.forEach(function(u){u.startTime<n.firstHiddenTime&&(s.value=Math.max(u.startTime-$(),0),s.entries=[u],t())})},o=V("largest-contentful-paint",i);if(o){t=v(r,s,he,e.reportAllChanges);var c=oe(function(){ge[s.id]||(i(o.takeRecords()),o.disconnect(),ge[s.id]=!0,t(!0))});["keydown","click"].forEach(function(l){addEventListener(l,function(){return qe(c)},{once:!0,capture:!0})}),Q(c),N(function(l){s=p("LCP"),t=v(r,s,he,e.reportAllChanges),ae(function(){s.value=performance.now()-l.timeStamp,ge[s.id]=!0,t(!0)})})}})},fe=[800,1800],Mr=function r(e){document.prerendering?W(function(){return r(e)}):document.readyState!=="complete"?addEventListener("load",function(){return r(e)},!0):setTimeout(e,0)},Rr=function(r,e){e=e||{};var t=p("TTFB"),n=v(r,t,fe,e.reportAllChanges);Mr(function(){var s=ie();s&&(t.value=Math.max(s.responseStart-$(),0),t.entries=[s],n(!0),N(function(){t=p("TTFB",0),(n=v(r,t,fe,e.reportAllChanges))(!0)}))})};const Lr=Object.freeze(Object.defineProperty({__proto__:null,CLSThresholds:ce,FCPThresholds:le,INPThresholds:de,LCPThresholds:he,TTFBThresholds:fe,onCLS:vr,onFCP:We,onINP:Ar,onLCP:br,onTTFB:Rr},Symbol.toStringTag,{value:"Module"}));h.ANALYTICS_QUERY_LIMITS=fr,h.ANOMALY_DETECTION=mr,h.CONTENT_ANALYTICS=ur,h.DATA_PROTECTION=ar,h.DEVICE_ANALYTICS=cr,h.DeviceType=T,h.ENGAGEMENT_THRESHOLDS=or,h.ErrorType=M,h.EventType=d,h.INSIGHT_THRESHOLDS=dr,h.Mode=R,h.PERFORMANCE_CONFIG=ir,h.SEGMENTATION_ANALYTICS=gr,h.SESSION_ANALYTICS=lr,h.SPECIAL_PAGE_URLS=Sr,h.ScrollDirection=U,h.TEMPORAL_ANALYSIS=hr,h.TagConditionOperator=He,h.TagConditionType=xe,h.TagLogicalOperator=Ue,h.tracelog=Er,Object.defineProperty(h,Symbol.toStringTag,{value:"Module"})})(this.TraceLog=this.TraceLog||{});typeof window<"u"&&(window.TraceLog?.tracelog||window.tracelog?.tracelog)&&(window.tracelog=window.TraceLog.tracelog||window.tracelog.tracelog);
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "@tracelog/lib",
3
3
  "description": "JavaScript library for web analytics and real-time event tracking",
4
4
  "license": "MIT",
5
- "version": "0.5.2",
5
+ "version": "0.5.4",
6
6
  "main": "./dist/cjs/public-api.js",
7
7
  "module": "./dist/esm/public-api.js",
8
8
  "types": "./dist/esm/public-api.d.ts",