@tracelog/lib 0.5.4 → 0.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (200) hide show
  1. package/README.md +157 -180
  2. package/dist/browser/tracelog.esm.js +1007 -1357
  3. package/dist/browser/tracelog.js +2 -2
  4. package/dist/cjs/api.d.ts +12 -2
  5. package/dist/cjs/api.js +63 -27
  6. package/dist/cjs/app.d.ts +2 -2
  7. package/dist/cjs/app.js +26 -32
  8. package/dist/cjs/constants/config.constants.d.ts +4 -2
  9. package/dist/cjs/constants/config.constants.js +6 -18
  10. package/dist/cjs/constants/index.d.ts +0 -1
  11. package/dist/cjs/constants/index.js +0 -1
  12. package/dist/cjs/constants/storage.constants.d.ts +3 -2
  13. package/dist/cjs/constants/storage.constants.js +4 -4
  14. package/dist/cjs/handlers/click.handler.js +3 -6
  15. package/dist/cjs/handlers/error.handler.js +1 -11
  16. package/dist/cjs/handlers/page-view.handler.js +0 -4
  17. package/dist/cjs/handlers/performance.handler.js +14 -29
  18. package/dist/cjs/handlers/scroll.handler.js +7 -6
  19. package/dist/cjs/handlers/session.handler.js +7 -6
  20. package/dist/cjs/integrations/google-analytics.integration.js +2 -6
  21. package/dist/cjs/listeners/activity-listener-manager.js +3 -3
  22. package/dist/cjs/listeners/input-listener-managers.js +3 -3
  23. package/dist/cjs/listeners/touch-listener-manager.js +3 -3
  24. package/dist/cjs/listeners/unload-listener-manager.js +3 -3
  25. package/dist/cjs/listeners/visibility-listener-manager.js +3 -3
  26. package/dist/cjs/managers/event.manager.d.ts +2 -1
  27. package/dist/cjs/managers/event.manager.js +60 -38
  28. package/dist/cjs/managers/sender.manager.js +29 -36
  29. package/dist/cjs/managers/session.manager.js +5 -13
  30. package/dist/cjs/managers/state.manager.d.ts +0 -3
  31. package/dist/cjs/managers/state.manager.js +1 -43
  32. package/dist/cjs/managers/storage.manager.d.ts +16 -2
  33. package/dist/cjs/managers/storage.manager.js +73 -19
  34. package/dist/cjs/managers/user.manager.d.ts +1 -1
  35. package/dist/cjs/managers/user.manager.js +2 -2
  36. package/dist/cjs/public-api.d.ts +3 -3
  37. package/dist/cjs/public-api.js +1 -1
  38. package/dist/cjs/test-bridge.d.ts +1 -0
  39. package/dist/cjs/test-bridge.js +37 -2
  40. package/dist/cjs/types/config.types.d.ts +15 -18
  41. package/dist/cjs/types/config.types.js +6 -0
  42. package/dist/cjs/types/event.types.d.ts +1 -13
  43. package/dist/cjs/types/index.d.ts +0 -2
  44. package/dist/cjs/types/index.js +0 -2
  45. package/dist/cjs/types/mode.types.d.ts +1 -2
  46. package/dist/cjs/types/mode.types.js +0 -1
  47. package/dist/cjs/types/queue.types.d.ts +0 -6
  48. package/dist/cjs/types/state.types.d.ts +2 -0
  49. package/dist/cjs/types/test-bridge.types.d.ts +2 -2
  50. package/dist/cjs/types/validation-error.types.d.ts +0 -6
  51. package/dist/cjs/types/validation-error.types.js +1 -10
  52. package/dist/cjs/utils/browser/device-detector.utils.js +2 -24
  53. package/dist/cjs/utils/browser/index.d.ts +1 -0
  54. package/dist/cjs/utils/browser/index.js +1 -0
  55. package/dist/cjs/utils/browser/qa-mode.utils.d.ts +13 -0
  56. package/dist/cjs/utils/browser/qa-mode.utils.js +43 -0
  57. package/dist/cjs/utils/browser/utm-params.utils.js +0 -15
  58. package/dist/cjs/utils/data/uuid.utils.d.ts +13 -0
  59. package/dist/cjs/utils/data/uuid.utils.js +37 -1
  60. package/dist/cjs/utils/index.d.ts +1 -1
  61. package/dist/cjs/utils/index.js +1 -1
  62. package/dist/cjs/utils/logging.utils.d.ts +6 -0
  63. package/dist/cjs/utils/logging.utils.js +25 -0
  64. package/dist/cjs/utils/network/index.d.ts +0 -1
  65. package/dist/cjs/utils/network/index.js +0 -1
  66. package/dist/cjs/utils/network/url.utils.d.ts +2 -8
  67. package/dist/cjs/utils/network/url.utils.js +46 -90
  68. package/dist/cjs/utils/security/sanitize.utils.d.ts +1 -13
  69. package/dist/cjs/utils/security/sanitize.utils.js +15 -178
  70. package/dist/cjs/utils/validations/config-validations.utils.d.ts +3 -9
  71. package/dist/cjs/utils/validations/config-validations.utils.js +48 -94
  72. package/dist/cjs/utils/validations/event-validations.utils.js +11 -5
  73. package/dist/cjs/utils/validations/index.d.ts +0 -1
  74. package/dist/cjs/utils/validations/index.js +0 -1
  75. package/dist/cjs/utils/validations/metadata-validations.utils.js +0 -1
  76. package/dist/cjs/utils/validations/type-guards.utils.d.ts +2 -2
  77. package/dist/cjs/utils/validations/type-guards.utils.js +50 -4
  78. package/dist/esm/api.d.ts +12 -2
  79. package/dist/esm/api.js +62 -27
  80. package/dist/esm/app.d.ts +2 -2
  81. package/dist/esm/app.js +28 -34
  82. package/dist/esm/constants/config.constants.d.ts +4 -2
  83. package/dist/esm/constants/config.constants.js +4 -16
  84. package/dist/esm/constants/index.d.ts +0 -1
  85. package/dist/esm/constants/index.js +0 -1
  86. package/dist/esm/constants/storage.constants.d.ts +3 -2
  87. package/dist/esm/constants/storage.constants.js +3 -2
  88. package/dist/esm/handlers/click.handler.js +3 -6
  89. package/dist/esm/handlers/error.handler.js +1 -11
  90. package/dist/esm/handlers/page-view.handler.js +0 -4
  91. package/dist/esm/handlers/performance.handler.js +14 -29
  92. package/dist/esm/handlers/scroll.handler.js +7 -6
  93. package/dist/esm/handlers/session.handler.js +7 -6
  94. package/dist/esm/integrations/google-analytics.integration.js +3 -7
  95. package/dist/esm/listeners/activity-listener-manager.js +3 -3
  96. package/dist/esm/listeners/input-listener-managers.js +3 -3
  97. package/dist/esm/listeners/touch-listener-manager.js +3 -3
  98. package/dist/esm/listeners/unload-listener-manager.js +3 -3
  99. package/dist/esm/listeners/visibility-listener-manager.js +3 -3
  100. package/dist/esm/managers/event.manager.d.ts +2 -1
  101. package/dist/esm/managers/event.manager.js +62 -40
  102. package/dist/esm/managers/sender.manager.js +31 -38
  103. package/dist/esm/managers/session.manager.js +5 -13
  104. package/dist/esm/managers/state.manager.d.ts +0 -3
  105. package/dist/esm/managers/state.manager.js +1 -43
  106. package/dist/esm/managers/storage.manager.d.ts +16 -2
  107. package/dist/esm/managers/storage.manager.js +73 -19
  108. package/dist/esm/managers/user.manager.d.ts +1 -1
  109. package/dist/esm/managers/user.manager.js +2 -2
  110. package/dist/esm/public-api.d.ts +3 -3
  111. package/dist/esm/public-api.js +1 -1
  112. package/dist/esm/test-bridge.d.ts +1 -0
  113. package/dist/esm/test-bridge.js +37 -2
  114. package/dist/esm/types/config.types.d.ts +15 -18
  115. package/dist/esm/types/config.types.js +5 -1
  116. package/dist/esm/types/event.types.d.ts +1 -13
  117. package/dist/esm/types/index.d.ts +0 -2
  118. package/dist/esm/types/index.js +0 -2
  119. package/dist/esm/types/mode.types.d.ts +1 -2
  120. package/dist/esm/types/mode.types.js +0 -1
  121. package/dist/esm/types/queue.types.d.ts +0 -6
  122. package/dist/esm/types/state.types.d.ts +2 -0
  123. package/dist/esm/types/test-bridge.types.d.ts +2 -2
  124. package/dist/esm/types/validation-error.types.d.ts +0 -6
  125. package/dist/esm/types/validation-error.types.js +0 -8
  126. package/dist/esm/utils/browser/device-detector.utils.js +2 -24
  127. package/dist/esm/utils/browser/index.d.ts +1 -0
  128. package/dist/esm/utils/browser/index.js +1 -0
  129. package/dist/esm/utils/browser/qa-mode.utils.d.ts +13 -0
  130. package/dist/esm/utils/browser/qa-mode.utils.js +39 -0
  131. package/dist/esm/utils/browser/utm-params.utils.js +0 -15
  132. package/dist/esm/utils/data/uuid.utils.d.ts +13 -0
  133. package/dist/esm/utils/data/uuid.utils.js +35 -0
  134. package/dist/esm/utils/index.d.ts +1 -1
  135. package/dist/esm/utils/index.js +1 -1
  136. package/dist/esm/utils/logging.utils.d.ts +6 -0
  137. package/dist/esm/utils/logging.utils.js +20 -0
  138. package/dist/esm/utils/network/index.d.ts +0 -1
  139. package/dist/esm/utils/network/index.js +0 -1
  140. package/dist/esm/utils/network/url.utils.d.ts +2 -8
  141. package/dist/esm/utils/network/url.utils.js +45 -88
  142. package/dist/esm/utils/security/sanitize.utils.d.ts +1 -13
  143. package/dist/esm/utils/security/sanitize.utils.js +15 -176
  144. package/dist/esm/utils/validations/config-validations.utils.d.ts +3 -9
  145. package/dist/esm/utils/validations/config-validations.utils.js +49 -94
  146. package/dist/esm/utils/validations/event-validations.utils.js +11 -5
  147. package/dist/esm/utils/validations/index.d.ts +0 -1
  148. package/dist/esm/utils/validations/index.js +0 -1
  149. package/dist/esm/utils/validations/metadata-validations.utils.js +0 -1
  150. package/dist/esm/utils/validations/type-guards.utils.d.ts +2 -2
  151. package/dist/esm/utils/validations/type-guards.utils.js +50 -4
  152. package/package.json +1 -1
  153. package/dist/cjs/app.types.d.ts +0 -2
  154. package/dist/cjs/app.types.js +0 -12
  155. package/dist/cjs/constants/api.constants.d.ts +0 -6
  156. package/dist/cjs/constants/api.constants.js +0 -14
  157. package/dist/cjs/managers/api.manager.d.ts +0 -13
  158. package/dist/cjs/managers/api.manager.js +0 -44
  159. package/dist/cjs/managers/config.builder.d.ts +0 -33
  160. package/dist/cjs/managers/config.builder.js +0 -116
  161. package/dist/cjs/managers/config.manager.d.ts +0 -56
  162. package/dist/cjs/managers/config.manager.js +0 -157
  163. package/dist/cjs/managers/tags.manager.d.ts +0 -36
  164. package/dist/cjs/managers/tags.manager.js +0 -171
  165. package/dist/cjs/types/api.types.d.ts +0 -52
  166. package/dist/cjs/types/api.types.js +0 -56
  167. package/dist/cjs/types/tag.types.d.ts +0 -43
  168. package/dist/cjs/types/tag.types.js +0 -31
  169. package/dist/cjs/utils/logging/debug-logger.utils.d.ts +0 -14
  170. package/dist/cjs/utils/logging/debug-logger.utils.js +0 -47
  171. package/dist/cjs/utils/logging/index.d.ts +0 -1
  172. package/dist/cjs/utils/logging/index.js +0 -5
  173. package/dist/cjs/utils/network/fetch-with-timeout.utils.d.ts +0 -4
  174. package/dist/cjs/utils/network/fetch-with-timeout.utils.js +0 -25
  175. package/dist/cjs/utils/validations/url-validations.utils.d.ts +0 -15
  176. package/dist/cjs/utils/validations/url-validations.utils.js +0 -47
  177. package/dist/esm/app.types.d.ts +0 -2
  178. package/dist/esm/app.types.js +0 -1
  179. package/dist/esm/constants/api.constants.d.ts +0 -6
  180. package/dist/esm/constants/api.constants.js +0 -11
  181. package/dist/esm/managers/api.manager.d.ts +0 -13
  182. package/dist/esm/managers/api.manager.js +0 -41
  183. package/dist/esm/managers/config.builder.d.ts +0 -33
  184. package/dist/esm/managers/config.builder.js +0 -112
  185. package/dist/esm/managers/config.manager.d.ts +0 -56
  186. package/dist/esm/managers/config.manager.js +0 -153
  187. package/dist/esm/managers/tags.manager.d.ts +0 -36
  188. package/dist/esm/managers/tags.manager.js +0 -167
  189. package/dist/esm/types/api.types.d.ts +0 -52
  190. package/dist/esm/types/api.types.js +0 -53
  191. package/dist/esm/types/tag.types.d.ts +0 -43
  192. package/dist/esm/types/tag.types.js +0 -28
  193. package/dist/esm/utils/logging/debug-logger.utils.d.ts +0 -14
  194. package/dist/esm/utils/logging/debug-logger.utils.js +0 -44
  195. package/dist/esm/utils/logging/index.d.ts +0 -1
  196. package/dist/esm/utils/logging/index.js +0 -1
  197. package/dist/esm/utils/network/fetch-with-timeout.utils.d.ts +0 -4
  198. package/dist/esm/utils/network/fetch-with-timeout.utils.js +0 -22
  199. package/dist/esm/utils/validations/url-validations.utils.d.ts +0 -15
  200. package/dist/esm/utils/validations/url-validations.utils.js +0 -42
@@ -1,8 +1,8 @@
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=`
1
+ (function(d){"use strict";const P="data-tlog",Ce=["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"]'],be=["utm_source","utm_medium","utm_campaign","utm_term","utm_content"],T={INVALID_SESSION_TIMEOUT:"Session timeout must be between 30000ms (30 seconds) and 86400000ms (24 hours)",INVALID_SAMPLING_RATE:"Sampling rate must be between 0 and 1",INVALID_ERROR_SAMPLING_RATE:"Error sampling must be between 0 and 1",INVALID_TRACELOG_PROJECT_ID:"TraceLog project ID is required when integration is enabled",INVALID_CUSTOM_API_URL:"Custom API URL is required when integration is enabled",INVALID_GOOGLE_ANALYTICS_ID:"Google Analytics measurement ID is required when integration is enabled",INVALID_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"},Oe=[/<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi,/javascript:/gi,/on\w+\s*=/gi,/<iframe\b[^<]*(?:(?!<\/iframe>)<[^<]*)*<\/iframe>/gi,/<embed\b[^>]*>/gi,/<object\b[^<]*(?:(?!<\/object>)<[^<]*)*<\/object>/gi];var D=(r=>(r.Localhost="localhost:8080",r.Fail="localhost:9999",r))(D||{}),_=(r=>(r.Mobile="mobile",r.Tablet="tablet",r.Desktop="desktop",r.Unknown="unknown",r))(_||{}),k=(r=>(r.EVENT="event",r.QUEUE="queue",r))(k||{}),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||{}),b=(r=>(r.UP="up",r.DOWN="down",r))(b||{}),A=(r=>(r.JS_ERROR="js_error",r.PROMISE_REJECTION="promise_rejection",r))(A||{}),w=(r=>(r.QA="qa",r))(w||{});class M extends Error{constructor(e,t,s){super(e),this.errorCode=t,this.layer=s,this.name=this.constructor.name,Error.captureStackTrace&&Error.captureStackTrace(this,this.constructor)}}class v extends M{constructor(e,t="config"){super(e,"APP_CONFIG_INVALID",t)}}class le extends M{constructor(e,t="config"){super(e,"SESSION_TIMEOUT_INVALID",t)}}class j extends M{constructor(e,t="config"){super(e,"SAMPLING_RATE_INVALID",t)}}class N extends M{constructor(e,t="config"){super(e,"INTEGRATION_INVALID",t)}}class Pe extends M{constructor(e,t,s="runtime"){super(e,"INITIALIZATION_TIMEOUT",s),this.timeoutMs=t}}const De=(r,e)=>e?`[TraceLog] ${r}: ${e instanceof Error?e.message:"Unknown error"}`:`[TraceLog] ${r}`,o=(r,e,t)=>{const{error:s,data:n,showToClient:i}=t??{},a=s?De(e,s):`[TraceLog] ${e}`,l=r==="error"?"error":r==="warn"?"warn":"log";i&&(n!==void 0?console[l](a,n):console[l](a))};let B,ce;const ke=()=>{typeof window<"u"&&!B&&(B=window.matchMedia("(pointer: coarse)"),ce=window.matchMedia("(hover: none)"))},Ue=()=>{try{const r=navigator;if(r.userAgentData&&typeof r.userAgentData.mobile=="boolean")return r.userAgentData.platform&&/ipad|tablet/i.test(r.userAgentData.platform)?_.Tablet:r.userAgentData.mobile?_.Mobile:_.Desktop;ke();const e=window.innerWidth,t=B?.matches??!1,s=ce?.matches??!1,n="ontouchstart"in window||navigator.maxTouchPoints>0,i=navigator.userAgent.toLowerCase(),a=/mobile|android|iphone|ipod|blackberry|iemobile|opera mini/.test(i),l=/tablet|ipad|android(?!.*mobile)/.test(i);return e<=767||a&&n?_.Mobile:e>=768&&e<=1024||l||t&&s&&n?_.Tablet:_.Desktop}catch(r){return o("warn","Device detection failed, defaulting to desktop",{error:r}),_.Desktop}},I="tlog",ue=`${I}:qa_mode`,He=`${I}:uid`,Ve=r=>r?`${I}:${r}:queue`:`${I}:queue`,xe=r=>r?`${I}:${r}:session`:`${I}:session`,Fe=r=>r?`${I}:${r}:broadcast`:`${I}:broadcast`,de={LCP:4e3,FCP:1800,CLS:.25,INP:200,TTFB:800,LONG_TASK:50},Ge=1e3,he=[/\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],ge=500,fe=5e3,U=50,Qe=U*2,Se="tlog_mode",$e="qa",ze=()=>{if(sessionStorage.getItem(ue)==="true")return!0;const e=new URLSearchParams(window.location.search),s=e.get(Se)===$e;if(s){sessionStorage.setItem(ue,"true"),e.delete(Se);const n=e.toString(),i=`${window.location.pathname}${n?"?"+n:""}${window.location.hash}`;try{window.history.replaceState({},"",i)}catch(a){o("warn","History API not available, cannot replace URL",{error:a})}console.log("%c[TraceLog] QA Mode ACTIVE","background: #ff9800; color: white; font-weight: bold; padding: 2px 8px; border-radius: 3px;")}return s},Ee=()=>{const r=new URLSearchParams(window.location.search),e={};return be.forEach(s=>{const n=r.get(s);if(n){const i=s.split("utm_")[1];e[i]=n}}),Object.keys(e).length?e:void 0},je=()=>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)}),Be=()=>{const r=Date.now();let e="";try{if(typeof crypto<"u"&&crypto.getRandomValues){const t=crypto.getRandomValues(new Uint8Array(4));t&&(e=Array.from(t,s=>s.toString(16).padStart(2,"0")).join(""))}}catch{}return e||(e=Math.floor(Math.random()*4294967295).toString(16).padStart(8,"0")),`${r}-${e}`},me=(r,e=!1)=>{try{const t=new URL(r),s=t.protocol==="https:",n=t.protocol==="http:";return s||e&&n}catch{return!1}},Ye=r=>{const e=r.allowHttp??!1;if(r.integrations?.tracelog?.projectId){const t=new URL(window.location.href),n=t.hostname.split(".");if(n.length===0)throw new Error("Invalid URL");const i=r.integrations.tracelog.projectId,a=n.slice(-2).join("."),c=`${e&&t.protocol==="http:"?"http":"https"}://${i}.${a}`;if(!me(c,e))throw new Error("Invalid URL");return c}if(r.integrations?.custom?.apiUrl){const t=r.integrations.custom.apiUrl;if(!me(t,e))throw new Error("Invalid URL");return t}return""},Y=(r,e=[])=>{try{const t=new URL(r),s=t.searchParams;let n=!1;const i=[];return e.forEach(l=>{s.has(l)&&(s.delete(l),n=!0,i.push(l))}),!n&&r.includes("?")?r:(t.search=s.toString(),t.toString())}catch(t){return o("warn","URL normalization failed, returning original",{error:t,data:{url:r.slice(0,100)}}),r}},pe=r=>{if(!r||typeof r!="string"||r.trim().length===0)return"";let e=r;r.length>1e3&&(e=r.slice(0,Math.max(0,1e3)));let t=0;for(const n of Oe){const i=e;e=e.replace(n,""),i!==e&&t++}return t>0&&o("warn","XSS patterns detected and removed",{data:{patternMatches:t,originalValue:r.slice(0,100)}}),e=e.replaceAll("&","&amp;").replaceAll("<","&lt;").replaceAll(">","&gt;").replaceAll('"',"&quot;").replaceAll("'","&#x27;").replaceAll("/","&#x2F;"),e.trim()},X=(r,e=0)=>{if(e>3||r==null)return null;if(typeof r=="string")return pe(r);if(typeof r=="number")return!Number.isFinite(r)||r<-Number.MAX_SAFE_INTEGER||r>Number.MAX_SAFE_INTEGER?0:r;if(typeof r=="boolean")return r;if(Array.isArray(r))return r.slice(0,100).map(n=>X(n,e+1)).filter(n=>n!==null);if(typeof r=="object"){const t={},n=Object.entries(r).slice(0,20);for(const[i,a]of n){const l=pe(i);if(l){const c=X(a,e+1);c!==null&&(t[l]=c)}}return t}return null},Xe=r=>{if(typeof r!="object"||r===null)return{};try{const e=X(r);return typeof e=="object"&&e!==null?e:{}}catch(e){const t=e instanceof Error?e.message:String(e);throw new Error(`[TraceLog] Metadata sanitization failed: ${t}`)}},We=r=>{if(!r||typeof r!="object")throw new v("Configuration must be an object","config");if(r.sessionTimeout!==void 0&&(typeof r.sessionTimeout!="number"||r.sessionTimeout<3e4||r.sessionTimeout>864e5))throw new le(T.INVALID_SESSION_TIMEOUT,"config");if(r.globalMetadata!==void 0&&(typeof r.globalMetadata!="object"||r.globalMetadata===null))throw new v(T.INVALID_GLOBAL_METADATA,"config");if(r.scrollContainerSelectors!==void 0&&qe(r.scrollContainerSelectors),r.integrations&&Je(r.integrations),r.sensitiveQueryParams!==void 0){if(!Array.isArray(r.sensitiveQueryParams))throw new v(T.INVALID_SENSITIVE_QUERY_PARAMS,"config");for(const e of r.sensitiveQueryParams)if(typeof e!="string")throw new v("All sensitive query params must be strings","config")}if(r.errorSampling!==void 0&&(typeof r.errorSampling!="number"||r.errorSampling<0||r.errorSampling>1))throw new j(T.INVALID_ERROR_SAMPLING_RATE,"config");if(r.samplingRate!==void 0&&(typeof r.samplingRate!="number"||r.samplingRate<0||r.samplingRate>1))throw new j(T.INVALID_SAMPLING_RATE,"config");if(r.allowHttp!==void 0&&typeof r.allowHttp!="boolean")throw new v("allowHttp must be a boolean","config")},Ke=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 n of r)if(n==="("&&t++,n===")"&&t--,t<0)return!1;if(t!==0)return!1;let s=0;for(const n of r)if(n==="["&&s++,n==="]"&&s--,s<0)return!1;return s===0},qe=r=>{const e=Array.isArray(r)?r:[r];for(const t of e){if(typeof t!="string"||t.trim()==="")throw o("error","Invalid scroll container selector",{showToClient:!0,data:{selector:t,type:typeof t,isEmpty:t===""||typeof t=="string"&&t.trim()===""}}),new v(T.INVALID_SCROLL_CONTAINER_SELECTORS,"config");if(!Ke(t))throw o("error","Invalid or potentially unsafe CSS selector",{showToClient:!0,data:{selector:t,reason:"Failed security validation"}}),new v("Invalid or potentially unsafe CSS selector","config")}},Je=r=>{if(r){if(r.tracelog&&(!r.tracelog.projectId||typeof r.tracelog.projectId!="string"||r.tracelog.projectId.trim()===""))throw new N(T.INVALID_TRACELOG_PROJECT_ID,"config");if(r.custom){if(!r.custom.apiUrl||typeof r.custom.apiUrl!="string"||r.custom.apiUrl.trim()==="")throw new N(T.INVALID_CUSTOM_API_URL,"config");if(!r.custom.apiUrl.startsWith("http"))throw new N('Custom API URL must start with "http"',"config")}if(r.googleAnalytics){if(!r.googleAnalytics.measurementId||typeof r.googleAnalytics.measurementId!="string"||r.googleAnalytics.measurementId.trim()==="")throw new N(T.INVALID_GOOGLE_ANALYTICS_ID,"config");if(!r.googleAnalytics.measurementId.trim().match(/^(G-|UA-)/))throw new N('Google Analytics measurement ID must start with "G-" or "UA-"',"config")}}},Ze=r=>(We(r),{...r,sessionTimeout:r.sessionTimeout??9e5,globalMetadata:r.globalMetadata??{},sensitiveQueryParams:r.sensitiveQueryParams??[],errorSampling:r.errorSampling??1,samplingRate:r.samplingRate??1,allowHttp:r.allowHttp??!1}),et=r=>{if(typeof r=="string")return!0;if(typeof r=="object"&&r!==null&&!Array.isArray(r)){const e=Object.entries(r);if(e.length>20)return!1;for(const[,t]of e){if(t==null)continue;const s=typeof t;if(s!=="string"&&s!=="number"&&s!=="boolean")return!1}return!0}return!1},tt=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.length===0)continue;if(typeof e[0]=="string"){if(!e.every(i=>typeof i=="string"))return!1}else if(!e.every(i=>et(i)))return!1;continue}return!1}}return!0},rt=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>120?{valid:!1,error:"Event name is too long (max 120 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},Te=(r,e,t)=>{const s=Xe(e),n=`${t} "${r}" metadata error`;if(!tt(s))return{valid:!1,error:`${n}: object has invalid types. Valid types are string, number, boolean or string arrays.`};let i;try{i=JSON.stringify(s)}catch{return{valid:!1,error:`${n}: object contains circular references or cannot be serialized.`}}if(i.length>8192)return{valid:!1,error:`${n}: object is too large (max ${8192/1024} KB).`};if(Object.keys(s).length>10)return{valid:!1,error:`${n}: object has too many keys (max 10 keys).`};for(const[l,c]of Object.entries(s)){if(Array.isArray(c)){if(c.length>10)return{valid:!1,error:`${n}: array property "${l}" is too large (max 10 items).`};for(const u of c)if(typeof u=="string"&&u.length>500)return{valid:!1,error:`${n}: array property "${l}" contains strings that are too long (max 500 characters).`}}if(typeof c=="string"&&c.length>1e3)return{valid:!1,error:`${n}: property "${l}" is too long (max 1000 characters).`}}return{valid:!0,sanitizedMetadata:s}},st=(r,e,t)=>{if(Array.isArray(e)){const s=[],n=`${t} "${r}" metadata error`;for(let i=0;i<e.length;i++){const a=e[i];if(typeof a!="object"||a===null||Array.isArray(a))return{valid:!1,error:`${n}: array item at index ${i} must be an object.`};const l=Te(r,a,t);if(!l.valid)return{valid:!1,error:`${n}: array item at index ${i} is invalid: ${l.error}`};l.sanitizedMetadata&&s.push(l.sanitizedMetadata)}return{valid:!0,sanitizedMetadata:s}}return Te(r,e,t)},nt=(r,e)=>{const t=rt(r);if(!t.valid)return o("error","Event name validation failed",{showToClient:!0,data:{eventName:r,error:t.error}}),t;if(!e)return{valid:!0};const s=st(r,e,"customEvent");return s.valid||o("error","Event metadata validation failed",{showToClient:!0,data:{eventName:r,error:s.error}}),s};class it{listeners=new Map;on(e,t){this.listeners.has(e)||this.listeners.set(e,[]),this.listeners.get(e).push(t)}off(e,t){const s=this.listeners.get(e);if(s){const n=s.indexOf(t);n>-1&&s.splice(n,1)}}emit(e,t){const s=this.listeners.get(e);s&&s.forEach(n=>n(t))}removeAllListeners(){this.listeners.clear()}}const W={};class f{get(e){return W[e]}set(e,t){W[e]=t}getState(){return{...W}}}class at extends f{storeManager;retryTimeoutId=null;retryCount=0;isRetrying=!1;constructor(e){super(),this.storeManager=e}getQueueStorageKey(){const e=this.get("userId")||"anonymous";return Ve(e)}sendEventsQueueSync(e){if(this.shouldSkipSend())return this.resetRetryState(),!0;if(this.get("config")?.integrations?.custom?.apiUrl===D.Fail)return o("warn","Fail mode: simulating network failure (sync)",{data:{events:e.events.length}}),!1;const s=this.sendQueueSyncInternal(e);return s&&this.resetRetryState(),s}async sendEventsQueue(e,t){this.shouldSkipSend()||this.persistEvents(e)||o("warn","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 s=this.createRecoveryBody(t);await this.send(s)?(this.clearPersistedEvents(),this.resetRetryState(),e?.onSuccess?.(t.events.length,t.events,s)):(this.scheduleRetry(s,e),e?.onFailure?.())}catch(t){o("error","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")?.integrations?.custom?.apiUrl===D.Fail)return o("warn","Fail mode: simulating network failure",{data:{events:e.events.length}}),!1;const{url:s,payload:n}=this.prepareRequest(e);try{return(await this.sendWithTimeout(s,n)).ok}catch(i){return o("error","Send request failed",{error:i,data:{events:e.events.length,url:s.replace(/\/\/[^/]+/,"//[DOMAIN]")}}),!1}}async sendWithTimeout(e,t){const s=new AbortController,n=setTimeout(()=>s.abort(),1e4);try{const i=await fetch(e,{method:"POST",body:t,keepalive:!0,credentials:"include",signal:s.signal,headers:{"Content-Type":"application/json"}});if(!i.ok)throw new Error(`HTTP ${i.status}: ${i.statusText}`);return i}finally{clearTimeout(n)}}sendQueueSyncInternal(e){const{url:t,payload:s}=this.prepareRequest(e),n=new Blob([s],{type:"application/json"});if(this.isSendBeaconAvailable()){if(navigator.sendBeacon(t,n))return!0;o("warn","sendBeacon failed, persisting events for recovery")}else o("warn","sendBeacon not available, persisting events for recovery");return this.persistEventsForRecovery(e),!1}prepareRequest(e){const t=`${this.get("apiUrl")}/collect`,s={...e,_metadata:{referer:typeof window<"u"?window.location.href:void 0,timestamp:Date.now()}};return{url:t,payload:JSON.stringify(s)}}getPersistedData(){try{const e=this.getQueueStorageKey(),t=this.storeManager.getItem(e);if(t)return JSON.parse(t)}catch(e){o("warn","Failed to parse persisted data",{error:e}),this.clearPersistedEvents()}return null}isDataRecent(e){return!e.timestamp||typeof e.timestamp!="number"?!1:(Date.now()-e.timestamp)/(1e3*60*60)<24}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}},s=this.getQueueStorageKey();return this.storeManager.setItem(s,JSON.stringify(t)),!!this.storeManager.getItem(s)}catch(t){return o("warn","Failed to persist events",{error:t}),!1}}clearPersistedEvents(){try{const e=this.getQueueStorageKey();this.storeManager.removeItem(e)}catch(e){o("warn","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>=3){o("warn","Max retries reached, giving up",{data:{retryCount:this.retryCount}}),this.clearPersistedEvents(),this.resetRetryState(),t?.onFailure?.();return}const s=5e3*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>=3?(this.clearPersistedEvents(),this.resetRetryState(),t?.onFailure?.()):this.scheduleRetry(e,t)}finally{this.isRetrying=!1}},s)}shouldSkipSend(){return!this.get("apiUrl")}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 ot extends f{googleAnalytics;dataSender;emitter;eventsQueue=[];pendingEventsBuffer=[];lastEventFingerprint=null;lastEventTime=0;sendIntervalId=null;constructor(e,t=null,s=null){super(),this.googleAnalytics=t,this.dataSender=new at(e),this.emitter=s}async recoverPersistedEvents(){await this.dataSender.recoverPersistedEvents({onSuccess:(e,t,s)=>{if(t&&t.length>0){const n=t.map(i=>i.id);this.removeProcessedEvents(n),s&&this.emitEventsQueue(s)}},onFailure:async()=>{o("warn","Failed to recover persisted events")}})}track({type:e,page_url:t,from_page_url:s,scroll_data:n,click_data:i,custom_event:a,web_vitals:l,error_data:c,session_end_reason:u}){if(!e){o("warn","Event type is required");return}if(!this.get("sessionId")){this.pendingEventsBuffer.push({type:e,page_url:t,from_page_url:s,scroll_data:n,click_data:i,custom_event:a,web_vitals:l,error_data:c,session_end_reason:u});return}const p=e,z=p===h.SESSION_START,Kt=p===h.SESSION_END,qt=z||Kt,Jt=t||this.get("pageUrl"),oe=this.buildEventPayload({type:p,page_url:Jt,from_page_url:s,scroll_data:n,click_data:i,custom_event:a,web_vitals:l,error_data:c,session_end_reason:u});if(!(!qt&&!this.shouldSample())){if(z){const Re=this.get("sessionId");if(!Re){o("warn","Session start event ignored: missing sessionId");return}if(this.get("hasStartSession")){o("warn","Duplicate session_start detected",{data:{sessionId:Re}});return}this.set("hasStartSession",!0)}if(!this.isDuplicateEvent(oe)){if(this.get("mode")===w.QA&&p===h.CUSTOM&&a){console.log("[TraceLog] Event",{name:a.name,...a.metadata&&{metadata:a.metadata}}),this.emitEvent(oe);return}this.addToQueue(oe)}}}stop(){this.sendIntervalId&&(clearInterval(this.sendIntervalId),this.sendIntervalId=null),this.eventsQueue=[],this.pendingEventsBuffer=[],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}flushPendingEvents(){if(this.pendingEventsBuffer.length===0)return;if(!this.get("sessionId")){o("warn","Cannot flush pending events: session not initialized");return}const e=[...this.pendingEventsBuffer];this.pendingEventsBuffer=[],e.forEach(t=>{this.track(t)})}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(),s=[...this.eventsQueue],n=s.map(i=>i.id);if(e){const i=this.dataSender.sendEventsQueueSync(t);return i&&(this.removeProcessedEvents(n),this.clearSendInterval(),this.emitEventsQueue(t)),i}else return this.dataSender.sendEventsQueue(t,{onSuccess:()=>{this.removeProcessedEvents(n),this.clearSendInterval(),this.emitEventsQueue(t)},onFailure:()=>{o("warn","Async flush failed",{data:{eventCount:s.length}})}})}async sendEventsQueue(){if(!this.get("sessionId")||this.eventsQueue.length===0)return;const e=this.buildEventsPayload(),t=[...this.eventsQueue],s=t.map(n=>n.id);await this.dataSender.sendEventsQueue(e,{onSuccess:()=>{this.removeProcessedEvents(s),this.emitEventsQueue(e)},onFailure:async()=>{o("warn","Events send failed, keeping in queue",{data:{eventCount:t.length}})}})}buildEventsPayload(){const e=new Map,t=[];for(const n of this.eventsQueue){const i=this.createEventSignature(n);e.has(i)||t.push(i),e.set(i,n)}const s=t.map(n=>e.get(n)).filter(n=>!!n).sort((n,i)=>n.timestamp-i.timestamp);return{user_id:this.get("userId"),session_id:this.get("sessionId"),device:this.get("device"),events:s,...this.get("config")?.globalMetadata&&{global_metadata:this.get("config")?.globalMetadata}}}buildEventPayload(e){const t=e.type===h.SESSION_START,s=e.page_url??this.get("pageUrl");return{id:Be(),type:e.type,page_url:s,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&&Ee()&&{utm:Ee()}}}isDuplicateEvent(e){const t=Date.now(),s=this.createEventFingerprint(e);return this.lastEventFingerprint===s&&t-this.lastEventTime<500?!0:(this.lastEventFingerprint=s,this.lastEventTime=t,!1)}createEventFingerprint(e){let t=`${e.type}_${e.page_url}`;if(e.click_data){const s=Math.round((e.click_data.x||0)/10)*10,n=Math.round((e.click_data.y||0)/10)*10;t+=`_click_${s}_${n}`}return e.scroll_data&&(t+=`_scroll_${e.scroll_data.depth}_${e.scroll_data.direction}`),e.custom_event&&(t+=`_custom_${e.custom_event.name}`),e.web_vitals&&(t+=`_vitals_${e.web_vitals.type}`),e.error_data&&(t+=`_error_${e.error_data.type}_${e.error_data.message}`),t}createEventSignature(e){return this.createEventFingerprint(e)}addToQueue(e){if(this.eventsQueue.push(e),this.emitEvent(e),this.eventsQueue.length>100){const t=this.eventsQueue.findIndex(n=>n.type!==h.SESSION_START&&n.type!==h.SESSION_END),s=t>=0?this.eventsQueue.splice(t,1)[0]:this.eventsQueue.shift();o("warn","Event queue overflow, oldest non-critical event removed",{data:{maxLength:100,currentLength:this.eventsQueue.length,removedEventType:s?.type,wasCritical:s?.type===h.SESSION_START||s?.type===h.SESSION_END}})}this.sendIntervalId||this.startSendInterval(),this.handleGoogleAnalyticsIntegration(e)}startSendInterval(){this.sendIntervalId=window.setInterval(()=>{this.eventsQueue.length>0&&this.sendEventsQueue()},1e4)}handleGoogleAnalyticsIntegration(e){if(this.googleAnalytics&&e.type===h.CUSTOM&&e.custom_event){if(this.get("mode")===w.QA)return;this.googleAnalytics.trackEvent(e.custom_event.name,e.custom_event.metadata??{})}}shouldSample(){const e=this.get("config")?.samplingRate??1;return Math.random()<e}removeProcessedEvents(e){const t=new Set(e);this.eventsQueue=this.eventsQueue.filter(s=>!t.has(s.id))}emitEvent(e){this.emitter&&this.emitter.emit(k.EVENT,e)}emitEventsQueue(e){this.emitter&&this.emitter.emit(k.QUEUE,e)}}class lt{static getId(e){const t=He,s=e.getItem(t);if(s)return s;const n=je();return e.setItem(t,n),n}}class ct extends f{storageManager;eventManager;projectId;sessionTimeoutId=null;broadcastChannel=null;activityHandler=null;visibilityChangeHandler=null;beforeUnloadHandler=null;isTracking=!1;constructor(e,t,s){super(),this.storageManager=e,this.eventManager=t,this.projectId=s}initCrossTabSync(){if(typeof BroadcastChannel>"u"){o("warn","BroadcastChannel not supported");return}const e=this.getProjectId();this.broadcastChannel=new BroadcastChannel(Fe(e)),this.broadcastChannel.onmessage=t=>{const{action:s,sessionId:n,timestamp:i,projectId:a}=t.data??{};if(a===e){if(s==="session_end"){this.resetSessionState();return}n&&typeof i=="number"&&i>Date.now()-5e3&&(this.set("sessionId",n),this.set("hasStartSession",!0),this.persistSession(n,i),this.isTracking&&this.setupSessionTimeout())}}}shareSession(e){this.broadcastChannel&&typeof this.broadcastChannel.postMessage=="function"&&this.broadcastChannel.postMessage({action:"session_start",projectId:this.getProjectId(),sessionId:e,timestamp:Date.now()})}broadcastSessionEnd(e,t){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??9e5;return Date.now()-e.lastActivity>t?(this.clearStoredSession(),null):e.id}persistSession(e,t=Date.now()){this.saveStoredSession({id:e,lastActivity:t})}clearStoredSession(){const e=this.getSessionStorageKey();this.storageManager.removeItem(e)}loadStoredSession(){const e=this.getSessionStorageKey(),t=this.storageManager.getItem(e);if(!t)return null;try{const s=JSON.parse(t);return!s.id||typeof s.lastActivity!="number"?null:s}catch{return this.storageManager.removeItem(e),null}}saveStoredSession(e){const t=this.getSessionStorageKey();this.storageManager.setItem(t,JSON.stringify(e))}getSessionStorageKey(){return xe(this.getProjectId())}getProjectId(){return this.projectId}async startTracking(){if(this.isTracking){o("warn","Session tracking already active");return}const e=this.recoverSession(),t=e??this.generateSessionId(),s=!!e;this.isTracking=!0;try{this.set("sessionId",t),this.persistSession(t),s||this.eventManager.track({type:h.SESSION_START}),this.initCrossTabSync(),this.shareSession(t),this.setupSessionTimeout(),this.setupActivityListeners(),this.setupLifecycleListeners()}catch(n){throw this.isTracking=!1,this.clearSessionTimeout(),this.cleanupActivityListeners(),this.cleanupLifecycleListeners(),this.cleanupCrossTabSync(),this.set("sessionId",null),n}}generateSessionId(){return`${Date.now()}-${Math.random().toString(36).substring(2,11)}`}setupSessionTimeout(){this.clearSessionTimeout();const e=this.get("config")?.sessionTimeout??9e5;this.sessionTimeoutId=setTimeout(()=>{this.endSession("inactivity")},e)}resetSessionTimeout(){this.setupSessionTimeout();const e=this.get("sessionId");e&&this.persistSession(e)}clearSessionTimeout(){this.sessionTimeoutId&&(clearTimeout(this.sessionTimeoutId),this.sessionTimeoutId=null)}setupActivityListeners(){this.activityHandler=()=>this.resetSessionTimeout(),document.addEventListener("click",this.activityHandler,{passive:!0}),document.addEventListener("keydown",this.activityHandler,{passive:!0}),document.addEventListener("scroll",this.activityHandler,{passive:!0})}cleanupActivityListeners(){this.activityHandler&&(document.removeEventListener("click",this.activityHandler),document.removeEventListener("keydown",this.activityHandler),document.removeEventListener("scroll",this.activityHandler),this.activityHandler=null)}setupLifecycleListeners(){this.visibilityChangeHandler||this.beforeUnloadHandler||(this.visibilityChangeHandler=()=>{document.hidden?this.clearSessionTimeout():this.get("sessionId")&&this.setupSessionTimeout()},this.beforeUnloadHandler=()=>{this.endSession("page_unload")},document.addEventListener("visibilitychange",this.visibilityChangeHandler),window.addEventListener("beforeunload",this.beforeUnloadHandler))}cleanupLifecycleListeners(){this.visibilityChangeHandler&&(document.removeEventListener("visibilitychange",this.visibilityChangeHandler),this.visibilityChangeHandler=null),this.beforeUnloadHandler&&(window.removeEventListener("beforeunload",this.beforeUnloadHandler),this.beforeUnloadHandler=null)}async endSession(e){const t=this.get("sessionId");if(!t){o("warn","endSession called without active session",{data:{reason:e}}),this.resetSessionState(e);return}this.eventManager.track({type:h.SESSION_END,session_end_reason:e});const s=()=>{this.broadcastSessionEnd(t,e),this.resetSessionState(e)};if(this.eventManager.flushImmediatelySync()){s();return}try{await this.eventManager.flushImmediately(),s()}catch(i){o("warn","Async flush failed during session end",{error:i}),s()}}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 ut extends f{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){o("warn","Cannot start tracking on destroyed handler");return}const e=this.get("config"),t=e?.integrations?.tracelog?.projectId??e?.integrations?.custom?.apiUrl??"default";if(!t)throw new Error("Cannot start session tracking: config not available");try{this.sessionManager=new ct(this.storageManager,this.eventManager,t),await this.sessionManager.startTracking(),this.eventManager.flushPendingEvents()}catch(s){if(this.sessionManager){try{this.sessionManager.destroy()}catch{}this.sessionManager=null}throw o("error","Failed to start session tracking",{error:s}),s}}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 dt extends f{eventManager;onTrack;originalPushState;originalReplaceState;constructor(e,t){super(),this.eventManager=e,this.onTrack=t}startTracking(){this.trackInitialPageView(),window.addEventListener("popstate",this.trackCurrentPage,!0),window.addEventListener("hashchange",this.trackCurrentPage,!0),this.patchHistory("pushState"),this.patchHistory("replaceState")}stopTracking(){window.removeEventListener("popstate",this.trackCurrentPage,!0),window.removeEventListener("hashchange",this.trackCurrentPage,!0),this.originalPushState&&(window.history.pushState=this.originalPushState),this.originalReplaceState&&(window.history.replaceState=this.originalReplaceState)}patchHistory(e){const t=window.history[e];e==="pushState"&&!this.originalPushState?this.originalPushState=t:e==="replaceState"&&!this.originalReplaceState&&(this.originalReplaceState=t),window.history[e]=(...s)=>{t.apply(window.history,s),this.trackCurrentPage()}}trackCurrentPage=async()=>{const e=window.location.href,t=Y(e,this.get("config").sensitiveQueryParams);if(this.get("pageUrl")===t)return;this.onTrack();const s=this.get("pageUrl");this.set("pageUrl",t);const n=this.extractPageViewData();this.eventManager.track({type:h.PAGE_VIEW,page_url:this.get("pageUrl"),from_page_url:s,...n&&{page_view:n}})};trackInitialPageView(){const e=Y(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:s}=window.location,{referrer:n}=document,{title:i}=document;return!n&&!i&&!e&&!t&&!s?void 0:{...n&&{referrer:n},...i&&{title:i},...e&&{pathname:e},...t&&{search:t},...s&&{hash:s}}}}class ht extends f{eventManager;clickHandler;constructor(e){super(),this.eventManager=e}startTracking(){this.clickHandler||(this.clickHandler=e=>{const t=e,s=t.target,n=s instanceof HTMLElement?s:s instanceof Node&&s.parentElement instanceof HTMLElement?s.parentElement:null;if(!n){o("warn","Click target not found or not an element");return}const i=this.findTrackingElement(n),a=this.getRelevantClickElement(n),l=this.calculateClickCoordinates(t,n);if(i){const u=this.extractTrackingData(i);if(u){const p=this.createCustomEventData(u);this.eventManager.track({type:h.CUSTOM,custom_event:{name:p.name,...p.value&&{metadata:{value:p.value}}}})}}const c=this.generateClickData(n,a,l);this.eventManager.track({type:h.CLICK,click_data:c})},window.addEventListener("click",this.clickHandler,!0))}stopTracking(){this.clickHandler&&(window.removeEventListener("click",this.clickHandler,!0),this.clickHandler=void 0)}findTrackingElement(e){return e.hasAttribute(`${P}-name`)?e:e.closest(`[${P}-name]`)||void 0}getRelevantClickElement(e){for(const t of Ce)try{if(e.matches(t))return e;const s=e.closest(t);if(s)return s}catch(s){o("warn","Invalid selector in element search",{error:s,data:{selector:t}});continue}return e}clamp(e){return Math.max(0,Math.min(1,Number(e.toFixed(3))))}calculateClickCoordinates(e,t){const s=t.getBoundingClientRect(),n=e.clientX,i=e.clientY,a=s.width>0?this.clamp((n-s.left)/s.width):0,l=s.height>0?this.clamp((i-s.top)/s.height):0;return{x:n,y:i,relativeX:a,relativeY:l}}extractTrackingData(e){const t=e.getAttribute(`${P}-name`),s=e.getAttribute(`${P}-value`);if(t)return{element:e,name:t,...s&&{value:s}}}generateClickData(e,t,s){const{x:n,y:i,relativeX:a,relativeY:l}=s,c=this.getRelevantText(e,t),u=this.extractElementAttributes(t);return{x:n,y:i,relativeX:a,relativeY:l,tag:t.tagName.toLowerCase(),...t.id&&{id:t.id},...t.className&&{class:t.className},...c&&{text:c},...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 s=e.textContent?.trim()??"",n=t.textContent?.trim()??"";return!s&&!n?"":s&&s.length<=255?s:n.length<=255?n:n.slice(0,252)+"..."}extractElementAttributes(e){const t=["id","class","data-testid","aria-label","title","href","type","name","alt","role"],s={};for(const n of t){const i=e.getAttribute(n);i&&(s[n]=i)}return s}createCustomEventData(e){return{name:e.name,...e.value&&{value:e.value}}}}class gt extends f{eventManager;containers=[];limitWarningLogged=!1;minDepthChange=5;minIntervalMs=500;maxEventsPerSession=120;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 s=e.map(n=>this.safeQuerySelector(n)).filter(n=>n instanceof HTMLElement);if(s.length>0){for(const n of s)this.containers.some(a=>a.element===n)||this.setupScrollContainer(n);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(n),n.debounceTimer=window.setTimeout(()=>{const i=this.calculateScrollData(n);if(i){const a=Date.now();this.processScrollEvent(n,i,a)}n.debounceTimer=null},250))},s=this.getScrollTop(e),n={element:e,lastScrollPos:s,lastDepth:this.calculateScrollDepth(s,this.getScrollHeight(e),this.getViewportHeight(e)),lastDirection:b.DOWN,lastEventTime:0,debounceTimer:null,listener:t};this.containers.push(n),e instanceof Window?window.addEventListener("scroll",t,{passive:!0}):e.addEventListener("scroll",t,{passive:!0})}processScrollEvent(e,t,s){if(!this.shouldEmitScrollEvent(e,t,s))return;e.lastEventTime=s,e.lastDepth=t.depth,e.lastDirection=t.direction;const n=this.get("scrollEventCount")??0;this.set("scrollEventCount",n+1),this.eventManager.track({type:h.SCROLL,scroll_data:t})}shouldEmitScrollEvent(e,t,s){return this.hasReachedSessionLimit()?(this.logLimitOnce(),!1):!(!this.hasElapsedMinimumInterval(e,s)||!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,o("warn","Max scroll events per session reached",{data:{limit:this.maxEventsPerSession}}))}applyConfigOverrides(){this.minDepthChange=5,this.minIntervalMs=500,this.maxEventsPerSession=120}isWindowScrollable(){return document.documentElement.scrollHeight>window.innerHeight}clearContainerTimer(e){e.debounceTimer!==null&&(clearTimeout(e.debounceTimer),e.debounceTimer=null)}getScrollDirection(e,t){return e>t?b.DOWN:b.UP}calculateScrollDepth(e,t,s){if(t<=s)return 0;const n=t-s;return Math.min(100,Math.max(0,Math.floor(e/n*100)))}calculateScrollData(e){const{element:t,lastScrollPos:s}=e,n=this.getScrollTop(t);if(Math.abs(n-s)<10||t===window&&!this.isWindowScrollable())return null;const a=this.getViewportHeight(t),l=this.getScrollHeight(t),c=this.getScrollDirection(n,s),u=this.calculateScrollDepth(n,l,a);return e.lastScrollPos=n,{depth:u,direction:c}}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),s=t.overflowY==="auto"||t.overflowY==="scroll"||t.overflowX==="auto"||t.overflowX==="scroll"||t.overflow==="auto"||t.overflow==="scroll",n=e.scrollHeight>e.clientHeight||e.scrollWidth>e.clientWidth;return s&&n}safeQuerySelector(e){try{return document.querySelector(e)}catch(t){return o("warn","Invalid CSS selector",{error:t,data:{selector:e},showToClient:!0}),null}}}class ft extends f{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(s){o("error","Google Analytics initialization failed",{error:s})}}trackEvent(e,t){if(!(!e?.trim()||!this.isInitialized||typeof window.gtag!="function"))try{const s=Array.isArray(t)?{items:t}:t;window.gtag("event",e,s)}catch(s){o("error","Google Analytics event tracking failed",{error:s})}}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,s)=>{const n=document.createElement("script");n.id="tracelog-ga-script",n.async=!0,n.src=`https://www.googletagmanager.com/gtag/js?id=${e}`,n.onload=()=>t(),n.onerror=()=>s(new Error("Failed to load Google Analytics script")),document.head.appendChild(n)})}configureGtag(e,t){const s=document.createElement("script");s.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: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);
8
+ `,document.head.appendChild(s)}}class St{storage;sessionStorageRef;fallbackStorage=new Map;fallbackSessionStorage=new Map;hasQuotaExceededError=!1;constructor(){this.storage=this.initializeStorage("localStorage"),this.sessionStorageRef=this.initializeStorage("sessionStorage"),this.storage||o("warn","localStorage not available, using memory fallback"),this.sessionStorageRef||o("warn","sessionStorage not available, using memory fallback")}getItem(e){try{return this.storage?this.storage.getItem(e):this.fallbackStorage.get(e)??null}catch{return this.fallbackStorage.get(e)??null}}setItem(e,t){try{if(this.storage){this.storage.setItem(e,t);return}}catch(s){s instanceof DOMException&&s.name==="QuotaExceededError"&&(this.hasQuotaExceededError=!0,o("error","localStorage quota exceeded - data will not persist after reload",{error:s,data:{key:e,valueSize:t.length}}))}this.fallbackStorage.set(e,t)}removeItem(e){try{this.storage&&this.storage.removeItem(e)}catch{}this.fallbackStorage.delete(e)}clear(){if(!this.storage){this.fallbackStorage.clear();return}try{const e=[];for(let t=0;t<this.storage.length;t++){const s=this.storage.key(t);s?.startsWith("tracelog_")&&e.push(s)}e.forEach(t=>this.storage.removeItem(t)),this.fallbackStorage.clear()}catch(e){o("error","Failed to clear storage",{error:e}),this.fallbackStorage.clear()}}isAvailable(){return this.storage!==null}hasQuotaError(){return this.hasQuotaExceededError}initializeStorage(e){if(typeof window>"u")return null;try{const t=e==="localStorage"?window.localStorage:window.sessionStorage,s="__tracelog_test__";return t.setItem(s,"test"),t.removeItem(s),t}catch{return null}}getSessionItem(e){try{return this.sessionStorageRef?this.sessionStorageRef.getItem(e):this.fallbackSessionStorage.get(e)??null}catch{return this.fallbackSessionStorage.get(e)??null}}setSessionItem(e,t){try{if(this.sessionStorageRef){this.sessionStorageRef.setItem(e,t);return}}catch(s){s instanceof DOMException&&s.name==="QuotaExceededError"&&o("error","sessionStorage quota exceeded - data will not persist",{error:s,data:{key:e,valueSize:t.length}})}this.fallbackSessionStorage.set(e,t)}removeSessionItem(e){try{this.sessionStorageRef&&this.sessionStorageRef.removeItem(e)}catch{}this.fallbackSessionStorage.delete(e)}}class Et extends f{eventManager;reportedByNav=new Map;observers=[];lastLongTaskSentAt=0;vitalThresholds=de;constructor(e){super(),this.eventManager=e}async startTracking(){await this.initWebVitals(),this.observeLongTasks()}stopTracking(){this.observers.forEach((e,t)=>{try{e.disconnect()}catch(s){o("warn","Failed to disconnect performance observer",{error:s,data:{observerIndex:t}})}}),this.observers.length=0,this.reportedByNav.clear()}observeWebVitalsFallback(){this.reportTTFB(),this.safeObserve("largest-contentful-paint",s=>{const n=s.getEntries(),i=n[n.length-1];i&&this.sendVital({type:"LCP",value:Number(i.startTime.toFixed(2))})},{type:"largest-contentful-paint",buffered:!0},!0);let e=0,t=this.getNavigationId();this.safeObserve("layout-shift",s=>{const n=this.getNavigationId();n!==t&&(e=0,t=n);const i=s.getEntries();for(const a of i){if(a.hadRecentInput===!0)continue;const l=typeof a.value=="number"?a.value:0;e+=l}this.sendVital({type:"CLS",value:Number(e.toFixed(2))})},{type:"layout-shift",buffered:!0}),this.safeObserve("paint",s=>{for(const n of s.getEntries())n.name==="first-contentful-paint"&&this.sendVital({type:"FCP",value:Number(n.startTime.toFixed(2))})},{type:"paint",buffered:!0},!0),this.safeObserve("event",s=>{let n=0;const i=s.getEntries();for(const a of i){const l=(a.processingEnd??0)-(a.startTime??0);n=Math.max(n,l)}n>0&&this.sendVital({type:"INP",value:Number(n.toFixed(2))})},{type:"event",buffered:!0})}async initWebVitals(){try{const{onLCP:e,onCLS:t,onFCP:s,onTTFB:n,onINP:i}=await Promise.resolve().then(()=>Wt),a=l=>c=>{const u=Number(c.value.toFixed(2));this.sendVital({type:l,value:u})};e(a("LCP")),t(a("CLS")),s(a("FCP")),n(a("TTFB")),i(a("INP"))}catch(e){o("warn","Failed to load web-vitals library, using fallback",{error:e}),this.observeWebVitalsFallback()}}reportTTFB(){try{const e=performance.getEntriesByType("navigation")[0];if(!e)return;const t=e.responseStart;typeof t=="number"&&Number.isFinite(t)&&this.sendVital({type:"TTFB",value:Number(t.toFixed(2))})}catch(e){o("warn","Failed to report TTFB",{error:e})}}observeLongTasks(){this.safeObserve("longtask",e=>{const t=e.getEntries();for(const s of t){const n=Number(s.duration.toFixed(2)),i=Date.now();i-this.lastLongTaskSentAt>=Ge&&(this.shouldSendVital("LONG_TASK",n)&&this.trackWebVital("LONG_TASK",n),this.lastLongTaskSentAt=i)}},{type:"longtask",buffered:!0})}sendVital(e){if(!this.shouldSendVital(e.type,e.value))return;const t=this.getNavigationId();if(t){const s=this.reportedByNav.get(t);if(s?.has(e.type))return;s?s.add(e.type):this.reportedByNav.set(t,new Set([e.type]))}this.trackWebVital(e.type,e.value)}trackWebVital(e,t){if(!Number.isFinite(t)){o("warn","Invalid web vital value",{data:{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(),s=Math.random().toString(36).substr(2,5);return`${t.toFixed(2)}_${window.location.pathname}_${s}`}catch(e){return o("warn","Failed to get navigation ID",{error:e}),null}}isObserverSupported(e){if(typeof PerformanceObserver>"u")return!1;const t=PerformanceObserver.supportedEntryTypes;return!t||t.includes(e)}safeObserve(e,t,s,n=!1){try{if(!this.isObserverSupported(e))return!1;const i=new PerformanceObserver((a,l)=>{try{t(a,l)}catch(c){o("warn","Observer callback failed",{error:c,data:{type:e}})}if(n)try{l.disconnect()}catch{}});return i.observe(s??{type:e,buffered:!0}),n||this.observers.push(i),!0}catch(i){return o("warn","Failed to create performance observer",{error:i,data:{type:e}}),!1}}shouldSendVital(e,t){if(typeof t!="number"||!Number.isFinite(t))return o("warn","Invalid web vital value",{data:{type:e,value:t}}),!1;const s=this.vitalThresholds[e];return!(typeof s=="number"&&t<=s)}}class mt extends f{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(A.JS_ERROR,t)||this.eventManager.track({type:h.ERROR,error_data:{type:A.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),s=this.sanitize(t);this.shouldSuppressError(A.PROMISE_REJECTION,s)||this.eventManager.track({type:h.ERROR,error_data:{type:A.PROMISE_REJECTION,message:s}})};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>ge?e.slice(0,ge)+"...":e;for(const s of he){const n=new RegExp(s.source,s.flags);t=t.replace(n,"[REDACTED]")}return t}shouldSuppressError(e,t){const s=Date.now(),n=`${e}:${t}`,i=this.recentErrors.get(n);return i&&s-i<fe?(this.recentErrors.set(n,s),!0):(this.recentErrors.set(n,s),this.recentErrors.size>Qe?(this.recentErrors.clear(),this.recentErrors.set(n,s),!1):(this.recentErrors.size>U&&this.pruneOldErrors(),!1))}pruneOldErrors(){const e=Date.now();for(const[n,i]of this.recentErrors.entries())e-i>fe&&this.recentErrors.delete(n);if(this.recentErrors.size<=U)return;const t=Array.from(this.recentErrors.entries()).sort((n,i)=>n[1]-i[1]),s=this.recentErrors.size-U;for(let n=0;n<s;n+=1){const i=t[n];i&&this.recentErrors.delete(i[0])}}}class pt extends f{isInitialized=!1;suppressNextScrollTimer=null;emitter=new it;managers={};handlers={};integrations={};get initialized(){return this.isInitialized}async init(e){if(!this.isInitialized){this.managers.storage=new St;try{this.setupState(e),await this.setupIntegrations(),this.managers.event=new ot(this.managers.storage,this.integrations.googleAnalytics,this.emitter),await this.initializeHandlers(),await this.managers.event.recoverPersistedEvents().catch(t=>{o("warn","Failed to recover persisted events",{error:t})}),this.isInitialized=!0}catch(t){await this.destroy(!0);const s=t instanceof Error?t.message:String(t);throw new Error(`[TraceLog] TraceLog initialization failed: ${s}`)}}}sendCustomEvent(e,t){if(!this.managers.event)return;const{valid:s,error:n,sanitizedMetadata:i}=nt(e,t);if(!s){if(this.get("mode")===w.QA)throw new Error(`[TraceLog] Custom event "${e}" validation failed: ${n}`);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 s=>{try{await s.stopTracking()}catch(n){o("warn","Failed to stop tracking",{error:n})}});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={}}setupState(e){this.set("config",e);const t=lt.getId(this.managers.storage);this.set("userId",t);const s=Ye(e);this.set("apiUrl",s);const n=Ue();this.set("device",n);const i=Y(window.location.href,e.sensitiveQueryParams);this.set("pageUrl",i);const a=ze()?w.QA:void 0;a&&this.set("mode",a)}async setupIntegrations(){if(this.get("config").integrations?.googleAnalytics?.measurementId?.trim())try{this.integrations.googleAnalytics=new ft,await this.integrations.googleAnalytics.initialize()}catch{this.integrations.googleAnalytics=void 0}}async initializeHandlers(){this.handlers.session=new ut(this.managers.storage,this.managers.event),await this.handlers.session.startTracking();const e=()=>{this.set("suppressNextScroll",!0),this.suppressNextScrollTimer&&clearTimeout(this.suppressNextScrollTimer),this.suppressNextScrollTimer=window.setTimeout(()=>{this.set("suppressNextScroll",!1)},250*2)};this.handlers.pageView=new dt(this.managers.event,e),this.handlers.pageView.startTracking(),this.handlers.click=new ht(this.managers.event),this.handlers.click.startTracking(),this.handlers.scroll=new gt(this.managers.event),this.handlers.scroll.startTracking(),this.handlers.performance=new Et(this.managers.event),this.handlers.performance.startTracking().catch(t=>{o("warn","Failed to start performance tracking",{error:t})}),this.handlers.error=new mt(this.managers.event),this.handlers.error.startTracking()}}const y=[];let g=null,L=!1,H=!1;const Tt=async r=>{if(typeof window>"u"||typeof document>"u")throw new Error("[TraceLog] This library can only be used in a browser environment");if(!window.__traceLogDisabled&&!g&&!L){L=!0;try{const e=Ze(r),t=new pt;try{y.forEach(({event:s,callback:n})=>{t.on(s,n)}),y.length=0,await t.init(e),g=t}catch(s){try{await t.destroy(!0)}catch(n){o("error","Failed to cleanup partially initialized app",{error:n})}throw s}}catch(e){throw g=null,e}finally{L=!1}}},_t=(r,e)=>{if(!g)throw new Error("[TraceLog] TraceLog not initialized. Please call init() first.");if(H)throw new Error("[TraceLog] Cannot send events while TraceLog is being destroyed");g.sendCustomEvent(r,e)},vt=(r,e)=>{if(!g||L){y.push({event:r,callback:e});return}g.on(r,e)},It=(r,e)=>{if(!g){const t=y.findIndex(s=>s.event===r&&s.callback===e);t!==-1&&y.splice(t,1);return}g.off(r,e)},yt=()=>g!==null,At=async()=>{if(!g)throw new Error("[TraceLog] App not initialized");if(H)throw new Error("[TraceLog] Destroy operation already in progress");H=!0;try{await g.destroy(),g=null,L=!1,y.length=0}catch(r){throw g=null,L=!1,y.length=0,o("error","Error during destroy, forced cleanup",{error:r}),r}finally{H=!1}},wt={WEB_VITALS_THRESHOLDS:de},Mt={PII_PATTERNS:he},Nt={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},Lt={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},Rt={MOBILE_MAX_WIDTH:768,TABLET_MAX_WIDTH:1024,MOBILE_PERFORMANCE_FACTOR:1.5,TABLET_PERFORMANCE_FACTOR:1.2},Ct={MIN_TEXT_LENGTH_FOR_ANALYSIS:10,MIN_CLICKS_FOR_HOT_ELEMENT:10,MIN_SCROLL_COMPLETION_PERCENT:80,MIN_TIME_ON_PAGE_FOR_READ_MS:15*1e3},bt={SIGNIFICANT_CHANGE_PERCENT:20,MAJOR_CHANGE_PERCENT:50,MIN_EVENTS_FOR_INSIGHT:100,MIN_SESSIONS_FOR_INSIGHT:10,MIN_CORRELATION_STRENGTH:.7,LOW_ERROR_RATE_PERCENT:1,HIGH_ERROR_RATE_PERCENT:5,CRITICAL_ERROR_RATE_PERCENT:10},Ot={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},Pt={MIN_SEGMENT_SIZE:10,MIN_COHORT_SIZE:5,COHORT_ANALYSIS_DAYS:[1,3,7,14,30],MIN_FUNNEL_EVENTS:20},Dt={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},kt={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},Ut={PAGE_URL_EXCLUDED:"excluded",PAGE_URL_UNKNOWN:"unknown"},Ht={init:Tt,event:_t,on:vt,off:It,isInitialized:yt,destroy:At};var K,_e=-1,R=function(r){addEventListener("pageshow",function(e){e.persisted&&(_e=e.timeStamp,r(e))},!0)},q=function(){var r=self.performance&&performance.getEntriesByType&&performance.getEntriesByType("navigation")[0];if(r&&r.responseStart>0&&r.responseStart<performance.now())return r},V=function(){var r=q();return r&&r.activationStart||0},S=function(r,e){var t=q(),s="navigate";return _e>=0?s="back-forward-cache":t&&(document.prerendering||V()>0?s="prerender":document.wasDiscarded?s="restore":t.type&&(s=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:s}},O=function(r,e,t){try{if(PerformanceObserver.supportedEntryTypes.includes(r)){var s=new PerformanceObserver(function(n){Promise.resolve().then(function(){e(n.getEntries())})});return s.observe(Object.assign({type:r,buffered:!0},t||{})),s}}catch{}},E=function(r,e,t,s){var n,i;return function(a){e.value>=0&&(a||s)&&((i=e.value-(n||0))||n===void 0)&&(n=e.value,e.delta=i,e.rating=function(l,c){return l>c[1]?"poor":l>c[0]?"needs-improvement":"good"}(e.value,t),r(e))}},J=function(r){requestAnimationFrame(function(){return requestAnimationFrame(function(){return r()})})},x=function(r){document.addEventListener("visibilitychange",function(){document.visibilityState==="hidden"&&r()})},Z=function(r){var e=!1;return function(){e||(r(),e=!0)}},C=-1,ve=function(){return document.visibilityState!=="hidden"||document.prerendering?1/0:0},F=function(r){document.visibilityState==="hidden"&&C>-1&&(C=r.type==="visibilitychange"?r.timeStamp:0,Vt())},Ie=function(){addEventListener("visibilitychange",F,!0),addEventListener("prerenderingchange",F,!0)},Vt=function(){removeEventListener("visibilitychange",F,!0),removeEventListener("prerenderingchange",F,!0)},ye=function(){return C<0&&(C=ve(),Ie(),R(function(){setTimeout(function(){C=ve(),Ie()},0)})),{get firstHiddenTime(){return C}}},G=function(r){document.prerendering?addEventListener("prerenderingchange",function(){return r()},!0):r()},ee=[1800,3e3],Ae=function(r,e){e=e||{},G(function(){var t,s=ye(),n=S("FCP"),i=O("paint",function(a){a.forEach(function(l){l.name==="first-contentful-paint"&&(i.disconnect(),l.startTime<s.firstHiddenTime&&(n.value=Math.max(l.startTime-V(),0),n.entries.push(l),t(!0)))})});i&&(t=E(r,n,ee,e.reportAllChanges),R(function(a){n=S("FCP"),t=E(r,n,ee,e.reportAllChanges),J(function(){n.value=performance.now()-a.timeStamp,t(!0)})}))})},te=[.1,.25],xt=function(r,e){e=e||{},Ae(Z(function(){var t,s=S("CLS",0),n=0,i=[],a=function(c){c.forEach(function(u){if(!u.hadRecentInput){var p=i[0],z=i[i.length-1];n&&u.startTime-z.startTime<1e3&&u.startTime-p.startTime<5e3?(n+=u.value,i.push(u)):(n=u.value,i=[u])}}),n>s.value&&(s.value=n,s.entries=i,t())},l=O("layout-shift",a);l&&(t=E(r,s,te,e.reportAllChanges),x(function(){a(l.takeRecords()),t(!0)}),R(function(){n=0,s=S("CLS",0),t=E(r,s,te,e.reportAllChanges),J(function(){return t()})}),setTimeout(t,0))}))},we=0,re=1/0,Q=0,Ft=function(r){r.forEach(function(e){e.interactionId&&(re=Math.min(re,e.interactionId),Q=Math.max(Q,e.interactionId),we=Q?(Q-re)/7+1:0)})},Me=function(){return K?we:performance.interactionCount||0},Gt=function(){"interactionCount"in performance||K||(K=O("event",Ft,{type:"event",buffered:!0,durationThreshold:0}))},m=[],$=new Map,Ne=0,Qt=function(){var r=Math.min(m.length-1,Math.floor((Me()-Ne)/50));return m[r]},$t=[],zt=function(r){if($t.forEach(function(n){return n(r)}),r.interactionId||r.entryType==="first-input"){var e=m[m.length-1],t=$.get(r.interactionId);if(t||m.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 s={id:r.interactionId,latency:r.duration,entries:[r]};$.set(s.id,s),m.push(s)}m.sort(function(n,i){return i.latency-n.latency}),m.length>10&&m.splice(10).forEach(function(n){return $.delete(n.id)})}}},Le=function(r){var e=self.requestIdleCallback||self.setTimeout,t=-1;return r=Z(r),document.visibilityState==="hidden"?r():(t=e(r),x(r)),t},se=[200,500],jt=function(r,e){"PerformanceEventTiming"in self&&"interactionId"in PerformanceEventTiming.prototype&&(e=e||{},G(function(){var t;Gt();var s,n=S("INP"),i=function(l){Le(function(){l.forEach(zt);var c=Qt();c&&c.latency!==n.value&&(n.value=c.latency,n.entries=c.entries,s())})},a=O("event",i,{durationThreshold:(t=e.durationThreshold)!==null&&t!==void 0?t:40});s=E(r,n,se,e.reportAllChanges),a&&(a.observe({type:"first-input",buffered:!0}),x(function(){i(a.takeRecords()),s(!0)}),R(function(){Ne=Me(),m.length=0,$.clear(),n=S("INP"),s=E(r,n,se,e.reportAllChanges)}))}))},ne=[2500,4e3],ie={},Bt=function(r,e){e=e||{},G(function(){var t,s=ye(),n=S("LCP"),i=function(c){e.reportAllChanges||(c=c.slice(-1)),c.forEach(function(u){u.startTime<s.firstHiddenTime&&(n.value=Math.max(u.startTime-V(),0),n.entries=[u],t())})},a=O("largest-contentful-paint",i);if(a){t=E(r,n,ne,e.reportAllChanges);var l=Z(function(){ie[n.id]||(i(a.takeRecords()),a.disconnect(),ie[n.id]=!0,t(!0))});["keydown","click"].forEach(function(c){addEventListener(c,function(){return Le(l)},{once:!0,capture:!0})}),x(l),R(function(c){n=S("LCP"),t=E(r,n,ne,e.reportAllChanges),J(function(){n.value=performance.now()-c.timeStamp,ie[n.id]=!0,t(!0)})})}})},ae=[800,1800],Yt=function r(e){document.prerendering?G(function(){return r(e)}):document.readyState!=="complete"?addEventListener("load",function(){return r(e)},!0):setTimeout(e,0)},Xt=function(r,e){e=e||{};var t=S("TTFB"),s=E(r,t,ae,e.reportAllChanges);Yt(function(){var n=q();n&&(t.value=Math.max(n.responseStart-V(),0),t.entries=[n],s(!0),R(function(){t=S("TTFB",0),(s=E(r,t,ae,e.reportAllChanges))(!0)}))})};const Wt=Object.freeze(Object.defineProperty({__proto__:null,CLSThresholds:te,FCPThresholds:ee,INPThresholds:se,LCPThresholds:ne,TTFBThresholds:ae,onCLS:xt,onFCP:Ae,onINP:jt,onLCP:Bt,onTTFB:Xt},Symbol.toStringTag,{value:"Module"}));d.ANALYTICS_QUERY_LIMITS=Dt,d.ANOMALY_DETECTION=kt,d.AppConfigValidationError=v,d.CONTENT_ANALYTICS=Ct,d.DATA_PROTECTION=Mt,d.DEVICE_ANALYTICS=Rt,d.DeviceType=_,d.ENGAGEMENT_THRESHOLDS=Nt,d.EmitterEvent=k,d.ErrorType=A,d.EventType=h,d.INSIGHT_THRESHOLDS=bt,d.InitializationTimeoutError=Pe,d.IntegrationValidationError=N,d.Mode=w,d.PERFORMANCE_CONFIG=wt,d.SEGMENTATION_ANALYTICS=Pt,d.SESSION_ANALYTICS=Lt,d.SPECIAL_PAGE_URLS=Ut,d.SamplingRateValidationError=j,d.ScrollDirection=b,d.SessionTimeoutValidationError=le,d.SpecialApiUrl=D,d.TEMPORAL_ANALYSIS=Ot,d.TraceLogValidationError=M,d.tracelog=Ht,Object.defineProperty(d,Symbol.toStringTag,{value:"Module"})})(this.TraceLog=this.TraceLog||{});typeof window<"u"&&window.TraceLog?.tracelog&&(window.tracelog=window.TraceLog.tracelog);
package/dist/cjs/api.d.ts CHANGED
@@ -1,8 +1,18 @@
1
- import { MetadataType, AppConfig, EmitterCallback, EmitterMap } from './types';
1
+ import { App } from './app';
2
+ import { MetadataType, Config, EmitterCallback, EmitterMap } from './types';
2
3
  import './types/window.types';
3
- export declare const init: (appConfig: AppConfig) => Promise<void>;
4
+ export declare const init: (config: Config) => Promise<void>;
4
5
  export declare const event: (name: string, metadata?: Record<string, MetadataType> | Record<string, MetadataType>[]) => void;
5
6
  export declare const on: <K extends keyof EmitterMap>(event: K, callback: EmitterCallback<EmitterMap[K]>) => void;
6
7
  export declare const off: <K extends keyof EmitterMap>(event: K, callback: EmitterCallback<EmitterMap[K]>) => void;
7
8
  export declare const isInitialized: () => boolean;
8
9
  export declare const destroy: () => Promise<void>;
10
+ /**
11
+ * Internal sync function - ONLY for TestBridge in development
12
+ *
13
+ * WARNING: This function is internal and should NEVER be called directly.
14
+ * It's only exported for TestBridge synchronization in dev mode.
15
+ *
16
+ * @internal
17
+ */
18
+ export declare const __setAppInstance: (instance: App | null) => void;
package/dist/cjs/api.js CHANGED
@@ -1,51 +1,53 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.destroy = exports.isInitialized = exports.off = exports.on = exports.event = exports.init = void 0;
3
+ exports.__setAppInstance = exports.destroy = exports.isInitialized = exports.off = exports.on = exports.event = exports.init = void 0;
4
4
  const app_1 = require("./app");
5
5
  const utils_1 = require("./utils");
6
6
  const test_bridge_1 = require("./test-bridge");
7
7
  require("./types/window.types");
8
+ // Buffer for listeners registered before init()
9
+ const pendingListeners = [];
8
10
  let app = null;
9
11
  let isInitializing = false;
10
12
  let isDestroying = false;
11
- const init = async (appConfig) => {
13
+ const init = async (config) => {
12
14
  if (typeof window === 'undefined' || typeof document === 'undefined') {
13
- throw new Error('This library can only be used in a browser environment');
15
+ throw new Error('[TraceLog] This library can only be used in a browser environment');
14
16
  }
15
17
  if (window.__traceLogDisabled) {
16
18
  return;
17
19
  }
18
20
  if (app) {
19
- utils_1.debugLog.debug('API', 'Library already initialized, skipping duplicate initialization');
20
21
  return;
21
22
  }
22
23
  if (isInitializing) {
23
- utils_1.debugLog.warn('API', 'Initialization already in progress');
24
- throw new Error('Initialization already in progress');
24
+ return;
25
25
  }
26
26
  isInitializing = true;
27
27
  try {
28
- utils_1.debugLog.info('API', 'Initializing TraceLog', { projectId: appConfig.id });
29
- const validatedConfig = (0, utils_1.validateAndNormalizeConfig)(appConfig);
28
+ const validatedConfig = (0, utils_1.validateAndNormalizeConfig)(config);
30
29
  const instance = new app_1.App();
31
30
  try {
31
+ // Attach buffered listeners BEFORE init() so they capture initial events
32
+ pendingListeners.forEach(({ event, callback }) => {
33
+ instance.on(event, callback);
34
+ });
35
+ pendingListeners.length = 0;
32
36
  await instance.init(validatedConfig);
33
37
  app = instance;
34
- utils_1.debugLog.info('API', 'TraceLog initialized successfully', { projectId: validatedConfig.id });
35
38
  }
36
39
  catch (error) {
37
40
  try {
38
41
  await instance.destroy(true);
39
42
  }
40
43
  catch (cleanupError) {
41
- utils_1.debugLog.warn('API', 'Failed to cleanup partially initialized app', { cleanupError });
44
+ (0, utils_1.log)('error', 'Failed to cleanup partially initialized app', { error: cleanupError });
42
45
  }
43
46
  throw error;
44
47
  }
45
48
  }
46
49
  catch (error) {
47
50
  app = null;
48
- utils_1.debugLog.error('API', 'Initialization failed', { error });
49
51
  throw error;
50
52
  }
51
53
  finally {
@@ -55,27 +57,31 @@ const init = async (appConfig) => {
55
57
  exports.init = init;
56
58
  const event = (name, metadata) => {
57
59
  if (!app) {
58
- throw new Error('TraceLog not initialized. Please call init() first.');
59
- }
60
- try {
61
- app.sendCustomEvent(name, metadata);
60
+ throw new Error('[TraceLog] TraceLog not initialized. Please call init() first.');
62
61
  }
63
- catch (error) {
64
- utils_1.debugLog.error('API', 'Failed to send custom event', { eventName: name, error });
65
- throw error;
62
+ if (isDestroying) {
63
+ throw new Error('[TraceLog] Cannot send events while TraceLog is being destroyed');
66
64
  }
65
+ app.sendCustomEvent(name, metadata);
67
66
  };
68
67
  exports.event = event;
69
68
  const on = (event, callback) => {
70
- if (!app) {
71
- throw new Error('TraceLog not initialized. Please call init() first.');
69
+ if (!app || isInitializing) {
70
+ // Buffer listeners registered before or during init()
71
+ pendingListeners.push({ event, callback });
72
+ return;
72
73
  }
73
74
  app.on(event, callback);
74
75
  };
75
76
  exports.on = on;
76
77
  const off = (event, callback) => {
77
78
  if (!app) {
78
- throw new Error('TraceLog not initialized. Please call init() first.');
79
+ // Remove from pending listeners if not yet initialized
80
+ const index = pendingListeners.findIndex((l) => l.event === event && l.callback === callback);
81
+ if (index !== -1) {
82
+ pendingListeners.splice(index, 1);
83
+ }
84
+ return;
79
85
  }
80
86
  app.off(event, callback);
81
87
  };
@@ -86,24 +92,28 @@ const isInitialized = () => {
86
92
  exports.isInitialized = isInitialized;
87
93
  const destroy = async () => {
88
94
  if (!app) {
89
- throw new Error('App not initialized');
95
+ throw new Error('[TraceLog] App not initialized');
90
96
  }
91
97
  if (isDestroying) {
92
- throw new Error('Destroy operation already in progress');
98
+ throw new Error('[TraceLog] Destroy operation already in progress');
93
99
  }
94
100
  isDestroying = true;
95
101
  try {
96
- utils_1.debugLog.info('API', 'Destroying TraceLog instance');
97
102
  await app.destroy();
98
103
  app = null;
99
104
  isInitializing = false;
100
- utils_1.debugLog.info('API', 'TraceLog destroyed successfully');
105
+ pendingListeners.length = 0;
106
+ // Clear TestBridge reference in dev mode to prevent stale references
107
+ if (process.env.NODE_ENV === 'dev' && typeof window !== 'undefined' && window.__traceLogBridge) {
108
+ // Don't call destroy on bridge (would cause recursion), just clear reference
109
+ window.__traceLogBridge = undefined;
110
+ }
101
111
  }
102
112
  catch (error) {
103
- // Force cleanup even if destroy fails
104
113
  app = null;
105
114
  isInitializing = false;
106
- utils_1.debugLog.error('API', 'Error during destroy, forced cleanup', { error });
115
+ pendingListeners.length = 0;
116
+ (0, utils_1.log)('error', 'Error during destroy, forced cleanup', { error });
107
117
  throw error;
108
118
  }
109
119
  finally {
@@ -122,3 +132,29 @@ if (process.env.NODE_ENV === 'dev' && typeof window !== 'undefined') {
122
132
  injectTestingBridge();
123
133
  }
124
134
  }
135
+ /**
136
+ * Internal sync function - ONLY for TestBridge in development
137
+ *
138
+ * WARNING: This function is internal and should NEVER be called directly.
139
+ * It's only exported for TestBridge synchronization in dev mode.
140
+ *
141
+ * @internal
142
+ */
143
+ const __setAppInstance = (instance) => {
144
+ if (instance !== null) {
145
+ const hasRequiredMethods = typeof instance === 'object' &&
146
+ 'init' in instance &&
147
+ 'destroy' in instance &&
148
+ 'on' in instance &&
149
+ 'off' in instance;
150
+ if (!hasRequiredMethods) {
151
+ throw new Error('[TraceLog] Invalid app instance type');
152
+ }
153
+ }
154
+ // Prevent overwriting an already initialized app (except when clearing)
155
+ if (app !== null && instance !== null && app !== instance) {
156
+ throw new Error('[TraceLog] Cannot overwrite existing app instance. Call destroy() first.');
157
+ }
158
+ app = instance;
159
+ };
160
+ exports.__setAppInstance = __setAppInstance;
package/dist/cjs/app.d.ts CHANGED
@@ -4,7 +4,7 @@ import { SessionHandler } from './handlers/session.handler';
4
4
  import { PageViewHandler } from './handlers/page-view.handler';
5
5
  import { ClickHandler } from './handlers/click.handler';
6
6
  import { ScrollHandler } from './handlers/scroll.handler';
7
- import { AppConfig, EmitterCallback, EmitterMap } from './types';
7
+ import { Config, EmitterCallback, EmitterMap } from './types';
8
8
  import { GoogleAnalyticsIntegration } from './integrations/google-analytics.integration';
9
9
  import { StorageManager } from './managers/storage.manager';
10
10
  import { PerformanceHandler } from './handlers/performance.handler';
@@ -29,7 +29,7 @@ export declare class App extends StateManager {
29
29
  googleAnalytics?: GoogleAnalyticsIntegration;
30
30
  };
31
31
  get initialized(): boolean;
32
- init(appConfig: AppConfig): Promise<void>;
32
+ init(config: Config): Promise<void>;
33
33
  sendCustomEvent(name: string, metadata?: Record<string, unknown> | Record<string, unknown>[]): void;
34
34
  on<K extends keyof EmitterMap>(event: K, callback: EmitterCallback<EmitterMap[K]>): void;
35
35
  off<K extends keyof EmitterMap>(event: K, callback: EmitterCallback<EmitterMap[K]>): void;