@tracelog/lib 0.5.1 → 0.5.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +4 -4
- package/dist/browser/tracelog.js +1 -1
- package/dist/cjs/constants/performance.constants.d.ts +1 -1
- package/dist/cjs/constants/performance.constants.js +1 -1
- package/dist/esm/constants/performance.constants.d.ts +1 -1
- package/dist/esm/constants/performance.constants.js +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -20,7 +20,7 @@ A lightweight TypeScript library for web analytics and user behavior tracking. A
|
|
|
20
20
|
| Your Setup | File to Use | How to Use |
|
|
21
21
|
|-----------|-------------|------------|
|
|
22
22
|
| **npm/yarn** (React, Vue, Angular, etc.) | Automatic | `import { tracelog } from '@tracelog/lib'` |
|
|
23
|
-
| **HTML + `<script>` tag** | `tracelog.js` (IIFE) | `<script src="...tracelog.js"></script>` then use `tracelog.init()` |
|
|
23
|
+
| **HTML + `<script>` tag** | `tracelog.js` (IIFE) | `<script src="...tracelog.js"></script>` then use `TraceLog.tracelog.init()` |
|
|
24
24
|
| **HTML + `<script type="module">`** | `tracelog.esm.js` (ESM) | `import { tracelog } from '...tracelog.esm.js'` |
|
|
25
25
|
|
|
26
26
|
### Installation Methods
|
|
@@ -45,9 +45,9 @@ tracelog.event('user_action', { data: 'example' });
|
|
|
45
45
|
```html
|
|
46
46
|
<script src="https://cdn.jsdelivr.net/npm/@tracelog/lib@latest/dist/browser/tracelog.js"></script>
|
|
47
47
|
<script>
|
|
48
|
-
//
|
|
49
|
-
tracelog.init({ id: 'your-project-id' });
|
|
50
|
-
tracelog.event('page_view');
|
|
48
|
+
// TraceLog is available globally
|
|
49
|
+
TraceLog.tracelog.init({ id: 'your-project-id' });
|
|
50
|
+
TraceLog.tracelog.event('page_view');
|
|
51
51
|
</script>
|
|
52
52
|
```
|
|
53
53
|
|
package/dist/browser/tracelog.js
CHANGED
|
@@ -5,4 +5,4 @@
|
|
|
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||{});
|
|
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||{});
|
|
@@ -12,7 +12,7 @@ import { WebVitalType } from '../types';
|
|
|
12
12
|
* - FCP (First Contentful Paint): 1800ms threshold (good threshold)
|
|
13
13
|
* - CLS (Cumulative Layout Shift): 0.25 threshold (unitless, needs improvement threshold)
|
|
14
14
|
* - INP (Interaction to Next Paint): 200ms threshold (good threshold)
|
|
15
|
-
* - TTFB (Time to First Byte): 800ms threshold (good
|
|
15
|
+
* - TTFB (Time to First Byte): 800ms threshold (good/needs improvement boundary, aligned with Web Vitals standard)
|
|
16
16
|
* - LONG_TASK: 50ms threshold for long task detection
|
|
17
17
|
*/
|
|
18
18
|
export declare const WEB_VITALS_THRESHOLDS: Record<WebVitalType, number>;
|
|
@@ -17,7 +17,7 @@ exports.PERFORMANCE_PRECISION_DECIMALS = exports.LONG_TASK_THROTTLE_MS = exports
|
|
|
17
17
|
* - FCP (First Contentful Paint): 1800ms threshold (good threshold)
|
|
18
18
|
* - CLS (Cumulative Layout Shift): 0.25 threshold (unitless, needs improvement threshold)
|
|
19
19
|
* - INP (Interaction to Next Paint): 200ms threshold (good threshold)
|
|
20
|
-
* - TTFB (Time to First Byte): 800ms threshold (good
|
|
20
|
+
* - TTFB (Time to First Byte): 800ms threshold (good/needs improvement boundary, aligned with Web Vitals standard)
|
|
21
21
|
* - LONG_TASK: 50ms threshold for long task detection
|
|
22
22
|
*/
|
|
23
23
|
exports.WEB_VITALS_THRESHOLDS = {
|
|
@@ -12,7 +12,7 @@ import { WebVitalType } from '../types';
|
|
|
12
12
|
* - FCP (First Contentful Paint): 1800ms threshold (good threshold)
|
|
13
13
|
* - CLS (Cumulative Layout Shift): 0.25 threshold (unitless, needs improvement threshold)
|
|
14
14
|
* - INP (Interaction to Next Paint): 200ms threshold (good threshold)
|
|
15
|
-
* - TTFB (Time to First Byte): 800ms threshold (good
|
|
15
|
+
* - TTFB (Time to First Byte): 800ms threshold (good/needs improvement boundary, aligned with Web Vitals standard)
|
|
16
16
|
* - LONG_TASK: 50ms threshold for long task detection
|
|
17
17
|
*/
|
|
18
18
|
export declare const WEB_VITALS_THRESHOLDS: Record<WebVitalType, number>;
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
* - FCP (First Contentful Paint): 1800ms threshold (good threshold)
|
|
15
15
|
* - CLS (Cumulative Layout Shift): 0.25 threshold (unitless, needs improvement threshold)
|
|
16
16
|
* - INP (Interaction to Next Paint): 200ms threshold (good threshold)
|
|
17
|
-
* - TTFB (Time to First Byte): 800ms threshold (good
|
|
17
|
+
* - TTFB (Time to First Byte): 800ms threshold (good/needs improvement boundary, aligned with Web Vitals standard)
|
|
18
18
|
* - LONG_TASK: 50ms threshold for long task detection
|
|
19
19
|
*/
|
|
20
20
|
export const WEB_VITALS_THRESHOLDS = {
|
package/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "@tracelog/lib",
|
|
3
3
|
"description": "JavaScript library for web analytics and real-time event tracking",
|
|
4
4
|
"license": "MIT",
|
|
5
|
-
"version": "0.5.
|
|
5
|
+
"version": "0.5.3",
|
|
6
6
|
"main": "./dist/cjs/public-api.js",
|
|
7
7
|
"module": "./dist/esm/public-api.js",
|
|
8
8
|
"types": "./dist/esm/public-api.d.ts",
|