@rybbit/js 0.5.0 → 0.6.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -9,4 +9,4 @@ For usage instructions, see the [docs](https://www.rybbit.io/docs/sdks/web).
9
9
  ```bash
10
10
  npm install @rybbit/js
11
11
  # or
12
- yarn add @rybbit/js
12
+ yarn add @rybbit/js
package/dist/index.js CHANGED
@@ -1,7 +1,7 @@
1
1
  /*!
2
- * @rybbit/js v0.5.0
2
+ * @rybbit/js v0.6.1
3
3
  * Rybbit Web SDK
4
4
  * (c) 2026 Rybbit
5
5
  * Released under the AGPL-3.0-only license.
6
6
  */
7
- "use strict";var ct=Object.create;var O=Object.defineProperty;var ut=Object.getOwnPropertyDescriptor;var dt=Object.getOwnPropertyNames,ye=Object.getOwnPropertySymbols,ft=Object.getPrototypeOf,ve=Object.prototype.hasOwnProperty,gt=Object.prototype.propertyIsEnumerable;var G=(e,t,n)=>t in e?O(e,t,{enumerable:!0,configurable:!0,writable:!0,value:n}):e[t]=n,b=(e,t)=>{for(var n in t||(t={}))ve.call(t,n)&&G(e,n,t[n]);if(ye)for(var n of ye(t))gt.call(t,n)&&G(e,n,t[n]);return e};var pt=(e,t)=>{for(var n in t)O(e,n,{get:t[n],enumerable:!0})},ke=(e,t,n,r)=>{if(t&&typeof t=="object"||typeof t=="function")for(let i of dt(t))!ve.call(e,i)&&i!==n&&O(e,i,{get:()=>t[i],enumerable:!(r=ut(t,i))||r.enumerable});return e};var mt=(e,t,n)=>(n=e!=null?ct(ft(e)):{},ke(t||!e||!e.__esModule?O(n,"default",{value:e,enumerable:!0}):n,e)),bt=e=>ke(O({},"__esModule",{value:!0}),e);var S=(e,t,n)=>G(e,typeof t!="symbol"?t+"":t,n);var Dt={};pt(Dt,{default:()=>xt});module.exports=bt(Dt);function Se(e,t){let n=null;return function(...r){let i=this;n!==null&&clearTimeout(n),n=setTimeout(()=>{n=null,e.apply(i,r)},t)}}function Te(e){try{let t=window.location.hostname,n=new URL(e,window.location.href).hostname;return!!n&&n!==t}catch(t){return!1}}function ht(e){try{let t="__DOUBLE_ASTERISK_TOKEN__",n="__SINGLE_ASTERISK_TOKEN__",i=e.replace(/\*\*/g,t).replace(/\*/g,n).replace(/[.+?^${}()|[\]\\]/g,"\\$&");i=i.replace(/\//g,"\\/");let s=i.replace(new RegExp(t,"g"),".*").replace(new RegExp(n,"g"),"[^/]+");return new RegExp("^"+s+"$")}catch(t){return a(`Invalid pattern: ${e}`,t),null}}function Y(e,t=[]){if(!t||t.length===0)return null;for(let n of t){let r=ht(n);if(r&&r.test(e))return n}return null}function o(...e){u.debug&&console.log("[Rybbit]",...e)}function a(...e){u.debug&&console.error("[Rybbit Error]",...e)}function C(){let e=new URL(window.location.href),t=e.pathname;return e.hash&&(t+=e.hash),t}var L={debounceDuration:500,skipPatterns:[],maskPatterns:[],debug:!1},T={autoTrackPageview:!0,autoTrackSpa:!0,trackQuerystring:!0,trackOutbound:!0,enableWebVitals:!1,trackErrors:!1,enableSessionReplay:!1},$=null,u=new Proxy({},{get:(e,t)=>{var n,r;return $?$[t]:(t!=="debug"&&a("Rybbit SDK accessed before initialization. Call rybbit.init() first."),(r=(n=L[t])!=null?n:T[t])!=null?r:void 0)},set:()=>(a("Rybbit config is read-only after initialization."),!1)});async function yt(e,t){var n,r,i,s,d,l,c;try{o("Fetching remote configuration...");let f=new AbortController,w=setTimeout(()=>f.abort(),3e3),h=await fetch(`${e}/site/tracking-config/${t}`,{signal:f.signal});if(clearTimeout(w),h.ok){let g=await h.json();return o("Remote configuration fetched successfully",g),{autoTrackPageview:(n=g.trackInitialPageView)!=null?n:T.autoTrackPageview,autoTrackSpa:(r=g.trackSpaNavigation)!=null?r:T.autoTrackSpa,trackQuerystring:(i=g.trackUrlParams)!=null?i:T.trackQuerystring,trackOutbound:(s=g.trackOutbound)!=null?s:T.trackOutbound,enableWebVitals:(d=g.webVitals)!=null?d:T.enableWebVitals,trackErrors:(l=g.trackErrors)!=null?l:T.trackErrors,enableSessionReplay:(c=g.sessionReplay)!=null?c:T.enableSessionReplay}}else return a(`Failed to fetch remote config: ${h.status}`),null}catch(f){return f.name==="AbortError"?a("Remote config fetch timed out"):a("Error fetching remote config:",f),null}}async function we(e){var c,f;if($)return a("Rybbit SDK already initialized."),!1;if(typeof e!="object"||e===null)return a("Invalid configuration provided to rybbit.init(). Expected an object."),!1;let t=e.analyticsHost;if(!t||t.trim()==="")return a("`analyticsHost` is required in Rybbit config and must be a non-empty string."),!1;let n=t.replace(/\/$/,""),r=e.siteId;if(!r||r.trim()==="")return a("`siteId` is required in Rybbit config and must be a non-empty string."),!1;let s=await yt(n,r)||T,d=Array.isArray(e.skipPatterns)?e.skipPatterns:L.skipPatterns,l=Array.isArray(e.maskPatterns)?e.maskPatterns:L.maskPatterns;return $={analyticsHost:n,siteId:r,debounceDuration:Math.max(0,(c=e.debounceDuration)!=null?c:L.debounceDuration),skipPatterns:d,maskPatterns:l,debug:(f=e.debug)!=null?f:L.debug,replayPrivacyConfig:e.replayPrivacyConfig,autoTrackPageview:s.autoTrackPageview,autoTrackSpa:s.autoTrackSpa,trackQuerystring:s.trackQuerystring,trackOutbound:s.trackOutbound,enableWebVitals:s.enableWebVitals,trackErrors:s.trackErrors,enableSessionReplay:s.enableSessionReplay},!0}var y=null,X=!1;try{let e=localStorage.getItem("rybbit-user-id");e&&(y=e),localStorage.getItem("disable-rybbit")!==null&&(X=!0)}catch(e){a("localStorage unavailable")}typeof window!="undefined"&&window.__RYBBIT_OPTOUT__&&(X=!0);function m(e,t={}){if(X){o("Opted out of tracking.");return}if(!u||!u.analyticsHost||!u.siteId){a("Rybbit config not available. Ensure rybbit.init() was called successfully.");return}let{eventName:n,properties:r,pathOverride:i,webVitals:s}=t;if((e==="custom_event"||e==="performance")&&!n){a("Event name is required and must be a string for performance or custom events.");return}try{let d=new URL(window.location.href),l,c="";if(e==="pageview"&&typeof i=="string"&&i.trim()){o(`Using path override: ${i}`);try{let W=new URL(i,"http://dummybase");l=W.pathname,c=W.search||"",o(`Parsed override path: ${l}, search: ${c}`)}catch(W){a(`Invalid pathOverride format: ${i}. Using window location.`),l=C(),c=u.trackQuerystring?d.search:""}}else l=C(),c=u.trackQuerystring?d.search:"";if(e!=="performance"&&Y(l,u.skipPatterns)){o(`Skipping track for path: ${l}`);return}let f=Y(l,u.maskPatterns);f&&e!=="performance"&&(o(`Masking path ${l} as ${f}`),l=f,c="");let w=b(b(b(b({site_id:u.siteId,hostname:d.hostname,pathname:l,querystring:c,screenWidth:window.screen.width,screenHeight:window.screen.height,language:navigator.language,page_title:document.title,referrer:document.referrer,type:e},(e==="custom_event"||e==="performance"||e==="error")&&{event_name:n}),(e==="custom_event"||e==="outbound"||e==="error")&&Object.keys(r!=null?r:{}).length>0&&{properties:JSON.stringify(r)}),e==="performance"&&s&&b({},s)),y&&{user_id:y});o("Sending track event:",w);let h=JSON.stringify(w),g=`${u.analyticsHost}/track`;navigator.sendBeacon?navigator.sendBeacon(g,new Blob([h],{type:"application/json"}))||(a("sendBeacon failed, falling back to fetch."),Ee(g,h)):Ee(g,h)}catch(d){a("Error during tracking:",d)}}function Ee(e,t){fetch(e,{method:"POST",headers:{"Content-Type":"application/json"},body:t,mode:"cors",keepalive:!0}).catch(n=>{a("Fetch request failed:",n)})}async function Re(e,t,n=!0){if(!u||!u.analyticsHost||!u.siteId){a("Rybbit config not available. Ensure rybbit.init() was called successfully.");return}try{await fetch(`${u.analyticsHost}/identify`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({site_id:u.siteId,user_id:e,traits:t,is_new_identify:n}),mode:"cors",keepalive:!0}),o("Identify event sent:",{userId:e,traits:t,isNewIdentify:n})}catch(r){a("Failed to send identify event:",r)}}function Ce(e,t){if(e.trim()===""){a("User ID must be a non-empty string");return}y=e.trim();try{localStorage.setItem("rybbit-user-id",y),o("User identified:",y)}catch(n){a("Could not persist user ID to localStorage")}Re(y,t,!0)}function Pe(e){if(!e||typeof e!="object"){a("Traits must be an object");return}let t=y;if(!t){a("Cannot set traits without identifying user first. Call identify() first.");return}Re(t,e,!1)}function Ie(){y=null;try{localStorage.removeItem("rybbit-user-id"),o("User ID cleared")}catch(e){a("Could not remove user ID from localStorage")}}function Z(){return y}var E,V=!1,A=[],ee="";function De(){if(V){o("Automatic tracking already set up.");return}if(!u.autoTrackPageview){o("Automatic pageview tracking is disabled.");return}if(o("Setting up automatic tracking..."),ee=C(),E=u.debounceDuration&&u.debounceDuration>0?Se(()=>{let e=C();xe(e),m("pageview")},u.debounceDuration):()=>{let e=C();xe(e),m("pageview")},requestAnimationFrame(()=>{E()}),u.autoTrackSpa){o("Setting up SPA route change tracking.");let e=history.pushState,t=history.replaceState;history.pushState=function(...n){e.apply(this,n),E()},history.replaceState=function(...n){t.apply(this,n),E()},window.addEventListener("popstate",E)}else o("SPA route change tracking is disabled.");window.addEventListener("hashchange",E),V=!0}function Oe(){o("Setting up data attribute and outbound link tracking."),document.addEventListener("click",Le,!0)}function Le(e){if(!(e.target instanceof Element))return;let t=e.target;for(;t;){if(t.hasAttribute("data-rybbit-event")){let n=t.getAttribute("data-rybbit-event");if(n){let r={};for(let i of t.attributes)if(i.name.startsWith("data-rybbit-prop-")){let s=i.name.replace("data-rybbit-prop-","");r[s]=i.value}o("Data attribute event triggered:",n,r),m("custom_event",{eventName:n,properties:r})}break}t=t.parentElement}if(u.trackOutbound&&e.target instanceof Element){let n=e.target.closest("a");if(n&&n.href&&Te(n.href)){o("Outbound link clicked:",n.href);let r={url:n.href,text:n.innerText||n.textContent||"",target:n.target||"_self"};m("outbound",{properties:r})}}}function Ae(e){return A.push(e),o("Page change callback added"),()=>{A=A.filter(t=>t!==e),o("Page change callback removed")}}function xe(e){let t=ee;ee=e,t!==e&&(o(`Page changed from ${t} to ${e}`),A.forEach(n=>{try{n(e,t)}catch(r){a("Error in page change callback:",r)}}))}function _e(){V&&(o("Cleaning up automatic tracking listeners."),window.removeEventListener("popstate",E),window.removeEventListener("hashchange",E),document.removeEventListener("click",Le,!0),A=[],V=!1)}var je=-1,I=e=>{addEventListener("pageshow",t=>{t.persisted&&(je=t.timeStamp,e(t))},!0)},v=(e,t,n,r)=>{let i,s;return d=>{t.value>=0&&(d||r)&&(s=t.value-(i!=null?i:0),(s||i===void 0)&&(i=t.value,t.delta=s,t.rating=((l,c)=>l>c[1]?"poor":l>c[0]?"needs-improvement":"good")(t.value,n),e(t)))}},le=e=>{requestAnimationFrame(()=>requestAnimationFrame(()=>e()))},ce=()=>{let e=performance.getEntriesByType("navigation")[0];if(e&&e.responseStart>0&&e.responseStart<performance.now())return e},_=()=>{var t;let e=ce();return(t=e==null?void 0:e.activationStart)!=null?t:0},k=(e,t=-1)=>{let n=ce(),r="navigate";return je>=0?r="back-forward-cache":n&&(document.prerendering||_()>0?r="prerender":document.wasDiscarded?r="restore":n.type&&(r=n.type.replace(/_/g,"-"))),{name:e,value:t,rating:"good",delta:0,entries:[],id:`v5-${Date.now()}-${Math.floor(8999999999999*Math.random())+1e12}`,navigationType:r}},te=new WeakMap;function ue(e,t){return te.get(e)||te.set(e,new t),te.get(e)}var re=class{constructor(){S(this,"t");S(this,"i",0);S(this,"o",[])}h(t){var i;if(t.hadRecentInput)return;let n=this.o[0],r=this.o.at(-1);this.i&&n&&r&&t.startTime-r.startTime<1e3&&t.startTime-n.startTime<5e3?(this.i+=t.value,this.o.push(t)):(this.i=t.value,this.o=[t]),(i=this.t)==null||i.call(this,t)}},M=(e,t,n={})=>{try{if(PerformanceObserver.supportedEntryTypes.includes(e)){let r=new PerformanceObserver(i=>{Promise.resolve().then(()=>{t(i.getEntries())})});return r.observe(b({type:e,buffered:!0},n)),r}}catch(r){}},de=e=>{let t=!1;return()=>{t||(e(),t=!0)}},P=-1,Me=()=>document.visibilityState!=="hidden"||document.prerendering?1/0:0,z=e=>{document.visibilityState==="hidden"&&P>-1&&(P=e.type==="visibilitychange"?e.timeStamp:0,vt())},Ue=()=>{addEventListener("visibilitychange",z,!0),addEventListener("prerenderingchange",z,!0)},vt=()=>{removeEventListener("visibilitychange",z,!0),removeEventListener("prerenderingchange",z,!0)},Ke=()=>{var e;if(P<0){let t=_(),n=document.prerendering||(e=globalThis.performance.getEntriesByType("visibility-state").filter(r=>r.name==="hidden"&&r.startTime>t)[0])==null?void 0:e.startTime;P=n!=null?n:Me(),Ue(),I(()=>{setTimeout(()=>{P=Me(),Ue()})})}return{get firstHiddenTime(){return P}}},j=e=>{document.prerendering?addEventListener("prerenderingchange",()=>e(),!0):e()},Fe=[1800,3e3],fe=(e,t={})=>{j(()=>{let n=Ke(),r,i=k("FCP"),s=M("paint",d=>{for(let l of d)l.name==="first-contentful-paint"&&(s.disconnect(),l.startTime<n.firstHiddenTime&&(i.value=Math.max(l.startTime-_(),0),i.entries.push(l),r(!0)))});s&&(r=v(e,i,Fe,t.reportAllChanges),I(d=>{i=k("FCP"),r=v(e,i,Fe,t.reportAllChanges),le(()=>{i.value=performance.now()-d.timeStamp,r(!0)})}))})},Ne=[.1,.25],He=(e,t={})=>{fe(de(()=>{let n,r=k("CLS",0),i=ue(t,re),s=l=>{for(let c of l)i.h(c);i.i>r.value&&(r.value=i.i,r.entries=i.o,n())},d=M("layout-shift",s);d&&(n=v(e,r,Ne,t.reportAllChanges),document.addEventListener("visibilitychange",()=>{document.visibilityState==="hidden"&&(s(d.takeRecords()),n(!0))}),I(()=>{i.i=0,r=k("CLS",0),n=v(e,r,Ne,t.reportAllChanges),le(()=>n())}),setTimeout(n))}))},qe=0,ne=1/0,B=0,kt=e=>{for(let t of e)t.interactionId&&(ne=Math.min(ne,t.interactionId),B=Math.max(B,t.interactionId),qe=B?(B-ne)/7+1:0)},ie,We=()=>{var e;return ie?qe:(e=performance.interactionCount)!=null?e:0},St=()=>{"interactionCount"in performance||ie||(ie=M("event",kt,{type:"event",buffered:!0,durationThreshold:0}))},$e=0,ae=class{constructor(){S(this,"u",[]);S(this,"l",new Map);S(this,"m");S(this,"v")}p(){$e=We(),this.u.length=0,this.l.clear()}P(){let t=Math.min(this.u.length-1,Math.floor((We()-$e)/50));return this.u[t]}h(t){var i,s;if((i=this.m)==null||i.call(this,t),!t.interactionId&&t.entryType!=="first-input")return;let n=this.u.at(-1),r=this.l.get(t.interactionId);if(r||this.u.length<10||t.duration>n.T){if(r?t.duration>r.T?(r.entries=[t],r.T=t.duration):t.duration===r.T&&t.startTime===r.entries[0].startTime&&r.entries.push(t):(r={id:t.interactionId,entries:[t],T:t.duration},this.l.set(r.id,r),this.u.push(r)),this.u.sort((d,l)=>l.T-d.T),this.u.length>10){let d=this.u.splice(10);for(let l of d)this.l.delete(l.id)}(s=this.v)==null||s.call(this,r)}}},Qe=e=>{let t=globalThis.requestIdleCallback||setTimeout;document.visibilityState==="hidden"?e():(e=de(e),document.addEventListener("visibilitychange",e,{once:!0}),t(()=>{e(),document.removeEventListener("visibilitychange",e)}))},Ve=[200,500],Je=(e,t={})=>{globalThis.PerformanceEventTiming&&"interactionId"in PerformanceEventTiming.prototype&&j(()=>{var l;St();let n,r=k("INP"),i=ue(t,ae),s=c=>{Qe(()=>{for(let w of c)i.h(w);let f=i.P();f&&f.T!==r.value&&(r.value=f.T,r.entries=f.entries,n())})},d=M("event",s,{durationThreshold:(l=t.durationThreshold)!=null?l:40});n=v(e,r,Ve,t.reportAllChanges),d&&(d.observe({type:"first-input",buffered:!0}),document.addEventListener("visibilitychange",()=>{document.visibilityState==="hidden"&&(s(d.takeRecords()),n(!0))}),I(()=>{i.p(),r=k("INP"),n=v(e,r,Ve,t.reportAllChanges)}))})},oe=class{constructor(){S(this,"m")}h(t){var n;(n=this.m)==null||n.call(this,t)}},Be=[2500,4e3],Ge=(e,t={})=>{j(()=>{let n=Ke(),r,i=k("LCP"),s=ue(t,oe),d=c=>{t.reportAllChanges||(c=c.slice(-1));for(let f of c)s.h(f),f.startTime<n.firstHiddenTime&&(i.value=Math.max(f.startTime-_(),0),i.entries=[f],r())},l=M("largest-contentful-paint",d);if(l){r=v(e,i,Be,t.reportAllChanges);let c=de(()=>{d(l.takeRecords()),l.disconnect(),r(!0)});for(let f of["keydown","click","visibilitychange"])addEventListener(f,()=>Qe(c),{capture:!0,once:!0});I(f=>{i=k("LCP"),r=v(e,i,Be,t.reportAllChanges),le(()=>{i.value=performance.now()-f.timeStamp,r(!0)})})}})},ze=[800,1800],se=e=>{document.prerendering?j(()=>se(e)):document.readyState!=="complete"?addEventListener("load",()=>se(e),!0):setTimeout(e)},Ye=(e,t={})=>{let n=k("TTFB"),r=v(e,n,ze,t.reportAllChanges);se(()=>{let i=ce();i&&(n.value=Math.max(i.responseStart-_(),0),n.entries=[i],r(!0),I(()=>{n=k("TTFB",0),r=v(e,n,ze,t.reportAllChanges),r(!0)}))})};var H={lcp:null,cls:null,inp:null,fcp:null,ttfb:null},x=!1,K=null;function Tt(){if(x)return;Object.values(H).every(t=>t!==null)&&ge()}function ge(){x||(x=!0,K&&(clearTimeout(K),K=null),o("Sending web vitals data:",H),m("performance",{eventName:"web-vitals",webVitals:H}))}function U(e){if(x)return;let t=e.name.toLowerCase();H[t]=e.value,o(`Collected ${t}:`,e.value),Tt()}function Xe(){if(!u.enableWebVitals){o("Web vitals tracking is disabled.");return}o("Initializing web vitals tracking...");try{Ge(U),He(U),Je(U),fe(U),Ye(U),K=setTimeout(()=>{x||(o("Web vitals timeout reached, sending collected metrics."),ge())},2e4),window.addEventListener("beforeunload",()=>{x||ge()}),o("Web vitals tracking initialized successfully.")}catch(e){a("Error setting up web vitals tracking:",e)}}var F=null,N=null;function Ze(){u.trackErrors&&(o("Setting up error tracking"),F=e=>{wt(e)},N=e=>{Et(e)},window.addEventListener("error",F),window.addEventListener("unhandledrejection",N))}function et(){F&&(window.removeEventListener("error",F),F=null),N&&(window.removeEventListener("unhandledrejection",N),N=null),o("Error tracking cleaned up")}function wt(e){var s,d;let t=window.location.origin,n=e.filename||"";if(n)try{if(new URL(n).origin!==t){o("Skipping third-party error:",n);return}}catch(l){}let r=((s=e.error)==null?void 0:s.stack)||"";if(!n&&r&&!r.includes(t)){o("Skipping third-party error based on stack trace");return}let i={message:(e.message||"Unknown error").substring(0,500),stack:r.substring(0,2e3),filename:n||void 0,lineno:e.lineno||void 0,colno:e.colno||void 0,timestamp:Date.now()};q(((d=e.error)==null?void 0:d.name)||"Error",i)}function Et(e){let t="Unhandled promise rejection",n="";e.reason instanceof Error?(t=e.reason.message||t,n=e.reason.stack||""):typeof e.reason=="string"?t=e.reason:e.reason&&typeof e.reason=="object"&&(t=JSON.stringify(e.reason));let r={message:t.substring(0,500),stack:n.substring(0,2e3),timestamp:Date.now()};q("UnhandledRejection",r)}function q(e,t,n){let r=b({error_name:e,message:t.message},n);t.stack&&(r.stack=t.stack),t.filename&&(r.filename=t.filename),t.lineno&&(r.line_number=t.lineno),t.colno&&(r.column_number=t.colno),m("error",{eventName:e,properties:r})}function tt(e,t){var n,r;if(!u.trackErrors){a("Error tracking is not enabled. Enable it via remote config.");return}if(e instanceof ErrorEvent){let i={message:(e.message||"Unknown error").substring(0,500),stack:(((n=e.error)==null?void 0:n.stack)||"").substring(0,2e3),filename:e.filename||void 0,lineno:e.lineno||void 0,colno:e.colno||void 0,timestamp:Date.now()};q(((r=e.error)==null?void 0:r.name)||"Error",i,t)}else{let i={message:(e.message||"Unknown error").substring(0,500),stack:(e.stack||"").substring(0,2e3),timestamp:Date.now()};q(e.name||"Error",i,t)}}var J=null,D=!1,pe=null,R=[],Q,me;async function nt(e){if(u.enableSessionReplay){me=e;try{J=(await import("rrweb")).record,o("rrweb loaded successfully"),rt()}catch(t){a("Failed to load rrweb. Make sure it's installed as a peer dependency:",t)}}}function rt(){var e,t,n,r,i,s,d,l;if(!(D||!J||!u.enableSessionReplay))try{let c=u.replayPrivacyConfig||{},f={mousemove:!1,mouseInteraction:{MouseUp:!1,MouseDown:!1,Click:!0,ContextMenu:!1,DblClick:!0,Focus:!0,Blur:!0,TouchStart:!1,TouchEnd:!1},scroll:500,input:"last",media:800},w={script:!1,comment:!0,headFavicon:!0,headWhitespace:!0,headMetaDescKeywords:!0,headMetaSocial:!0,headMetaRobots:!0,headMetaHttpEquiv:!0,headMetaAuthorship:!0,headMetaVerification:!0},h={emit:g=>{Rt({type:g.type,data:g.data,timestamp:g.timestamp||Date.now()})},recordCanvas:!1,checkoutEveryNms:6e4,checkoutEveryNth:500,blockClass:(e=c.blockClass)!=null?e:"rr-block",blockSelector:(t=c.blockSelector)!=null?t:void 0,ignoreClass:(n=c.ignoreClass)!=null?n:"rr-ignore",ignoreSelector:(r=c.ignoreSelector)!=null?r:void 0,maskTextClass:(i=c.maskTextClass)!=null?i:"rr-mask",maskAllInputs:(s=c.maskAllInputs)!=null?s:!0,maskInputOptions:{password:!0,email:!0},collectFonts:(d=c.collectFonts)!=null?d:!0,sampling:f,slimDOMOptions:(l=c.slimDOMOptions)!=null?l:w};c.maskTextSelectors&&c.maskTextSelectors.length>0&&(h.maskTextSelector=c.maskTextSelectors.join(", ")),pe=J(h),D=!0,Ct(),o("Session replay recording started")}catch(c){a("Failed to start session replay recording:",c)}}function it(){if(!u.enableSessionReplay){a("Session replay is not enabled. Enable it via remote config.");return}if(!J){a("rrweb is not loaded. Ensure it's installed as a peer dependency.");return}if(D){o("Session replay is already recording");return}rt()}function be(){if(!D){o("Session replay is not currently recording");return}pe&&pe(),D=!1,ot(),R.length>0&&he(),o("Session replay recording stopped")}function at(){return D}function Rt(e){R.push(e),R.length>=250&&he()}function Ct(){ot(),Q=window.setInterval(()=>{R.length>0&&he()},5e3)}function ot(){Q!==void 0&&(clearInterval(Q),Q=void 0)}function he(){if(R.length===0)return;let e=[...R];R=[];let t={userId:me||"",events:e,metadata:{pageUrl:window.location.href,viewportWidth:screen.width,viewportHeight:screen.height,language:navigator.language}};Pt(t).catch(n=>{a("Failed to send session replay batch:",n),R.unshift(...e)})}async function Pt(e){let t=`${u.analyticsHost}/session-replay/record/${u.siteId}`,n=JSON.stringify(e),r=await fetch(t,{method:"POST",headers:{"Content-Type":"application/json"},body:n,mode:"cors",keepalive:!0});if(!r.ok)throw new Error(`Failed to send replay batch: ${r.status}`);o(`Session replay batch sent: ${e.events.length} events`)}function st(e){me=e}function lt(){be()}var p=!1,It={init:async e=>{if(p){a("Rybbit SDK already initialized. Call init() only once.");return}await we(e)&&(p=!0,o("Config:",b({},u)),De(),Oe(),Xe(),Ze(),await nt(Z()||void 0))},pageview:e=>{if(!p){a("Rybbit SDK not initialized. Call rybbit.init() first.");return}m("pageview",{pathOverride:e})},event:(e,t)=>{if(!p){a("Rybbit SDK not initialized. Call rybbit.init() first.");return}if(!e){a("Event name is required and must be a string.");return}m("custom_event",{eventName:e,properties:t})},trackOutbound:(e,t="",n="_self")=>{if(!p){a("Rybbit SDK not initialized. Call rybbit.init() first.");return}if(!e){a("Outbound link URL is required and must be a string.");return}m("outbound",{properties:{url:e,text:t,target:n}})},identify:(e,t)=>{if(!p){a("Rybbit SDK not initialized. Call rybbit.init() first.");return}Ce(e,t),st(e)},setTraits:e=>{if(!p){a("Rybbit SDK not initialized. Call rybbit.init() first.");return}Pe(e)},clearUserId:()=>{if(!p){a("Rybbit SDK not initialized. Call rybbit.init() first.");return}Ie()},getUserId:()=>p?Z():(a("Rybbit SDK not initialized. Call rybbit.init() first."),null),error:(e,t)=>{if(!p){a("Rybbit SDK not initialized. Call rybbit.init() first.");return}tt(e,t)},onPageChange:e=>p?Ae(e):(a("Rybbit SDK not initialized. Call rybbit.init() first."),()=>{}),startSessionReplay:()=>{if(!p){a("Rybbit SDK not initialized. Call rybbit.init() first.");return}it()},stopSessionReplay:()=>{if(!p){a("Rybbit SDK not initialized. Call rybbit.init() first.");return}be()},isSessionReplayActive:()=>p?at():(a("Rybbit SDK not initialized. Call rybbit.init() first."),!1),cleanup:()=>{_e(),et(),lt(),p=!1}},xt=It;
7
+ "use strict";var Tt=Object.create;var A=Object.defineProperty,Ct=Object.defineProperties,wt=Object.getOwnPropertyDescriptor,St=Object.getOwnPropertyDescriptors,Rt=Object.getOwnPropertyNames,we=Object.getOwnPropertySymbols,Pt=Object.getPrototypeOf,Se=Object.prototype.hasOwnProperty,It=Object.prototype.propertyIsEnumerable;var re=(e,t,r)=>t in e?A(e,t,{enumerable:!0,configurable:!0,writable:!0,value:r}):e[t]=r,p=(e,t)=>{for(var r in t||(t={}))Se.call(t,r)&&re(e,r,t[r]);if(we)for(var r of we(t))It.call(t,r)&&re(e,r,t[r]);return e},Re=(e,t)=>Ct(e,St(t));var Lt=(e,t)=>{for(var r in t)A(e,r,{get:t[r],enumerable:!0})},Pe=(e,t,r,n)=>{if(t&&typeof t=="object"||typeof t=="function")for(let i of Rt(t))!Se.call(e,i)&&i!==r&&A(e,i,{get:()=>t[i],enumerable:!(n=wt(t,i))||n.enumerable});return e};var xt=(e,t,r)=>(r=e!=null?Tt(Pt(e)):{},Pe(t||!e||!e.__esModule?A(r,"default",{value:e,enumerable:!0}):r,e)),Dt=e=>Pe(A({},"__esModule",{value:!0}),e);var w=(e,t,r)=>re(e,typeof t!="symbol"?t+"":t,r);var Yt={};Lt(Yt,{default:()=>Xt});module.exports=Dt(Yt);function Ie(e,t){let r=null;return function(...n){let i=this;r!==null&&clearTimeout(r),r=setTimeout(()=>{r=null,e.apply(i,n)},t)}}function Le(e){try{let t=window.location.hostname,r=new URL(e,window.location.href).hostname;return!!r&&r!==t}catch(t){return!1}}function Ot(e){try{let t="re:";if(e.startsWith(t)){let c=e.slice(t.length);if(!c)throw new Error("Empty regex pattern");return new RegExp(c)}let r="__DOUBLE_ASTERISK_TOKEN__",n="__SINGLE_ASTERISK_TOKEN__",o=e.replace(/\*\*/g,r).replace(/\*/g,n).replace(/[.+?^${}()|[\]\\]/g,"\\$&");o=o.replace(/\//g,"\\/"),o=o.replace(new RegExp("\\\\/"+r+"\\\\/","g"),"(?:\\/.*)?\\/");let d=o.replace(new RegExp(r,"g"),".*").replace(new RegExp(n,"g"),"[^/]+");return new RegExp("^"+d+"$")}catch(t){return a(`Invalid pattern: ${e}`,t),null}}function ne(e,t=[]){if(!t||t.length===0)return null;for(let r of t){let n=Ot(r);if(n&&n.test(e))return r}return null}function s(...e){l.debug&&console.log("[Rybbit]",...e)}function a(...e){l.debug&&console.error("[Rybbit Error]",...e)}function I(){let e=new URL(window.location.href),t=e.pathname;return e.hash&&(t+=e.hash),t}var M={debounceDuration:500,skipPatterns:[],maskPatterns:[],debug:!1},h={autoTrackPageview:!0,autoTrackSpa:!0,trackQuerystring:!0,trackOutbound:!0,enableWebVitals:!1,trackErrors:!1,enableSessionReplay:!1,trackButtonClicks:!1,trackCopy:!1,trackFormInteractions:!1},j=null,l=new Proxy({},{get:(e,t)=>{var r,n;return j?j[t]:(t!=="debug"&&a("Rybbit SDK accessed before initialization. Call rybbit.init() first."),(n=(r=M[t])!=null?r:h[t])!=null?n:void 0)},set:()=>(a("Rybbit config is read-only after initialization."),!1)});async function At(e,t){var r,n,i,o,d,c,u,f,T,C;try{s("Fetching remote configuration...");let b=new AbortController,P=setTimeout(()=>b.abort(),3e3),te=await fetch(`${e}/site/tracking-config/${t}`,{signal:b.signal});if(clearTimeout(P),te.ok){let y=await te.json();return s("Remote configuration fetched successfully",y),{autoTrackPageview:(r=y.trackInitialPageView)!=null?r:h.autoTrackPageview,autoTrackSpa:(n=y.trackSpaNavigation)!=null?n:h.autoTrackSpa,trackQuerystring:(i=y.trackUrlParams)!=null?i:h.trackQuerystring,trackOutbound:(o=y.trackOutbound)!=null?o:h.trackOutbound,enableWebVitals:(d=y.webVitals)!=null?d:h.enableWebVitals,trackErrors:(c=y.trackErrors)!=null?c:h.trackErrors,enableSessionReplay:(u=y.sessionReplay)!=null?u:h.enableSessionReplay,trackButtonClicks:(f=y.trackButtonClicks)!=null?f:h.trackButtonClicks,trackCopy:(T=y.trackCopy)!=null?T:h.trackCopy,trackFormInteractions:(C=y.trackFormInteractions)!=null?C:h.trackFormInteractions}}else return a(`Failed to fetch remote config: ${te.status}`),null}catch(b){return b.name==="AbortError"?a("Remote config fetch timed out"):a("Error fetching remote config:",b),null}}async function xe(e){var u,f;if(j)return a("Rybbit SDK already initialized."),!1;if(typeof e!="object"||e===null)return a("Invalid configuration provided to rybbit.init(). Expected an object."),!1;let t=e.analyticsHost;if(!t||t.trim()==="")return a("`analyticsHost` is required in Rybbit config and must be a non-empty string."),!1;let r=t.replace(/\/$/,""),n=e.siteId;if(!n||n.trim()==="")return a("`siteId` is required in Rybbit config and must be a non-empty string."),!1;let o=await At(r,n)||h,d=Array.isArray(e.skipPatterns)?e.skipPatterns:M.skipPatterns,c=Array.isArray(e.maskPatterns)?e.maskPatterns:M.maskPatterns;return j={analyticsHost:r,siteId:n,debounceDuration:Math.max(0,(u=e.debounceDuration)!=null?u:M.debounceDuration),skipPatterns:d,maskPatterns:c,debug:(f=e.debug)!=null?f:M.debug,replayPrivacyConfig:e.replayPrivacyConfig,autoTrackPageview:o.autoTrackPageview,autoTrackSpa:o.autoTrackSpa,trackQuerystring:o.trackQuerystring,trackOutbound:o.trackOutbound,enableWebVitals:o.enableWebVitals,trackErrors:o.trackErrors,enableSessionReplay:o.enableSessionReplay,trackButtonClicks:o.trackButtonClicks,trackCopy:o.trackCopy,trackFormInteractions:o.trackFormInteractions},!0}var k=null,ie=!1;try{let e=localStorage.getItem("rybbit-user-id");e&&(k=e),localStorage.getItem("disable-rybbit")!==null&&(ie=!0)}catch(e){a("localStorage unavailable")}typeof window!="undefined"&&window.__RYBBIT_OPTOUT__&&(ie=!0);function g(e,t={}){if(ie){s("Opted out of tracking.");return}if(!l||!l.analyticsHost||!l.siteId){a("Rybbit config not available. Ensure rybbit.init() was called successfully.");return}let{eventName:r,properties:n,pathOverride:i,webVitals:o}=t;if((e==="custom_event"||e==="performance")&&!r){a("Event name is required and must be a string for performance or custom events.");return}try{let d=new URL(window.location.href),c,u="";if(e==="pageview"&&typeof i=="string"&&i.trim()){s(`Using path override: ${i}`);try{if(!/^\//.test(i.trim())&&!/^https?:\/\//.test(i.trim()))throw new Error("pathOverride must start with /");let P=new URL(i.trim(),"http://dummybase");c=P.pathname,u=P.search||"",s(`Parsed override path: ${c}, search: ${u}`)}catch(P){a(`Invalid pathOverride format: ${i}. Using window location.`),c=I(),u=l.trackQuerystring?d.search:""}}else c=I(),u=l.trackQuerystring?d.search:"";if(e!=="performance"&&ne(c,l.skipPatterns)){s(`Skipping track for path: ${c}`);return}let f=ne(c,l.maskPatterns);f&&e!=="performance"&&(s(`Masking path ${c} as ${f}`),c=f,u="");let T=p(p(p(p({site_id:l.siteId,hostname:d.hostname,pathname:c,querystring:u,screenWidth:window.screen.width,screenHeight:window.screen.height,language:navigator.language,page_title:document.title,referrer:document.referrer,type:e},(e==="custom_event"||e==="performance"||e==="error")&&{event_name:r}),(e==="custom_event"||e==="outbound"||e==="error"||e==="button_click"||e==="copy"||e==="form_submit"||e==="input_change")&&Object.keys(n!=null?n:{}).length>0&&{properties:JSON.stringify(n)}),e==="performance"&&o&&p({},o)),k&&{user_id:k});s("Sending track event:",T);let C=JSON.stringify(T),b=`${l.analyticsHost}/track`;navigator.sendBeacon?navigator.sendBeacon(b,new Blob([C],{type:"application/json"}))||(a("sendBeacon failed, falling back to fetch."),De(b,C)):De(b,C)}catch(d){a("Error during tracking:",d)}}function De(e,t){fetch(e,{method:"POST",headers:{"Content-Type":"application/json"},body:t,mode:"cors",keepalive:!0}).catch(r=>{a("Fetch request failed:",r)})}async function Oe(e,t,r=!0){if(!l||!l.analyticsHost||!l.siteId){a("Rybbit config not available. Ensure rybbit.init() was called successfully.");return}try{await fetch(`${l.analyticsHost}/identify`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({site_id:l.siteId,user_id:e,traits:t,is_new_identify:r}),mode:"cors",keepalive:!0}),s("Identify event sent:",{userId:e,traits:t,isNewIdentify:r})}catch(n){a("Failed to send identify event:",n)}}function Ae(e,t){if(e.trim()===""){a("User ID must be a non-empty string");return}k=e.trim();try{localStorage.setItem("rybbit-user-id",k),s("User identified:",k)}catch(r){a("Could not persist user ID to localStorage")}Oe(k,t,!0)}function Me(e){if(!e||typeof e!="object"){a("Traits must be an object");return}let t=k;if(!t){a("Cannot set traits without identifying user first. Call identify() first.");return}Oe(t,e,!1)}function _e(){k=null;try{localStorage.removeItem("rybbit-user-id"),s("User ID cleared")}catch(e){a("Could not remove user ID from localStorage")}}function oe(){return k}var R,K=!1,_=[],ae="";function Fe(){if(K){s("Automatic tracking already set up.");return}if(!l.autoTrackPageview){s("Automatic pageview tracking is disabled.");return}s("Setting up automatic tracking..."),ae=I();let e=()=>{let t=I();Mt(t),g("pageview")};if(R=l.debounceDuration&&l.debounceDuration>0?Ie(()=>{e()},l.debounceDuration):()=>{e()},requestAnimationFrame(()=>{e()}),l.autoTrackSpa){s("Setting up SPA route change tracking.");let t=history.pushState,r=history.replaceState;history.pushState=function(...n){t.apply(this,n),R()},history.replaceState=function(...n){r.apply(this,n),R()},window.addEventListener("popstate",R)}else s("SPA route change tracking is disabled.");window.addEventListener("hashchange",R),K=!0}function Ue(){s("Setting up data attribute and outbound link tracking."),document.addEventListener("click",Ne,!0)}function Ne(e){if(!(e.target instanceof Element))return;let t=e.target;for(;t;){if(t.hasAttribute("data-rybbit-event")){let r=t.getAttribute("data-rybbit-event");if(r){let n={};for(let i of t.attributes)if(i.name.startsWith("data-rybbit-prop-")){let o=i.name.replace("data-rybbit-prop-","");n[o]=i.value}s("Data attribute event triggered:",r,n),g("custom_event",{eventName:r,properties:n})}break}t=t.parentElement}if(l.trackOutbound&&e.target instanceof Element){let r=e.target.closest("a");if(r&&r.href&&Le(r.href)){s("Outbound link clicked:",r.href);let n={url:r.href,text:r.innerText||r.textContent||"",target:r.target||"_self"};g("outbound",{properties:n})}}}function Be(e){return _.push(e),s("Page change callback added"),()=>{_=_.filter(t=>t!==e),s("Page change callback removed")}}function Mt(e){let t=ae;ae=e,t!==e&&(s(`Page changed from ${t} to ${e}`),_.forEach(r=>{try{r(e,t)}catch(n){a("Error in page change callback:",n)}}))}function He(){K&&(s("Cleaning up automatic tracking listeners."),window.removeEventListener("popstate",R),window.removeEventListener("hashchange",R),document.removeEventListener("click",Ne,!0),_=[],K=!1)}var Ge=-1,x=e=>{addEventListener("pageshow",t=>{t.persisted&&(Ge=t.timeStamp,e(t))},!0)},v=(e,t,r,n)=>{let i,o;return d=>{t.value>=0&&(d||n)&&(o=t.value-(i!=null?i:0),(o||i===void 0)&&(i=t.value,t.delta=o,t.rating=((c,u)=>c>u[1]?"poor":c>u[0]?"needs-improvement":"good")(t.value,r),e(t)))}},ge=e=>{requestAnimationFrame(()=>requestAnimationFrame(()=>e()))},me=()=>{let e=performance.getEntriesByType("navigation")[0];if(e&&e.responseStart>0&&e.responseStart<performance.now())return e},F=()=>{var t;let e=me();return(t=e==null?void 0:e.activationStart)!=null?t:0},E=(e,t=-1)=>{let r=me(),n="navigate";return Ge>=0?n="back-forward-cache":r&&(document.prerendering||F()>0?n="prerender":document.wasDiscarded?n="restore":r.type&&(n=r.type.replace(/_/g,"-"))),{name:e,value:t,rating:"good",delta:0,entries:[],id:`v5-${Date.now()}-${Math.floor(8999999999999*Math.random())+1e12}`,navigationType:n}},se=new WeakMap;function be(e,t){return se.get(e)||se.set(e,new t),se.get(e)}var le=class{constructor(){w(this,"t");w(this,"i",0);w(this,"o",[])}h(t){var i;if(t.hadRecentInput)return;let r=this.o[0],n=this.o.at(-1);this.i&&r&&n&&t.startTime-n.startTime<1e3&&t.startTime-r.startTime<5e3?(this.i+=t.value,this.o.push(t)):(this.i=t.value,this.o=[t]),(i=this.t)==null||i.call(this,t)}},U=(e,t,r={})=>{try{if(PerformanceObserver.supportedEntryTypes.includes(e)){let n=new PerformanceObserver(i=>{Promise.resolve().then(()=>{t(i.getEntries())})});return n.observe(p({type:e,buffered:!0},r)),n}}catch(n){}},he=e=>{let t=!1;return()=>{t||(e(),t=!0)}},L=-1,We=()=>document.visibilityState!=="hidden"||document.prerendering?1/0:0,Q=e=>{document.visibilityState==="hidden"&&L>-1&&(L=e.type==="visibilitychange"?e.timeStamp:0,_t())},$e=()=>{addEventListener("visibilitychange",Q,!0),addEventListener("prerenderingchange",Q,!0)},_t=()=>{removeEventListener("visibilitychange",Q,!0),removeEventListener("prerenderingchange",Q,!0)},Xe=()=>{var e;if(L<0){let t=F(),r=document.prerendering||(e=globalThis.performance.getEntriesByType("visibility-state").filter(n=>n.name==="hidden"&&n.startTime>t)[0])==null?void 0:e.startTime;L=r!=null?r:We(),$e(),x(()=>{setTimeout(()=>{L=We(),$e()})})}return{get firstHiddenTime(){return L}}},J=e=>{document.prerendering?addEventListener("prerenderingchange",()=>e(),!0):e()},Ve=[1800,3e3],ye=(e,t={})=>{J(()=>{let r=Xe(),n,i=E("FCP"),o=U("paint",d=>{for(let c of d)c.name==="first-contentful-paint"&&(o.disconnect(),c.startTime<r.firstHiddenTime&&(i.value=Math.max(c.startTime-F(),0),i.entries.push(c),n(!0)))});o&&(n=v(e,i,Ve,t.reportAllChanges),x(d=>{i=E("FCP"),n=v(e,i,Ve,t.reportAllChanges),ge(()=>{i.value=performance.now()-d.timeStamp,n(!0)})}))})},ze=[.1,.25],Ye=(e,t={})=>{ye(he(()=>{let r,n=E("CLS",0),i=be(t,le),o=c=>{for(let u of c)i.h(u);i.i>n.value&&(n.value=i.i,n.entries=i.o,r())},d=U("layout-shift",o);d&&(r=v(e,n,ze,t.reportAllChanges),document.addEventListener("visibilitychange",()=>{document.visibilityState==="hidden"&&(o(d.takeRecords()),r(!0))}),x(()=>{i.i=0,n=E("CLS",0),r=v(e,n,ze,t.reportAllChanges),ge(()=>r())}),setTimeout(r))}))},Ze=0,ce=1/0,q=0,Ft=e=>{for(let t of e)t.interactionId&&(ce=Math.min(ce,t.interactionId),q=Math.max(q,t.interactionId),Ze=q?(q-ce)/7+1:0)},ue,je=()=>{var e;return ue?Ze:(e=performance.interactionCount)!=null?e:0},Ut=()=>{"interactionCount"in performance||ue||(ue=U("event",Ft,{type:"event",buffered:!0,durationThreshold:0}))},Ke=0,de=class{constructor(){w(this,"u",[]);w(this,"l",new Map);w(this,"m");w(this,"v")}p(){Ke=je(),this.u.length=0,this.l.clear()}P(){let t=Math.min(this.u.length-1,Math.floor((je()-Ke)/50));return this.u[t]}h(t){var i,o;if((i=this.m)==null||i.call(this,t),!t.interactionId&&t.entryType!=="first-input")return;let r=this.u.at(-1),n=this.l.get(t.interactionId);if(n||this.u.length<10||t.duration>r.T){if(n?t.duration>n.T?(n.entries=[t],n.T=t.duration):t.duration===n.T&&t.startTime===n.entries[0].startTime&&n.entries.push(t):(n={id:t.interactionId,entries:[t],T:t.duration},this.l.set(n.id,n),this.u.push(n)),this.u.sort((d,c)=>c.T-d.T),this.u.length>10){let d=this.u.splice(10);for(let c of d)this.l.delete(c.id)}(o=this.v)==null||o.call(this,n)}}},et=e=>{let t=globalThis.requestIdleCallback||setTimeout;document.visibilityState==="hidden"?e():(e=he(e),document.addEventListener("visibilitychange",e,{once:!0}),t(()=>{e(),document.removeEventListener("visibilitychange",e)}))},qe=[200,500],tt=(e,t={})=>{globalThis.PerformanceEventTiming&&"interactionId"in PerformanceEventTiming.prototype&&J(()=>{var c;Ut();let r,n=E("INP"),i=be(t,de),o=u=>{et(()=>{for(let T of u)i.h(T);let f=i.P();f&&f.T!==n.value&&(n.value=f.T,n.entries=f.entries,r())})},d=U("event",o,{durationThreshold:(c=t.durationThreshold)!=null?c:40});r=v(e,n,qe,t.reportAllChanges),d&&(d.observe({type:"first-input",buffered:!0}),document.addEventListener("visibilitychange",()=>{document.visibilityState==="hidden"&&(o(d.takeRecords()),r(!0))}),x(()=>{i.p(),n=E("INP"),r=v(e,n,qe,t.reportAllChanges)}))})},fe=class{constructor(){w(this,"m")}h(t){var r;(r=this.m)==null||r.call(this,t)}},Qe=[2500,4e3],rt=(e,t={})=>{J(()=>{let r=Xe(),n,i=E("LCP"),o=be(t,fe),d=u=>{t.reportAllChanges||(u=u.slice(-1));for(let f of u)o.h(f),f.startTime<r.firstHiddenTime&&(i.value=Math.max(f.startTime-F(),0),i.entries=[f],n())},c=U("largest-contentful-paint",d);if(c){n=v(e,i,Qe,t.reportAllChanges);let u=he(()=>{d(c.takeRecords()),c.disconnect(),n(!0)});for(let f of["keydown","click","visibilitychange"])addEventListener(f,()=>et(u),{capture:!0,once:!0});x(f=>{i=E("LCP"),n=v(e,i,Qe,t.reportAllChanges),ge(()=>{i.value=performance.now()-f.timeStamp,n(!0)})})}})},Je=[800,1800],pe=e=>{document.prerendering?J(()=>pe(e)):document.readyState!=="complete"?addEventListener("load",()=>pe(e),!0):setTimeout(e)},nt=(e,t={})=>{let r=E("TTFB"),n=v(e,r,Je,t.reportAllChanges);pe(()=>{let i=me();i&&(r.value=Math.max(i.responseStart-F(),0),r.entries=[i],n(!0),x(()=>{r=E("TTFB",0),n=v(e,r,Je,t.reportAllChanges),n(!0)}))})};var X={lcp:null,cls:null,inp:null,fcp:null,ttfb:null},D=!1,G=null;function Nt(){if(D)return;Object.values(X).every(t=>t!==null)&&ke()}function ke(){D||(D=!0,G&&(clearTimeout(G),G=null),s("Sending web vitals data:",X),g("performance",{eventName:"web-vitals",webVitals:X}))}function N(e){if(D)return;let t=e.name.toLowerCase();X[t]=e.value,s(`Collected ${t}:`,e.value),Nt()}function it(){if(!l.enableWebVitals){s("Web vitals tracking is disabled.");return}s("Initializing web vitals tracking...");try{rt(N),Ye(N),tt(N),ye(N),nt(N),G=setTimeout(()=>{D||(s("Web vitals timeout reached, sending collected metrics."),ke())},2e4),window.addEventListener("beforeunload",()=>{D||ke()}),s("Web vitals tracking initialized successfully.")}catch(e){a("Error setting up web vitals tracking:",e)}}var B=null,H=null;function ot(){l.trackErrors&&(s("Setting up error tracking"),B=e=>{Bt(e)},H=e=>{Ht(e)},window.addEventListener("error",B),window.addEventListener("unhandledrejection",H))}function at(){B&&(window.removeEventListener("error",B),B=null),H&&(window.removeEventListener("unhandledrejection",H),H=null),s("Error tracking cleaned up")}function Bt(e){var o,d;let t=window.location.origin,r=e.filename||"";if(r)try{if(new URL(r).origin!==t){s("Skipping third-party error:",r);return}}catch(c){}let n=((o=e.error)==null?void 0:o.stack)||"";if(!r&&n&&!n.includes(t)){s("Skipping third-party error based on stack trace");return}let i={message:(e.message||"Unknown error").substring(0,500),stack:n.substring(0,2e3),filename:r||void 0,lineno:e.lineno||void 0,colno:e.colno||void 0,timestamp:Date.now()};Y(((d=e.error)==null?void 0:d.name)||"Error",i)}function Ht(e){let t="Unhandled promise rejection",r="";e.reason instanceof Error?(t=e.reason.message||t,r=e.reason.stack||""):typeof e.reason=="string"?t=e.reason:e.reason&&typeof e.reason=="object"&&(t=JSON.stringify(e.reason));let n={message:t.substring(0,500),stack:r.substring(0,2e3),timestamp:Date.now()};Y("UnhandledRejection",n)}function Y(e,t,r){let n=p({error_name:e,message:t.message},r);t.stack&&(n.stack=t.stack),t.filename&&(n.filename=t.filename),t.lineno&&(n.line_number=t.lineno),t.colno&&(n.column_number=t.colno),g("error",{eventName:e,properties:n})}function st(e,t){var r,n;if(!l.trackErrors){a("Error tracking is not enabled. Enable it via remote config.");return}if(e instanceof ErrorEvent){let i={message:(e.message||"Unknown error").substring(0,500),stack:(((r=e.error)==null?void 0:r.stack)||"").substring(0,2e3),filename:e.filename||void 0,lineno:e.lineno||void 0,colno:e.colno||void 0,timestamp:Date.now()};Y(((n=e.error)==null?void 0:n.name)||"Error",i,t)}else{let i={message:(e.message||"Unknown error").substring(0,500),stack:(e.stack||"").substring(0,2e3),timestamp:Date.now()};Y(e.name||"Error",i,t)}}var W=null;function ct(){l.trackButtonClicks&&(s("Setting up button click tracking"),W=e=>{Wt(e)},document.addEventListener("click",W,!0))}function lt(){W&&(document.removeEventListener("click",W,!0),W=null)}function Wt(e){var o;let t=e.target;if(!t)return;let r=$t(t);if(!r||r.hasAttribute("data-rybbit-event"))return;let n=p({},Vt(r)),i=(o=r.textContent)==null?void 0:o.trim().substring(0,100);i&&(n.text=i),g("button_click",{properties:n})}function $t(e){var n;if(e.tagName==="BUTTON"||e.getAttribute("role")==="button")return e;if(e.tagName==="INPUT"){let i=(n=e.type)==null?void 0:n.toLowerCase();if(i==="submit"||i==="button")return e}let t=e.parentElement,r=0;for(;t&&r<3;){if(t.tagName==="BUTTON"||t.getAttribute("role")==="button")return t;t=t.parentElement,r++}return null}function Vt(e){let t={};for(let r of e.attributes)if(r.name.startsWith("data-rybbit-prop-")){let n=r.name.replace("data-rybbit-prop-","");t[n]=r.value}return t}var $=null;function ut(){l.trackCopy&&(s("Setting up copy tracking"),$=()=>{zt()},document.addEventListener("copy",$))}function dt(){$&&(document.removeEventListener("copy",$),$=null)}function zt(){let e=window.getSelection();if(!e||e.isCollapsed)return;let t=e.toString(),r=t.length;if(r===0)return;let n=e.anchorNode,i=n instanceof HTMLElement?n:n==null?void 0:n.parentElement;if(!i)return;let o=Re(p({text:t.substring(0,500)},r>500&&{textLength:r}),{sourceElement:i.tagName.toLowerCase()});g("copy",{properties:o})}var V=null,z=null;function ft(){l.trackFormInteractions&&(s("Setting up form tracking"),V=e=>{jt(e)},z=e=>{Kt(e)},document.addEventListener("submit",V,!0),document.addEventListener("change",z,!0))}function pt(){V&&(document.removeEventListener("submit",V,!0),V=null),z&&(document.removeEventListener("change",z,!0),z=null)}function jt(e){let t=e.target;if(t.tagName!=="FORM")return;let r=p({formId:t.id||"",formName:t.name||"",formAction:t.getAttribute("action")||"",method:(t.method||"get").toUpperCase(),fieldCount:t.elements.length},gt(t));g("form_submit",{properties:r})}function Kt(e){var o,d,c;let t=e.target,r=t.tagName.toUpperCase();if(!["INPUT","SELECT","TEXTAREA"].includes(r))return;if(r==="INPUT"){let u=(o=t.type)==null?void 0:o.toLowerCase();if(u==="hidden"||u==="password")return}let n=p({element:r.toLowerCase(),inputName:t.name||t.id||""},gt(t));r==="INPUT"&&(n.inputType=(d=t.type)==null?void 0:d.toLowerCase());let i=(c=t.form)==null?void 0:c.id;i&&(n.formId=i),g("input_change",{properties:n})}function gt(e){let t={};for(let r of e.attributes)if(r.name.startsWith("data-rybbit-prop-")){let n=r.name.replace("data-rybbit-prop-","");t[n]=r.value}return t}var ee=null,O=!1,ve=null,S=[],Z,Ee;async function mt(e){if(l.enableSessionReplay){Ee=e;try{ee=(await import("rrweb")).record,s("rrweb loaded successfully"),bt()}catch(t){a("Failed to load rrweb. Make sure it's installed as a peer dependency:",t)}}}function bt(){var e,t,r,n,i,o,d,c;if(!(O||!ee||!l.enableSessionReplay))try{let u=l.replayPrivacyConfig||{},f={mousemove:!1,mouseInteraction:{MouseUp:!1,MouseDown:!1,Click:!0,ContextMenu:!1,DblClick:!0,Focus:!0,Blur:!0,TouchStart:!1,TouchEnd:!1},scroll:500,input:"last",media:800},T={script:!1,comment:!0,headFavicon:!0,headWhitespace:!0,headMetaDescKeywords:!0,headMetaSocial:!0,headMetaRobots:!0,headMetaHttpEquiv:!0,headMetaAuthorship:!0,headMetaVerification:!0},C={emit:b=>{qt({type:b.type,data:b.data,timestamp:b.timestamp||Date.now()})},recordCanvas:!1,checkoutEveryNms:6e4,checkoutEveryNth:500,blockClass:(e=u.blockClass)!=null?e:"rr-block",blockSelector:(t=u.blockSelector)!=null?t:void 0,ignoreClass:(r=u.ignoreClass)!=null?r:"rr-ignore",ignoreSelector:(n=u.ignoreSelector)!=null?n:void 0,maskTextClass:(i=u.maskTextClass)!=null?i:"rr-mask",maskAllInputs:(o=u.maskAllInputs)!=null?o:!0,maskInputOptions:{password:!0,email:!0},collectFonts:(d=u.collectFonts)!=null?d:!0,sampling:f,slimDOMOptions:(c=u.slimDOMOptions)!=null?c:T};u.maskTextSelectors&&u.maskTextSelectors.length>0&&(C.maskTextSelector=u.maskTextSelectors.join(", ")),ve=ee(C),O=!0,Qt(),s("Session replay recording started")}catch(u){a("Failed to start session replay recording:",u)}}function ht(){if(!l.enableSessionReplay){a("Session replay is not enabled. Enable it via remote config.");return}if(!ee){a("rrweb is not loaded. Ensure it's installed as a peer dependency.");return}if(O){s("Session replay is already recording");return}bt()}function Te(){if(!O){s("Session replay is not currently recording");return}ve&&ve(),O=!1,kt(),S.length>0&&Ce(),s("Session replay recording stopped")}function yt(){return O}function qt(e){S.push(e),S.length>=250&&Ce()}function Qt(){kt(),Z=window.setInterval(()=>{S.length>0&&Ce()},5e3)}function kt(){Z!==void 0&&(clearInterval(Z),Z=void 0)}function Ce(){if(S.length===0)return;let e=[...S];S=[];let t={userId:Ee||"",events:e,metadata:{pageUrl:window.location.href,viewportWidth:screen.width,viewportHeight:screen.height,language:navigator.language}};Jt(t).catch(r=>{a("Failed to send session replay batch:",r),S.unshift(...e)})}async function Jt(e){let t=`${l.analyticsHost}/session-replay/record/${l.siteId}`,r=JSON.stringify(e),n=await fetch(t,{method:"POST",headers:{"Content-Type":"application/json"},body:r,mode:"cors",keepalive:!0});if(!n.ok)throw new Error(`Failed to send replay batch: ${n.status}`);s(`Session replay batch sent: ${e.events.length} events`)}function vt(e){Ee=e}function Et(){Te()}var m=!1,Gt={init:async e=>{if(m){a("Rybbit SDK already initialized. Call init() only once.");return}await xe(e)&&(m=!0,s("Config:",p({},l)),Fe(),Ue(),it(),ot(),ct(),ut(),ft(),await mt(oe()||void 0))},pageview:e=>{if(!m){a("Rybbit SDK not initialized. Call rybbit.init() first.");return}g("pageview",{pathOverride:e})},event:(e,t)=>{if(!m){a("Rybbit SDK not initialized. Call rybbit.init() first.");return}if(!e){a("Event name is required and must be a string.");return}g("custom_event",{eventName:e,properties:t})},trackOutbound:(e,t="",r="_self")=>{if(!m){a("Rybbit SDK not initialized. Call rybbit.init() first.");return}if(!e){a("Outbound link URL is required and must be a string.");return}g("outbound",{properties:{url:e,text:t,target:r}})},identify:(e,t)=>{if(!m){a("Rybbit SDK not initialized. Call rybbit.init() first.");return}Ae(e,t),vt(e)},setTraits:e=>{if(!m){a("Rybbit SDK not initialized. Call rybbit.init() first.");return}Me(e)},clearUserId:()=>{if(!m){a("Rybbit SDK not initialized. Call rybbit.init() first.");return}_e()},getUserId:()=>m?oe():(a("Rybbit SDK not initialized. Call rybbit.init() first."),null),error:(e,t)=>{if(!m){a("Rybbit SDK not initialized. Call rybbit.init() first.");return}st(e,t)},onPageChange:e=>m?Be(e):(a("Rybbit SDK not initialized. Call rybbit.init() first."),()=>{}),startSessionReplay:()=>{if(!m){a("Rybbit SDK not initialized. Call rybbit.init() first.");return}ht()},stopSessionReplay:()=>{if(!m){a("Rybbit SDK not initialized. Call rybbit.init() first.");return}Te()},isSessionReplayActive:()=>m?yt():(a("Rybbit SDK not initialized. Call rybbit.init() first."),!1),cleanup:()=>{He(),at(),lt(),dt(),pt(),Et(),m=!1}},Xt=Gt;
package/dist/index.mjs CHANGED
@@ -1,7 +1,7 @@
1
1
  /*!
2
- * @rybbit/js v0.5.0
2
+ * @rybbit/js v0.6.1
3
3
  * Rybbit Web SDK
4
4
  * (c) 2026 Rybbit
5
5
  * Released under the AGPL-3.0-only license.
6
6
  */
7
- var ot=Object.defineProperty;var he=Object.getOwnPropertySymbols;var st=Object.prototype.hasOwnProperty,lt=Object.prototype.propertyIsEnumerable;var J=(e,t,n)=>t in e?ot(e,t,{enumerable:!0,configurable:!0,writable:!0,value:n}):e[t]=n,b=(e,t)=>{for(var n in t||(t={}))st.call(t,n)&&J(e,n,t[n]);if(he)for(var n of he(t))lt.call(t,n)&&J(e,n,t[n]);return e};var S=(e,t,n)=>J(e,typeof t!="symbol"?t+"":t,n);function ye(e,t){let n=null;return function(...r){let i=this;n!==null&&clearTimeout(n),n=setTimeout(()=>{n=null,e.apply(i,r)},t)}}function ve(e){try{let t=window.location.hostname,n=new URL(e,window.location.href).hostname;return!!n&&n!==t}catch(t){return!1}}function ct(e){try{let t="__DOUBLE_ASTERISK_TOKEN__",n="__SINGLE_ASTERISK_TOKEN__",i=e.replace(/\*\*/g,t).replace(/\*/g,n).replace(/[.+?^${}()|[\]\\]/g,"\\$&");i=i.replace(/\//g,"\\/");let s=i.replace(new RegExp(t,"g"),".*").replace(new RegExp(n,"g"),"[^/]+");return new RegExp("^"+s+"$")}catch(t){return a(`Invalid pattern: ${e}`,t),null}}function G(e,t=[]){if(!t||t.length===0)return null;for(let n of t){let r=ct(n);if(r&&r.test(e))return n}return null}function o(...e){u.debug&&console.log("[Rybbit]",...e)}function a(...e){u.debug&&console.error("[Rybbit Error]",...e)}function C(){let e=new URL(window.location.href),t=e.pathname;return e.hash&&(t+=e.hash),t}var O={debounceDuration:500,skipPatterns:[],maskPatterns:[],debug:!1},T={autoTrackPageview:!0,autoTrackSpa:!0,trackQuerystring:!0,trackOutbound:!0,enableWebVitals:!1,trackErrors:!1,enableSessionReplay:!1},W=null,u=new Proxy({},{get:(e,t)=>{var n,r;return W?W[t]:(t!=="debug"&&a("Rybbit SDK accessed before initialization. Call rybbit.init() first."),(r=(n=O[t])!=null?n:T[t])!=null?r:void 0)},set:()=>(a("Rybbit config is read-only after initialization."),!1)});async function ut(e,t){var n,r,i,s,d,l,c;try{o("Fetching remote configuration...");let f=new AbortController,w=setTimeout(()=>f.abort(),3e3),h=await fetch(`${e}/site/tracking-config/${t}`,{signal:f.signal});if(clearTimeout(w),h.ok){let g=await h.json();return o("Remote configuration fetched successfully",g),{autoTrackPageview:(n=g.trackInitialPageView)!=null?n:T.autoTrackPageview,autoTrackSpa:(r=g.trackSpaNavigation)!=null?r:T.autoTrackSpa,trackQuerystring:(i=g.trackUrlParams)!=null?i:T.trackQuerystring,trackOutbound:(s=g.trackOutbound)!=null?s:T.trackOutbound,enableWebVitals:(d=g.webVitals)!=null?d:T.enableWebVitals,trackErrors:(l=g.trackErrors)!=null?l:T.trackErrors,enableSessionReplay:(c=g.sessionReplay)!=null?c:T.enableSessionReplay}}else return a(`Failed to fetch remote config: ${h.status}`),null}catch(f){return f.name==="AbortError"?a("Remote config fetch timed out"):a("Error fetching remote config:",f),null}}async function ke(e){var c,f;if(W)return a("Rybbit SDK already initialized."),!1;if(typeof e!="object"||e===null)return a("Invalid configuration provided to rybbit.init(). Expected an object."),!1;let t=e.analyticsHost;if(!t||t.trim()==="")return a("`analyticsHost` is required in Rybbit config and must be a non-empty string."),!1;let n=t.replace(/\/$/,""),r=e.siteId;if(!r||r.trim()==="")return a("`siteId` is required in Rybbit config and must be a non-empty string."),!1;let s=await ut(n,r)||T,d=Array.isArray(e.skipPatterns)?e.skipPatterns:O.skipPatterns,l=Array.isArray(e.maskPatterns)?e.maskPatterns:O.maskPatterns;return W={analyticsHost:n,siteId:r,debounceDuration:Math.max(0,(c=e.debounceDuration)!=null?c:O.debounceDuration),skipPatterns:d,maskPatterns:l,debug:(f=e.debug)!=null?f:O.debug,replayPrivacyConfig:e.replayPrivacyConfig,autoTrackPageview:s.autoTrackPageview,autoTrackSpa:s.autoTrackSpa,trackQuerystring:s.trackQuerystring,trackOutbound:s.trackOutbound,enableWebVitals:s.enableWebVitals,trackErrors:s.trackErrors,enableSessionReplay:s.enableSessionReplay},!0}var y=null,Y=!1;try{let e=localStorage.getItem("rybbit-user-id");e&&(y=e),localStorage.getItem("disable-rybbit")!==null&&(Y=!0)}catch(e){a("localStorage unavailable")}typeof window!="undefined"&&window.__RYBBIT_OPTOUT__&&(Y=!0);function m(e,t={}){if(Y){o("Opted out of tracking.");return}if(!u||!u.analyticsHost||!u.siteId){a("Rybbit config not available. Ensure rybbit.init() was called successfully.");return}let{eventName:n,properties:r,pathOverride:i,webVitals:s}=t;if((e==="custom_event"||e==="performance")&&!n){a("Event name is required and must be a string for performance or custom events.");return}try{let d=new URL(window.location.href),l,c="";if(e==="pageview"&&typeof i=="string"&&i.trim()){o(`Using path override: ${i}`);try{let N=new URL(i,"http://dummybase");l=N.pathname,c=N.search||"",o(`Parsed override path: ${l}, search: ${c}`)}catch(N){a(`Invalid pathOverride format: ${i}. Using window location.`),l=C(),c=u.trackQuerystring?d.search:""}}else l=C(),c=u.trackQuerystring?d.search:"";if(e!=="performance"&&G(l,u.skipPatterns)){o(`Skipping track for path: ${l}`);return}let f=G(l,u.maskPatterns);f&&e!=="performance"&&(o(`Masking path ${l} as ${f}`),l=f,c="");let w=b(b(b(b({site_id:u.siteId,hostname:d.hostname,pathname:l,querystring:c,screenWidth:window.screen.width,screenHeight:window.screen.height,language:navigator.language,page_title:document.title,referrer:document.referrer,type:e},(e==="custom_event"||e==="performance"||e==="error")&&{event_name:n}),(e==="custom_event"||e==="outbound"||e==="error")&&Object.keys(r!=null?r:{}).length>0&&{properties:JSON.stringify(r)}),e==="performance"&&s&&b({},s)),y&&{user_id:y});o("Sending track event:",w);let h=JSON.stringify(w),g=`${u.analyticsHost}/track`;navigator.sendBeacon?navigator.sendBeacon(g,new Blob([h],{type:"application/json"}))||(a("sendBeacon failed, falling back to fetch."),Se(g,h)):Se(g,h)}catch(d){a("Error during tracking:",d)}}function Se(e,t){fetch(e,{method:"POST",headers:{"Content-Type":"application/json"},body:t,mode:"cors",keepalive:!0}).catch(n=>{a("Fetch request failed:",n)})}async function Te(e,t,n=!0){if(!u||!u.analyticsHost||!u.siteId){a("Rybbit config not available. Ensure rybbit.init() was called successfully.");return}try{await fetch(`${u.analyticsHost}/identify`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({site_id:u.siteId,user_id:e,traits:t,is_new_identify:n}),mode:"cors",keepalive:!0}),o("Identify event sent:",{userId:e,traits:t,isNewIdentify:n})}catch(r){a("Failed to send identify event:",r)}}function we(e,t){if(e.trim()===""){a("User ID must be a non-empty string");return}y=e.trim();try{localStorage.setItem("rybbit-user-id",y),o("User identified:",y)}catch(n){a("Could not persist user ID to localStorage")}Te(y,t,!0)}function Ee(e){if(!e||typeof e!="object"){a("Traits must be an object");return}let t=y;if(!t){a("Cannot set traits without identifying user first. Call identify() first.");return}Te(t,e,!1)}function Re(){y=null;try{localStorage.removeItem("rybbit-user-id"),o("User ID cleared")}catch(e){a("Could not remove user ID from localStorage")}}function X(){return y}var E,$=!1,L=[],Z="";function Pe(){if($){o("Automatic tracking already set up.");return}if(!u.autoTrackPageview){o("Automatic pageview tracking is disabled.");return}if(o("Setting up automatic tracking..."),Z=C(),E=u.debounceDuration&&u.debounceDuration>0?ye(()=>{let e=C();Ce(e),m("pageview")},u.debounceDuration):()=>{let e=C();Ce(e),m("pageview")},requestAnimationFrame(()=>{E()}),u.autoTrackSpa){o("Setting up SPA route change tracking.");let e=history.pushState,t=history.replaceState;history.pushState=function(...n){e.apply(this,n),E()},history.replaceState=function(...n){t.apply(this,n),E()},window.addEventListener("popstate",E)}else o("SPA route change tracking is disabled.");window.addEventListener("hashchange",E),$=!0}function Ie(){o("Setting up data attribute and outbound link tracking."),document.addEventListener("click",xe,!0)}function xe(e){if(!(e.target instanceof Element))return;let t=e.target;for(;t;){if(t.hasAttribute("data-rybbit-event")){let n=t.getAttribute("data-rybbit-event");if(n){let r={};for(let i of t.attributes)if(i.name.startsWith("data-rybbit-prop-")){let s=i.name.replace("data-rybbit-prop-","");r[s]=i.value}o("Data attribute event triggered:",n,r),m("custom_event",{eventName:n,properties:r})}break}t=t.parentElement}if(u.trackOutbound&&e.target instanceof Element){let n=e.target.closest("a");if(n&&n.href&&ve(n.href)){o("Outbound link clicked:",n.href);let r={url:n.href,text:n.innerText||n.textContent||"",target:n.target||"_self"};m("outbound",{properties:r})}}}function De(e){return L.push(e),o("Page change callback added"),()=>{L=L.filter(t=>t!==e),o("Page change callback removed")}}function Ce(e){let t=Z;Z=e,t!==e&&(o(`Page changed from ${t} to ${e}`),L.forEach(n=>{try{n(e,t)}catch(r){a("Error in page change callback:",r)}}))}function Oe(){$&&(o("Cleaning up automatic tracking listeners."),window.removeEventListener("popstate",E),window.removeEventListener("hashchange",E),document.removeEventListener("click",xe,!0),L=[],$=!1)}var Ve=-1,I=e=>{addEventListener("pageshow",t=>{t.persisted&&(Ve=t.timeStamp,e(t))},!0)},v=(e,t,n,r)=>{let i,s;return d=>{t.value>=0&&(d||r)&&(s=t.value-(i!=null?i:0),(s||i===void 0)&&(i=t.value,t.delta=s,t.rating=((l,c)=>l>c[1]?"poor":l>c[0]?"needs-improvement":"good")(t.value,n),e(t)))}},se=e=>{requestAnimationFrame(()=>requestAnimationFrame(()=>e()))},le=()=>{let e=performance.getEntriesByType("navigation")[0];if(e&&e.responseStart>0&&e.responseStart<performance.now())return e},A=()=>{var t;let e=le();return(t=e==null?void 0:e.activationStart)!=null?t:0},k=(e,t=-1)=>{let n=le(),r="navigate";return Ve>=0?r="back-forward-cache":n&&(document.prerendering||A()>0?r="prerender":document.wasDiscarded?r="restore":n.type&&(r=n.type.replace(/_/g,"-"))),{name:e,value:t,rating:"good",delta:0,entries:[],id:`v5-${Date.now()}-${Math.floor(8999999999999*Math.random())+1e12}`,navigationType:r}},ee=new WeakMap;function ce(e,t){return ee.get(e)||ee.set(e,new t),ee.get(e)}var ne=class{constructor(){S(this,"t");S(this,"i",0);S(this,"o",[])}h(t){var i;if(t.hadRecentInput)return;let n=this.o[0],r=this.o.at(-1);this.i&&n&&r&&t.startTime-r.startTime<1e3&&t.startTime-n.startTime<5e3?(this.i+=t.value,this.o.push(t)):(this.i=t.value,this.o=[t]),(i=this.t)==null||i.call(this,t)}},_=(e,t,n={})=>{try{if(PerformanceObserver.supportedEntryTypes.includes(e)){let r=new PerformanceObserver(i=>{Promise.resolve().then(()=>{t(i.getEntries())})});return r.observe(b({type:e,buffered:!0},n)),r}}catch(r){}},ue=e=>{let t=!1;return()=>{t||(e(),t=!0)}},P=-1,Le=()=>document.visibilityState!=="hidden"||document.prerendering?1/0:0,B=e=>{document.visibilityState==="hidden"&&P>-1&&(P=e.type==="visibilitychange"?e.timeStamp:0,dt())},Ae=()=>{addEventListener("visibilitychange",B,!0),addEventListener("prerenderingchange",B,!0)},dt=()=>{removeEventListener("visibilitychange",B,!0),removeEventListener("prerenderingchange",B,!0)},Be=()=>{var e;if(P<0){let t=A(),n=document.prerendering||(e=globalThis.performance.getEntriesByType("visibility-state").filter(r=>r.name==="hidden"&&r.startTime>t)[0])==null?void 0:e.startTime;P=n!=null?n:Le(),Ae(),I(()=>{setTimeout(()=>{P=Le(),Ae()})})}return{get firstHiddenTime(){return P}}},z=e=>{document.prerendering?addEventListener("prerenderingchange",()=>e(),!0):e()},_e=[1800,3e3],de=(e,t={})=>{z(()=>{let n=Be(),r,i=k("FCP"),s=_("paint",d=>{for(let l of d)l.name==="first-contentful-paint"&&(s.disconnect(),l.startTime<n.firstHiddenTime&&(i.value=Math.max(l.startTime-A(),0),i.entries.push(l),r(!0)))});s&&(r=v(e,i,_e,t.reportAllChanges),I(d=>{i=k("FCP"),r=v(e,i,_e,t.reportAllChanges),se(()=>{i.value=performance.now()-d.timeStamp,r(!0)})}))})},Me=[.1,.25],ze=(e,t={})=>{de(ue(()=>{let n,r=k("CLS",0),i=ce(t,ne),s=l=>{for(let c of l)i.h(c);i.i>r.value&&(r.value=i.i,r.entries=i.o,n())},d=_("layout-shift",s);d&&(n=v(e,r,Me,t.reportAllChanges),document.addEventListener("visibilitychange",()=>{document.visibilityState==="hidden"&&(s(d.takeRecords()),n(!0))}),I(()=>{i.i=0,r=k("CLS",0),n=v(e,r,Me,t.reportAllChanges),se(()=>n())}),setTimeout(n))}))},je=0,te=1/0,V=0,ft=e=>{for(let t of e)t.interactionId&&(te=Math.min(te,t.interactionId),V=Math.max(V,t.interactionId),je=V?(V-te)/7+1:0)},re,Ue=()=>{var e;return re?je:(e=performance.interactionCount)!=null?e:0},gt=()=>{"interactionCount"in performance||re||(re=_("event",ft,{type:"event",buffered:!0,durationThreshold:0}))},Fe=0,ie=class{constructor(){S(this,"u",[]);S(this,"l",new Map);S(this,"m");S(this,"v")}p(){Fe=Ue(),this.u.length=0,this.l.clear()}P(){let t=Math.min(this.u.length-1,Math.floor((Ue()-Fe)/50));return this.u[t]}h(t){var i,s;if((i=this.m)==null||i.call(this,t),!t.interactionId&&t.entryType!=="first-input")return;let n=this.u.at(-1),r=this.l.get(t.interactionId);if(r||this.u.length<10||t.duration>n.T){if(r?t.duration>r.T?(r.entries=[t],r.T=t.duration):t.duration===r.T&&t.startTime===r.entries[0].startTime&&r.entries.push(t):(r={id:t.interactionId,entries:[t],T:t.duration},this.l.set(r.id,r),this.u.push(r)),this.u.sort((d,l)=>l.T-d.T),this.u.length>10){let d=this.u.splice(10);for(let l of d)this.l.delete(l.id)}(s=this.v)==null||s.call(this,r)}}},Ke=e=>{let t=globalThis.requestIdleCallback||setTimeout;document.visibilityState==="hidden"?e():(e=ue(e),document.addEventListener("visibilitychange",e,{once:!0}),t(()=>{e(),document.removeEventListener("visibilitychange",e)}))},Ne=[200,500],He=(e,t={})=>{globalThis.PerformanceEventTiming&&"interactionId"in PerformanceEventTiming.prototype&&z(()=>{var l;gt();let n,r=k("INP"),i=ce(t,ie),s=c=>{Ke(()=>{for(let w of c)i.h(w);let f=i.P();f&&f.T!==r.value&&(r.value=f.T,r.entries=f.entries,n())})},d=_("event",s,{durationThreshold:(l=t.durationThreshold)!=null?l:40});n=v(e,r,Ne,t.reportAllChanges),d&&(d.observe({type:"first-input",buffered:!0}),document.addEventListener("visibilitychange",()=>{document.visibilityState==="hidden"&&(s(d.takeRecords()),n(!0))}),I(()=>{i.p(),r=k("INP"),n=v(e,r,Ne,t.reportAllChanges)}))})},ae=class{constructor(){S(this,"m")}h(t){var n;(n=this.m)==null||n.call(this,t)}},We=[2500,4e3],qe=(e,t={})=>{z(()=>{let n=Be(),r,i=k("LCP"),s=ce(t,ae),d=c=>{t.reportAllChanges||(c=c.slice(-1));for(let f of c)s.h(f),f.startTime<n.firstHiddenTime&&(i.value=Math.max(f.startTime-A(),0),i.entries=[f],r())},l=_("largest-contentful-paint",d);if(l){r=v(e,i,We,t.reportAllChanges);let c=ue(()=>{d(l.takeRecords()),l.disconnect(),r(!0)});for(let f of["keydown","click","visibilitychange"])addEventListener(f,()=>Ke(c),{capture:!0,once:!0});I(f=>{i=k("LCP"),r=v(e,i,We,t.reportAllChanges),se(()=>{i.value=performance.now()-f.timeStamp,r(!0)})})}})},$e=[800,1800],oe=e=>{document.prerendering?z(()=>oe(e)):document.readyState!=="complete"?addEventListener("load",()=>oe(e),!0):setTimeout(e)},Qe=(e,t={})=>{let n=k("TTFB"),r=v(e,n,$e,t.reportAllChanges);oe(()=>{let i=le();i&&(n.value=Math.max(i.responseStart-A(),0),n.entries=[i],r(!0),I(()=>{n=k("TTFB",0),r=v(e,n,$e,t.reportAllChanges),r(!0)}))})};var K={lcp:null,cls:null,inp:null,fcp:null,ttfb:null},x=!1,j=null;function pt(){if(x)return;Object.values(K).every(t=>t!==null)&&fe()}function fe(){x||(x=!0,j&&(clearTimeout(j),j=null),o("Sending web vitals data:",K),m("performance",{eventName:"web-vitals",webVitals:K}))}function M(e){if(x)return;let t=e.name.toLowerCase();K[t]=e.value,o(`Collected ${t}:`,e.value),pt()}function Je(){if(!u.enableWebVitals){o("Web vitals tracking is disabled.");return}o("Initializing web vitals tracking...");try{qe(M),ze(M),He(M),de(M),Qe(M),j=setTimeout(()=>{x||(o("Web vitals timeout reached, sending collected metrics."),fe())},2e4),window.addEventListener("beforeunload",()=>{x||fe()}),o("Web vitals tracking initialized successfully.")}catch(e){a("Error setting up web vitals tracking:",e)}}var U=null,F=null;function Ge(){u.trackErrors&&(o("Setting up error tracking"),U=e=>{mt(e)},F=e=>{bt(e)},window.addEventListener("error",U),window.addEventListener("unhandledrejection",F))}function Ye(){U&&(window.removeEventListener("error",U),U=null),F&&(window.removeEventListener("unhandledrejection",F),F=null),o("Error tracking cleaned up")}function mt(e){var s,d;let t=window.location.origin,n=e.filename||"";if(n)try{if(new URL(n).origin!==t){o("Skipping third-party error:",n);return}}catch(l){}let r=((s=e.error)==null?void 0:s.stack)||"";if(!n&&r&&!r.includes(t)){o("Skipping third-party error based on stack trace");return}let i={message:(e.message||"Unknown error").substring(0,500),stack:r.substring(0,2e3),filename:n||void 0,lineno:e.lineno||void 0,colno:e.colno||void 0,timestamp:Date.now()};H(((d=e.error)==null?void 0:d.name)||"Error",i)}function bt(e){let t="Unhandled promise rejection",n="";e.reason instanceof Error?(t=e.reason.message||t,n=e.reason.stack||""):typeof e.reason=="string"?t=e.reason:e.reason&&typeof e.reason=="object"&&(t=JSON.stringify(e.reason));let r={message:t.substring(0,500),stack:n.substring(0,2e3),timestamp:Date.now()};H("UnhandledRejection",r)}function H(e,t,n){let r=b({error_name:e,message:t.message},n);t.stack&&(r.stack=t.stack),t.filename&&(r.filename=t.filename),t.lineno&&(r.line_number=t.lineno),t.colno&&(r.column_number=t.colno),m("error",{eventName:e,properties:r})}function Xe(e,t){var n,r;if(!u.trackErrors){a("Error tracking is not enabled. Enable it via remote config.");return}if(e instanceof ErrorEvent){let i={message:(e.message||"Unknown error").substring(0,500),stack:(((n=e.error)==null?void 0:n.stack)||"").substring(0,2e3),filename:e.filename||void 0,lineno:e.lineno||void 0,colno:e.colno||void 0,timestamp:Date.now()};H(((r=e.error)==null?void 0:r.name)||"Error",i,t)}else{let i={message:(e.message||"Unknown error").substring(0,500),stack:(e.stack||"").substring(0,2e3),timestamp:Date.now()};H(e.name||"Error",i,t)}}var Q=null,D=!1,ge=null,R=[],q,pe;async function Ze(e){if(u.enableSessionReplay){pe=e;try{Q=(await import("rrweb")).record,o("rrweb loaded successfully"),et()}catch(t){a("Failed to load rrweb. Make sure it's installed as a peer dependency:",t)}}}function et(){var e,t,n,r,i,s,d,l;if(!(D||!Q||!u.enableSessionReplay))try{let c=u.replayPrivacyConfig||{},f={mousemove:!1,mouseInteraction:{MouseUp:!1,MouseDown:!1,Click:!0,ContextMenu:!1,DblClick:!0,Focus:!0,Blur:!0,TouchStart:!1,TouchEnd:!1},scroll:500,input:"last",media:800},w={script:!1,comment:!0,headFavicon:!0,headWhitespace:!0,headMetaDescKeywords:!0,headMetaSocial:!0,headMetaRobots:!0,headMetaHttpEquiv:!0,headMetaAuthorship:!0,headMetaVerification:!0},h={emit:g=>{ht({type:g.type,data:g.data,timestamp:g.timestamp||Date.now()})},recordCanvas:!1,checkoutEveryNms:6e4,checkoutEveryNth:500,blockClass:(e=c.blockClass)!=null?e:"rr-block",blockSelector:(t=c.blockSelector)!=null?t:void 0,ignoreClass:(n=c.ignoreClass)!=null?n:"rr-ignore",ignoreSelector:(r=c.ignoreSelector)!=null?r:void 0,maskTextClass:(i=c.maskTextClass)!=null?i:"rr-mask",maskAllInputs:(s=c.maskAllInputs)!=null?s:!0,maskInputOptions:{password:!0,email:!0},collectFonts:(d=c.collectFonts)!=null?d:!0,sampling:f,slimDOMOptions:(l=c.slimDOMOptions)!=null?l:w};c.maskTextSelectors&&c.maskTextSelectors.length>0&&(h.maskTextSelector=c.maskTextSelectors.join(", ")),ge=Q(h),D=!0,yt(),o("Session replay recording started")}catch(c){a("Failed to start session replay recording:",c)}}function tt(){if(!u.enableSessionReplay){a("Session replay is not enabled. Enable it via remote config.");return}if(!Q){a("rrweb is not loaded. Ensure it's installed as a peer dependency.");return}if(D){o("Session replay is already recording");return}et()}function me(){if(!D){o("Session replay is not currently recording");return}ge&&ge(),D=!1,rt(),R.length>0&&be(),o("Session replay recording stopped")}function nt(){return D}function ht(e){R.push(e),R.length>=250&&be()}function yt(){rt(),q=window.setInterval(()=>{R.length>0&&be()},5e3)}function rt(){q!==void 0&&(clearInterval(q),q=void 0)}function be(){if(R.length===0)return;let e=[...R];R=[];let t={userId:pe||"",events:e,metadata:{pageUrl:window.location.href,viewportWidth:screen.width,viewportHeight:screen.height,language:navigator.language}};vt(t).catch(n=>{a("Failed to send session replay batch:",n),R.unshift(...e)})}async function vt(e){let t=`${u.analyticsHost}/session-replay/record/${u.siteId}`,n=JSON.stringify(e),r=await fetch(t,{method:"POST",headers:{"Content-Type":"application/json"},body:n,mode:"cors",keepalive:!0});if(!r.ok)throw new Error(`Failed to send replay batch: ${r.status}`);o(`Session replay batch sent: ${e.events.length} events`)}function it(e){pe=e}function at(){me()}var p=!1,kt={init:async e=>{if(p){a("Rybbit SDK already initialized. Call init() only once.");return}await ke(e)&&(p=!0,o("Config:",b({},u)),Pe(),Ie(),Je(),Ge(),await Ze(X()||void 0))},pageview:e=>{if(!p){a("Rybbit SDK not initialized. Call rybbit.init() first.");return}m("pageview",{pathOverride:e})},event:(e,t)=>{if(!p){a("Rybbit SDK not initialized. Call rybbit.init() first.");return}if(!e){a("Event name is required and must be a string.");return}m("custom_event",{eventName:e,properties:t})},trackOutbound:(e,t="",n="_self")=>{if(!p){a("Rybbit SDK not initialized. Call rybbit.init() first.");return}if(!e){a("Outbound link URL is required and must be a string.");return}m("outbound",{properties:{url:e,text:t,target:n}})},identify:(e,t)=>{if(!p){a("Rybbit SDK not initialized. Call rybbit.init() first.");return}we(e,t),it(e)},setTraits:e=>{if(!p){a("Rybbit SDK not initialized. Call rybbit.init() first.");return}Ee(e)},clearUserId:()=>{if(!p){a("Rybbit SDK not initialized. Call rybbit.init() first.");return}Re()},getUserId:()=>p?X():(a("Rybbit SDK not initialized. Call rybbit.init() first."),null),error:(e,t)=>{if(!p){a("Rybbit SDK not initialized. Call rybbit.init() first.");return}Xe(e,t)},onPageChange:e=>p?De(e):(a("Rybbit SDK not initialized. Call rybbit.init() first."),()=>{}),startSessionReplay:()=>{if(!p){a("Rybbit SDK not initialized. Call rybbit.init() first.");return}tt()},stopSessionReplay:()=>{if(!p){a("Rybbit SDK not initialized. Call rybbit.init() first.");return}me()},isSessionReplayActive:()=>p?nt():(a("Rybbit SDK not initialized. Call rybbit.init() first."),!1),cleanup:()=>{Oe(),Ye(),at(),p=!1}},rn=kt;export{rn as default};
7
+ var kt=Object.defineProperty,vt=Object.defineProperties;var Et=Object.getOwnPropertyDescriptors;var Ce=Object.getOwnPropertySymbols;var Tt=Object.prototype.hasOwnProperty,Ct=Object.prototype.propertyIsEnumerable;var te=(e,t,r)=>t in e?kt(e,t,{enumerable:!0,configurable:!0,writable:!0,value:r}):e[t]=r,p=(e,t)=>{for(var r in t||(t={}))Tt.call(t,r)&&te(e,r,t[r]);if(Ce)for(var r of Ce(t))Ct.call(t,r)&&te(e,r,t[r]);return e},we=(e,t)=>vt(e,Et(t));var w=(e,t,r)=>te(e,typeof t!="symbol"?t+"":t,r);function Se(e,t){let r=null;return function(...n){let i=this;r!==null&&clearTimeout(r),r=setTimeout(()=>{r=null,e.apply(i,n)},t)}}function Re(e){try{let t=window.location.hostname,r=new URL(e,window.location.href).hostname;return!!r&&r!==t}catch(t){return!1}}function wt(e){try{let t="re:";if(e.startsWith(t)){let c=e.slice(t.length);if(!c)throw new Error("Empty regex pattern");return new RegExp(c)}let r="__DOUBLE_ASTERISK_TOKEN__",n="__SINGLE_ASTERISK_TOKEN__",o=e.replace(/\*\*/g,r).replace(/\*/g,n).replace(/[.+?^${}()|[\]\\]/g,"\\$&");o=o.replace(/\//g,"\\/"),o=o.replace(new RegExp("\\\\/"+r+"\\\\/","g"),"(?:\\/.*)?\\/");let d=o.replace(new RegExp(r,"g"),".*").replace(new RegExp(n,"g"),"[^/]+");return new RegExp("^"+d+"$")}catch(t){return a(`Invalid pattern: ${e}`,t),null}}function re(e,t=[]){if(!t||t.length===0)return null;for(let r of t){let n=wt(r);if(n&&n.test(e))return r}return null}function s(...e){l.debug&&console.log("[Rybbit]",...e)}function a(...e){l.debug&&console.error("[Rybbit Error]",...e)}function I(){let e=new URL(window.location.href),t=e.pathname;return e.hash&&(t+=e.hash),t}var A={debounceDuration:500,skipPatterns:[],maskPatterns:[],debug:!1},h={autoTrackPageview:!0,autoTrackSpa:!0,trackQuerystring:!0,trackOutbound:!0,enableWebVitals:!1,trackErrors:!1,enableSessionReplay:!1,trackButtonClicks:!1,trackCopy:!1,trackFormInteractions:!1},z=null,l=new Proxy({},{get:(e,t)=>{var r,n;return z?z[t]:(t!=="debug"&&a("Rybbit SDK accessed before initialization. Call rybbit.init() first."),(n=(r=A[t])!=null?r:h[t])!=null?n:void 0)},set:()=>(a("Rybbit config is read-only after initialization."),!1)});async function St(e,t){var r,n,i,o,d,c,u,f,T,C;try{s("Fetching remote configuration...");let b=new AbortController,P=setTimeout(()=>b.abort(),3e3),ee=await fetch(`${e}/site/tracking-config/${t}`,{signal:b.signal});if(clearTimeout(P),ee.ok){let y=await ee.json();return s("Remote configuration fetched successfully",y),{autoTrackPageview:(r=y.trackInitialPageView)!=null?r:h.autoTrackPageview,autoTrackSpa:(n=y.trackSpaNavigation)!=null?n:h.autoTrackSpa,trackQuerystring:(i=y.trackUrlParams)!=null?i:h.trackQuerystring,trackOutbound:(o=y.trackOutbound)!=null?o:h.trackOutbound,enableWebVitals:(d=y.webVitals)!=null?d:h.enableWebVitals,trackErrors:(c=y.trackErrors)!=null?c:h.trackErrors,enableSessionReplay:(u=y.sessionReplay)!=null?u:h.enableSessionReplay,trackButtonClicks:(f=y.trackButtonClicks)!=null?f:h.trackButtonClicks,trackCopy:(T=y.trackCopy)!=null?T:h.trackCopy,trackFormInteractions:(C=y.trackFormInteractions)!=null?C:h.trackFormInteractions}}else return a(`Failed to fetch remote config: ${ee.status}`),null}catch(b){return b.name==="AbortError"?a("Remote config fetch timed out"):a("Error fetching remote config:",b),null}}async function Pe(e){var u,f;if(z)return a("Rybbit SDK already initialized."),!1;if(typeof e!="object"||e===null)return a("Invalid configuration provided to rybbit.init(). Expected an object."),!1;let t=e.analyticsHost;if(!t||t.trim()==="")return a("`analyticsHost` is required in Rybbit config and must be a non-empty string."),!1;let r=t.replace(/\/$/,""),n=e.siteId;if(!n||n.trim()==="")return a("`siteId` is required in Rybbit config and must be a non-empty string."),!1;let o=await St(r,n)||h,d=Array.isArray(e.skipPatterns)?e.skipPatterns:A.skipPatterns,c=Array.isArray(e.maskPatterns)?e.maskPatterns:A.maskPatterns;return z={analyticsHost:r,siteId:n,debounceDuration:Math.max(0,(u=e.debounceDuration)!=null?u:A.debounceDuration),skipPatterns:d,maskPatterns:c,debug:(f=e.debug)!=null?f:A.debug,replayPrivacyConfig:e.replayPrivacyConfig,autoTrackPageview:o.autoTrackPageview,autoTrackSpa:o.autoTrackSpa,trackQuerystring:o.trackQuerystring,trackOutbound:o.trackOutbound,enableWebVitals:o.enableWebVitals,trackErrors:o.trackErrors,enableSessionReplay:o.enableSessionReplay,trackButtonClicks:o.trackButtonClicks,trackCopy:o.trackCopy,trackFormInteractions:o.trackFormInteractions},!0}var k=null,ne=!1;try{let e=localStorage.getItem("rybbit-user-id");e&&(k=e),localStorage.getItem("disable-rybbit")!==null&&(ne=!0)}catch(e){a("localStorage unavailable")}typeof window!="undefined"&&window.__RYBBIT_OPTOUT__&&(ne=!0);function g(e,t={}){if(ne){s("Opted out of tracking.");return}if(!l||!l.analyticsHost||!l.siteId){a("Rybbit config not available. Ensure rybbit.init() was called successfully.");return}let{eventName:r,properties:n,pathOverride:i,webVitals:o}=t;if((e==="custom_event"||e==="performance")&&!r){a("Event name is required and must be a string for performance or custom events.");return}try{let d=new URL(window.location.href),c,u="";if(e==="pageview"&&typeof i=="string"&&i.trim()){s(`Using path override: ${i}`);try{if(!/^\//.test(i.trim())&&!/^https?:\/\//.test(i.trim()))throw new Error("pathOverride must start with /");let P=new URL(i.trim(),"http://dummybase");c=P.pathname,u=P.search||"",s(`Parsed override path: ${c}, search: ${u}`)}catch(P){a(`Invalid pathOverride format: ${i}. Using window location.`),c=I(),u=l.trackQuerystring?d.search:""}}else c=I(),u=l.trackQuerystring?d.search:"";if(e!=="performance"&&re(c,l.skipPatterns)){s(`Skipping track for path: ${c}`);return}let f=re(c,l.maskPatterns);f&&e!=="performance"&&(s(`Masking path ${c} as ${f}`),c=f,u="");let T=p(p(p(p({site_id:l.siteId,hostname:d.hostname,pathname:c,querystring:u,screenWidth:window.screen.width,screenHeight:window.screen.height,language:navigator.language,page_title:document.title,referrer:document.referrer,type:e},(e==="custom_event"||e==="performance"||e==="error")&&{event_name:r}),(e==="custom_event"||e==="outbound"||e==="error"||e==="button_click"||e==="copy"||e==="form_submit"||e==="input_change")&&Object.keys(n!=null?n:{}).length>0&&{properties:JSON.stringify(n)}),e==="performance"&&o&&p({},o)),k&&{user_id:k});s("Sending track event:",T);let C=JSON.stringify(T),b=`${l.analyticsHost}/track`;navigator.sendBeacon?navigator.sendBeacon(b,new Blob([C],{type:"application/json"}))||(a("sendBeacon failed, falling back to fetch."),Ie(b,C)):Ie(b,C)}catch(d){a("Error during tracking:",d)}}function Ie(e,t){fetch(e,{method:"POST",headers:{"Content-Type":"application/json"},body:t,mode:"cors",keepalive:!0}).catch(r=>{a("Fetch request failed:",r)})}async function Le(e,t,r=!0){if(!l||!l.analyticsHost||!l.siteId){a("Rybbit config not available. Ensure rybbit.init() was called successfully.");return}try{await fetch(`${l.analyticsHost}/identify`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({site_id:l.siteId,user_id:e,traits:t,is_new_identify:r}),mode:"cors",keepalive:!0}),s("Identify event sent:",{userId:e,traits:t,isNewIdentify:r})}catch(n){a("Failed to send identify event:",n)}}function xe(e,t){if(e.trim()===""){a("User ID must be a non-empty string");return}k=e.trim();try{localStorage.setItem("rybbit-user-id",k),s("User identified:",k)}catch(r){a("Could not persist user ID to localStorage")}Le(k,t,!0)}function De(e){if(!e||typeof e!="object"){a("Traits must be an object");return}let t=k;if(!t){a("Cannot set traits without identifying user first. Call identify() first.");return}Le(t,e,!1)}function Oe(){k=null;try{localStorage.removeItem("rybbit-user-id"),s("User ID cleared")}catch(e){a("Could not remove user ID from localStorage")}}function ie(){return k}var R,j=!1,M=[],oe="";function Ae(){if(j){s("Automatic tracking already set up.");return}if(!l.autoTrackPageview){s("Automatic pageview tracking is disabled.");return}s("Setting up automatic tracking..."),oe=I();let e=()=>{let t=I();Rt(t),g("pageview")};if(R=l.debounceDuration&&l.debounceDuration>0?Se(()=>{e()},l.debounceDuration):()=>{e()},requestAnimationFrame(()=>{e()}),l.autoTrackSpa){s("Setting up SPA route change tracking.");let t=history.pushState,r=history.replaceState;history.pushState=function(...n){t.apply(this,n),R()},history.replaceState=function(...n){r.apply(this,n),R()},window.addEventListener("popstate",R)}else s("SPA route change tracking is disabled.");window.addEventListener("hashchange",R),j=!0}function Me(){s("Setting up data attribute and outbound link tracking."),document.addEventListener("click",_e,!0)}function _e(e){if(!(e.target instanceof Element))return;let t=e.target;for(;t;){if(t.hasAttribute("data-rybbit-event")){let r=t.getAttribute("data-rybbit-event");if(r){let n={};for(let i of t.attributes)if(i.name.startsWith("data-rybbit-prop-")){let o=i.name.replace("data-rybbit-prop-","");n[o]=i.value}s("Data attribute event triggered:",r,n),g("custom_event",{eventName:r,properties:n})}break}t=t.parentElement}if(l.trackOutbound&&e.target instanceof Element){let r=e.target.closest("a");if(r&&r.href&&Re(r.href)){s("Outbound link clicked:",r.href);let n={url:r.href,text:r.innerText||r.textContent||"",target:r.target||"_self"};g("outbound",{properties:n})}}}function Fe(e){return M.push(e),s("Page change callback added"),()=>{M=M.filter(t=>t!==e),s("Page change callback removed")}}function Rt(e){let t=oe;oe=e,t!==e&&(s(`Page changed from ${t} to ${e}`),M.forEach(r=>{try{r(e,t)}catch(n){a("Error in page change callback:",n)}}))}function Ue(){j&&(s("Cleaning up automatic tracking listeners."),window.removeEventListener("popstate",R),window.removeEventListener("hashchange",R),document.removeEventListener("click",_e,!0),M=[],j=!1)}var qe=-1,x=e=>{addEventListener("pageshow",t=>{t.persisted&&(qe=t.timeStamp,e(t))},!0)},v=(e,t,r,n)=>{let i,o;return d=>{t.value>=0&&(d||n)&&(o=t.value-(i!=null?i:0),(o||i===void 0)&&(i=t.value,t.delta=o,t.rating=((c,u)=>c>u[1]?"poor":c>u[0]?"needs-improvement":"good")(t.value,r),e(t)))}},pe=e=>{requestAnimationFrame(()=>requestAnimationFrame(()=>e()))},ge=()=>{let e=performance.getEntriesByType("navigation")[0];if(e&&e.responseStart>0&&e.responseStart<performance.now())return e},_=()=>{var t;let e=ge();return(t=e==null?void 0:e.activationStart)!=null?t:0},E=(e,t=-1)=>{let r=ge(),n="navigate";return qe>=0?n="back-forward-cache":r&&(document.prerendering||_()>0?n="prerender":document.wasDiscarded?n="restore":r.type&&(n=r.type.replace(/_/g,"-"))),{name:e,value:t,rating:"good",delta:0,entries:[],id:`v5-${Date.now()}-${Math.floor(8999999999999*Math.random())+1e12}`,navigationType:n}},ae=new WeakMap;function me(e,t){return ae.get(e)||ae.set(e,new t),ae.get(e)}var ce=class{constructor(){w(this,"t");w(this,"i",0);w(this,"o",[])}h(t){var i;if(t.hadRecentInput)return;let r=this.o[0],n=this.o.at(-1);this.i&&r&&n&&t.startTime-n.startTime<1e3&&t.startTime-r.startTime<5e3?(this.i+=t.value,this.o.push(t)):(this.i=t.value,this.o=[t]),(i=this.t)==null||i.call(this,t)}},F=(e,t,r={})=>{try{if(PerformanceObserver.supportedEntryTypes.includes(e)){let n=new PerformanceObserver(i=>{Promise.resolve().then(()=>{t(i.getEntries())})});return n.observe(p({type:e,buffered:!0},r)),n}}catch(n){}},be=e=>{let t=!1;return()=>{t||(e(),t=!0)}},L=-1,Ne=()=>document.visibilityState!=="hidden"||document.prerendering?1/0:0,q=e=>{document.visibilityState==="hidden"&&L>-1&&(L=e.type==="visibilitychange"?e.timeStamp:0,Pt())},Be=()=>{addEventListener("visibilitychange",q,!0),addEventListener("prerenderingchange",q,!0)},Pt=()=>{removeEventListener("visibilitychange",q,!0),removeEventListener("prerenderingchange",q,!0)},Qe=()=>{var e;if(L<0){let t=_(),r=document.prerendering||(e=globalThis.performance.getEntriesByType("visibility-state").filter(n=>n.name==="hidden"&&n.startTime>t)[0])==null?void 0:e.startTime;L=r!=null?r:Ne(),Be(),x(()=>{setTimeout(()=>{L=Ne(),Be()})})}return{get firstHiddenTime(){return L}}},Q=e=>{document.prerendering?addEventListener("prerenderingchange",()=>e(),!0):e()},He=[1800,3e3],he=(e,t={})=>{Q(()=>{let r=Qe(),n,i=E("FCP"),o=F("paint",d=>{for(let c of d)c.name==="first-contentful-paint"&&(o.disconnect(),c.startTime<r.firstHiddenTime&&(i.value=Math.max(c.startTime-_(),0),i.entries.push(c),n(!0)))});o&&(n=v(e,i,He,t.reportAllChanges),x(d=>{i=E("FCP"),n=v(e,i,He,t.reportAllChanges),pe(()=>{i.value=performance.now()-d.timeStamp,n(!0)})}))})},We=[.1,.25],Je=(e,t={})=>{he(be(()=>{let r,n=E("CLS",0),i=me(t,ce),o=c=>{for(let u of c)i.h(u);i.i>n.value&&(n.value=i.i,n.entries=i.o,r())},d=F("layout-shift",o);d&&(r=v(e,n,We,t.reportAllChanges),document.addEventListener("visibilitychange",()=>{document.visibilityState==="hidden"&&(o(d.takeRecords()),r(!0))}),x(()=>{i.i=0,n=E("CLS",0),r=v(e,n,We,t.reportAllChanges),pe(()=>r())}),setTimeout(r))}))},Ge=0,se=1/0,K=0,It=e=>{for(let t of e)t.interactionId&&(se=Math.min(se,t.interactionId),K=Math.max(K,t.interactionId),Ge=K?(K-se)/7+1:0)},le,$e=()=>{var e;return le?Ge:(e=performance.interactionCount)!=null?e:0},Lt=()=>{"interactionCount"in performance||le||(le=F("event",It,{type:"event",buffered:!0,durationThreshold:0}))},Ve=0,ue=class{constructor(){w(this,"u",[]);w(this,"l",new Map);w(this,"m");w(this,"v")}p(){Ve=$e(),this.u.length=0,this.l.clear()}P(){let t=Math.min(this.u.length-1,Math.floor(($e()-Ve)/50));return this.u[t]}h(t){var i,o;if((i=this.m)==null||i.call(this,t),!t.interactionId&&t.entryType!=="first-input")return;let r=this.u.at(-1),n=this.l.get(t.interactionId);if(n||this.u.length<10||t.duration>r.T){if(n?t.duration>n.T?(n.entries=[t],n.T=t.duration):t.duration===n.T&&t.startTime===n.entries[0].startTime&&n.entries.push(t):(n={id:t.interactionId,entries:[t],T:t.duration},this.l.set(n.id,n),this.u.push(n)),this.u.sort((d,c)=>c.T-d.T),this.u.length>10){let d=this.u.splice(10);for(let c of d)this.l.delete(c.id)}(o=this.v)==null||o.call(this,n)}}},Xe=e=>{let t=globalThis.requestIdleCallback||setTimeout;document.visibilityState==="hidden"?e():(e=be(e),document.addEventListener("visibilitychange",e,{once:!0}),t(()=>{e(),document.removeEventListener("visibilitychange",e)}))},ze=[200,500],Ye=(e,t={})=>{globalThis.PerformanceEventTiming&&"interactionId"in PerformanceEventTiming.prototype&&Q(()=>{var c;Lt();let r,n=E("INP"),i=me(t,ue),o=u=>{Xe(()=>{for(let T of u)i.h(T);let f=i.P();f&&f.T!==n.value&&(n.value=f.T,n.entries=f.entries,r())})},d=F("event",o,{durationThreshold:(c=t.durationThreshold)!=null?c:40});r=v(e,n,ze,t.reportAllChanges),d&&(d.observe({type:"first-input",buffered:!0}),document.addEventListener("visibilitychange",()=>{document.visibilityState==="hidden"&&(o(d.takeRecords()),r(!0))}),x(()=>{i.p(),n=E("INP"),r=v(e,n,ze,t.reportAllChanges)}))})},de=class{constructor(){w(this,"m")}h(t){var r;(r=this.m)==null||r.call(this,t)}},je=[2500,4e3],Ze=(e,t={})=>{Q(()=>{let r=Qe(),n,i=E("LCP"),o=me(t,de),d=u=>{t.reportAllChanges||(u=u.slice(-1));for(let f of u)o.h(f),f.startTime<r.firstHiddenTime&&(i.value=Math.max(f.startTime-_(),0),i.entries=[f],n())},c=F("largest-contentful-paint",d);if(c){n=v(e,i,je,t.reportAllChanges);let u=be(()=>{d(c.takeRecords()),c.disconnect(),n(!0)});for(let f of["keydown","click","visibilitychange"])addEventListener(f,()=>Xe(u),{capture:!0,once:!0});x(f=>{i=E("LCP"),n=v(e,i,je,t.reportAllChanges),pe(()=>{i.value=performance.now()-f.timeStamp,n(!0)})})}})},Ke=[800,1800],fe=e=>{document.prerendering?Q(()=>fe(e)):document.readyState!=="complete"?addEventListener("load",()=>fe(e),!0):setTimeout(e)},et=(e,t={})=>{let r=E("TTFB"),n=v(e,r,Ke,t.reportAllChanges);fe(()=>{let i=ge();i&&(r.value=Math.max(i.responseStart-_(),0),r.entries=[i],n(!0),x(()=>{r=E("TTFB",0),n=v(e,r,Ke,t.reportAllChanges),n(!0)}))})};var G={lcp:null,cls:null,inp:null,fcp:null,ttfb:null},D=!1,J=null;function xt(){if(D)return;Object.values(G).every(t=>t!==null)&&ye()}function ye(){D||(D=!0,J&&(clearTimeout(J),J=null),s("Sending web vitals data:",G),g("performance",{eventName:"web-vitals",webVitals:G}))}function U(e){if(D)return;let t=e.name.toLowerCase();G[t]=e.value,s(`Collected ${t}:`,e.value),xt()}function tt(){if(!l.enableWebVitals){s("Web vitals tracking is disabled.");return}s("Initializing web vitals tracking...");try{Ze(U),Je(U),Ye(U),he(U),et(U),J=setTimeout(()=>{D||(s("Web vitals timeout reached, sending collected metrics."),ye())},2e4),window.addEventListener("beforeunload",()=>{D||ye()}),s("Web vitals tracking initialized successfully.")}catch(e){a("Error setting up web vitals tracking:",e)}}var N=null,B=null;function rt(){l.trackErrors&&(s("Setting up error tracking"),N=e=>{Dt(e)},B=e=>{Ot(e)},window.addEventListener("error",N),window.addEventListener("unhandledrejection",B))}function nt(){N&&(window.removeEventListener("error",N),N=null),B&&(window.removeEventListener("unhandledrejection",B),B=null),s("Error tracking cleaned up")}function Dt(e){var o,d;let t=window.location.origin,r=e.filename||"";if(r)try{if(new URL(r).origin!==t){s("Skipping third-party error:",r);return}}catch(c){}let n=((o=e.error)==null?void 0:o.stack)||"";if(!r&&n&&!n.includes(t)){s("Skipping third-party error based on stack trace");return}let i={message:(e.message||"Unknown error").substring(0,500),stack:n.substring(0,2e3),filename:r||void 0,lineno:e.lineno||void 0,colno:e.colno||void 0,timestamp:Date.now()};X(((d=e.error)==null?void 0:d.name)||"Error",i)}function Ot(e){let t="Unhandled promise rejection",r="";e.reason instanceof Error?(t=e.reason.message||t,r=e.reason.stack||""):typeof e.reason=="string"?t=e.reason:e.reason&&typeof e.reason=="object"&&(t=JSON.stringify(e.reason));let n={message:t.substring(0,500),stack:r.substring(0,2e3),timestamp:Date.now()};X("UnhandledRejection",n)}function X(e,t,r){let n=p({error_name:e,message:t.message},r);t.stack&&(n.stack=t.stack),t.filename&&(n.filename=t.filename),t.lineno&&(n.line_number=t.lineno),t.colno&&(n.column_number=t.colno),g("error",{eventName:e,properties:n})}function it(e,t){var r,n;if(!l.trackErrors){a("Error tracking is not enabled. Enable it via remote config.");return}if(e instanceof ErrorEvent){let i={message:(e.message||"Unknown error").substring(0,500),stack:(((r=e.error)==null?void 0:r.stack)||"").substring(0,2e3),filename:e.filename||void 0,lineno:e.lineno||void 0,colno:e.colno||void 0,timestamp:Date.now()};X(((n=e.error)==null?void 0:n.name)||"Error",i,t)}else{let i={message:(e.message||"Unknown error").substring(0,500),stack:(e.stack||"").substring(0,2e3),timestamp:Date.now()};X(e.name||"Error",i,t)}}var H=null;function ot(){l.trackButtonClicks&&(s("Setting up button click tracking"),H=e=>{At(e)},document.addEventListener("click",H,!0))}function at(){H&&(document.removeEventListener("click",H,!0),H=null)}function At(e){var o;let t=e.target;if(!t)return;let r=Mt(t);if(!r||r.hasAttribute("data-rybbit-event"))return;let n=p({},_t(r)),i=(o=r.textContent)==null?void 0:o.trim().substring(0,100);i&&(n.text=i),g("button_click",{properties:n})}function Mt(e){var n;if(e.tagName==="BUTTON"||e.getAttribute("role")==="button")return e;if(e.tagName==="INPUT"){let i=(n=e.type)==null?void 0:n.toLowerCase();if(i==="submit"||i==="button")return e}let t=e.parentElement,r=0;for(;t&&r<3;){if(t.tagName==="BUTTON"||t.getAttribute("role")==="button")return t;t=t.parentElement,r++}return null}function _t(e){let t={};for(let r of e.attributes)if(r.name.startsWith("data-rybbit-prop-")){let n=r.name.replace("data-rybbit-prop-","");t[n]=r.value}return t}var W=null;function st(){l.trackCopy&&(s("Setting up copy tracking"),W=()=>{Ft()},document.addEventListener("copy",W))}function ct(){W&&(document.removeEventListener("copy",W),W=null)}function Ft(){let e=window.getSelection();if(!e||e.isCollapsed)return;let t=e.toString(),r=t.length;if(r===0)return;let n=e.anchorNode,i=n instanceof HTMLElement?n:n==null?void 0:n.parentElement;if(!i)return;let o=we(p({text:t.substring(0,500)},r>500&&{textLength:r}),{sourceElement:i.tagName.toLowerCase()});g("copy",{properties:o})}var $=null,V=null;function lt(){l.trackFormInteractions&&(s("Setting up form tracking"),$=e=>{Ut(e)},V=e=>{Nt(e)},document.addEventListener("submit",$,!0),document.addEventListener("change",V,!0))}function ut(){$&&(document.removeEventListener("submit",$,!0),$=null),V&&(document.removeEventListener("change",V,!0),V=null)}function Ut(e){let t=e.target;if(t.tagName!=="FORM")return;let r=p({formId:t.id||"",formName:t.name||"",formAction:t.getAttribute("action")||"",method:(t.method||"get").toUpperCase(),fieldCount:t.elements.length},dt(t));g("form_submit",{properties:r})}function Nt(e){var o,d,c;let t=e.target,r=t.tagName.toUpperCase();if(!["INPUT","SELECT","TEXTAREA"].includes(r))return;if(r==="INPUT"){let u=(o=t.type)==null?void 0:o.toLowerCase();if(u==="hidden"||u==="password")return}let n=p({element:r.toLowerCase(),inputName:t.name||t.id||""},dt(t));r==="INPUT"&&(n.inputType=(d=t.type)==null?void 0:d.toLowerCase());let i=(c=t.form)==null?void 0:c.id;i&&(n.formId=i),g("input_change",{properties:n})}function dt(e){let t={};for(let r of e.attributes)if(r.name.startsWith("data-rybbit-prop-")){let n=r.name.replace("data-rybbit-prop-","");t[n]=r.value}return t}var Z=null,O=!1,ke=null,S=[],Y,ve;async function ft(e){if(l.enableSessionReplay){ve=e;try{Z=(await import("rrweb")).record,s("rrweb loaded successfully"),pt()}catch(t){a("Failed to load rrweb. Make sure it's installed as a peer dependency:",t)}}}function pt(){var e,t,r,n,i,o,d,c;if(!(O||!Z||!l.enableSessionReplay))try{let u=l.replayPrivacyConfig||{},f={mousemove:!1,mouseInteraction:{MouseUp:!1,MouseDown:!1,Click:!0,ContextMenu:!1,DblClick:!0,Focus:!0,Blur:!0,TouchStart:!1,TouchEnd:!1},scroll:500,input:"last",media:800},T={script:!1,comment:!0,headFavicon:!0,headWhitespace:!0,headMetaDescKeywords:!0,headMetaSocial:!0,headMetaRobots:!0,headMetaHttpEquiv:!0,headMetaAuthorship:!0,headMetaVerification:!0},C={emit:b=>{Bt({type:b.type,data:b.data,timestamp:b.timestamp||Date.now()})},recordCanvas:!1,checkoutEveryNms:6e4,checkoutEveryNth:500,blockClass:(e=u.blockClass)!=null?e:"rr-block",blockSelector:(t=u.blockSelector)!=null?t:void 0,ignoreClass:(r=u.ignoreClass)!=null?r:"rr-ignore",ignoreSelector:(n=u.ignoreSelector)!=null?n:void 0,maskTextClass:(i=u.maskTextClass)!=null?i:"rr-mask",maskAllInputs:(o=u.maskAllInputs)!=null?o:!0,maskInputOptions:{password:!0,email:!0},collectFonts:(d=u.collectFonts)!=null?d:!0,sampling:f,slimDOMOptions:(c=u.slimDOMOptions)!=null?c:T};u.maskTextSelectors&&u.maskTextSelectors.length>0&&(C.maskTextSelector=u.maskTextSelectors.join(", ")),ke=Z(C),O=!0,Ht(),s("Session replay recording started")}catch(u){a("Failed to start session replay recording:",u)}}function gt(){if(!l.enableSessionReplay){a("Session replay is not enabled. Enable it via remote config.");return}if(!Z){a("rrweb is not loaded. Ensure it's installed as a peer dependency.");return}if(O){s("Session replay is already recording");return}pt()}function Ee(){if(!O){s("Session replay is not currently recording");return}ke&&ke(),O=!1,bt(),S.length>0&&Te(),s("Session replay recording stopped")}function mt(){return O}function Bt(e){S.push(e),S.length>=250&&Te()}function Ht(){bt(),Y=window.setInterval(()=>{S.length>0&&Te()},5e3)}function bt(){Y!==void 0&&(clearInterval(Y),Y=void 0)}function Te(){if(S.length===0)return;let e=[...S];S=[];let t={userId:ve||"",events:e,metadata:{pageUrl:window.location.href,viewportWidth:screen.width,viewportHeight:screen.height,language:navigator.language}};Wt(t).catch(r=>{a("Failed to send session replay batch:",r),S.unshift(...e)})}async function Wt(e){let t=`${l.analyticsHost}/session-replay/record/${l.siteId}`,r=JSON.stringify(e),n=await fetch(t,{method:"POST",headers:{"Content-Type":"application/json"},body:r,mode:"cors",keepalive:!0});if(!n.ok)throw new Error(`Failed to send replay batch: ${n.status}`);s(`Session replay batch sent: ${e.events.length} events`)}function ht(e){ve=e}function yt(){Ee()}var m=!1,$t={init:async e=>{if(m){a("Rybbit SDK already initialized. Call init() only once.");return}await Pe(e)&&(m=!0,s("Config:",p({},l)),Ae(),Me(),tt(),rt(),ot(),st(),lt(),await ft(ie()||void 0))},pageview:e=>{if(!m){a("Rybbit SDK not initialized. Call rybbit.init() first.");return}g("pageview",{pathOverride:e})},event:(e,t)=>{if(!m){a("Rybbit SDK not initialized. Call rybbit.init() first.");return}if(!e){a("Event name is required and must be a string.");return}g("custom_event",{eventName:e,properties:t})},trackOutbound:(e,t="",r="_self")=>{if(!m){a("Rybbit SDK not initialized. Call rybbit.init() first.");return}if(!e){a("Outbound link URL is required and must be a string.");return}g("outbound",{properties:{url:e,text:t,target:r}})},identify:(e,t)=>{if(!m){a("Rybbit SDK not initialized. Call rybbit.init() first.");return}xe(e,t),ht(e)},setTraits:e=>{if(!m){a("Rybbit SDK not initialized. Call rybbit.init() first.");return}De(e)},clearUserId:()=>{if(!m){a("Rybbit SDK not initialized. Call rybbit.init() first.");return}Oe()},getUserId:()=>m?ie():(a("Rybbit SDK not initialized. Call rybbit.init() first."),null),error:(e,t)=>{if(!m){a("Rybbit SDK not initialized. Call rybbit.init() first.");return}it(e,t)},onPageChange:e=>m?Fe(e):(a("Rybbit SDK not initialized. Call rybbit.init() first."),()=>{}),startSessionReplay:()=>{if(!m){a("Rybbit SDK not initialized. Call rybbit.init() first.");return}gt()},stopSessionReplay:()=>{if(!m){a("Rybbit SDK not initialized. Call rybbit.init() first.");return}Ee()},isSessionReplayActive:()=>m?mt():(a("Rybbit SDK not initialized. Call rybbit.init() first."),!1),cleanup:()=>{Ue(),nt(),at(),ct(),ut(),yt(),m=!1}},Vr=$t;export{Vr as default};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rybbit/js",
3
- "version": "0.5.0",
3
+ "version": "0.6.1",
4
4
  "description": "Rybbit Web SDK",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.mjs",
@@ -15,7 +15,9 @@
15
15
  ],
16
16
  "scripts": {
17
17
  "build": "tsup",
18
- "typecheck": "tsc --noEmit"
18
+ "typecheck": "tsc --noEmit",
19
+ "test": "vitest",
20
+ "test:run": "vitest run"
19
21
  },
20
22
  "repository": {
21
23
  "type": "git",
@@ -48,6 +50,8 @@
48
50
  "rrweb": "^2.0.0-alpha.4",
49
51
  "tsup": "^8.5.0",
50
52
  "typescript": "^5.8.3",
51
- "web-vitals": "^5.0.3"
53
+ "vitest": "^3.2.4",
54
+ "web-vitals": "^5.0.3",
55
+ "jsdom": "^26.0.0"
52
56
  }
53
57
  }