@rybbit/js 0.1.0 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  The official JavaScript Web SDK for [Rybbit](https://github.com/rybbit-io/rybbit).
4
4
 
5
- For usage instructions, see the [docs](https://www.rybbit.io/docs/web).
5
+ For usage instructions, see the [docs](https://www.rybbit.io/docs/sdks/web).
6
6
 
7
7
  ## Installation
8
8
 
package/dist/index.d.mts CHANGED
@@ -6,18 +6,27 @@ interface RybbitConfig {
6
6
  autoTrackSpaRoutes?: boolean;
7
7
  trackQuerystring?: boolean;
8
8
  trackOutboundLinks?: boolean;
9
+ trackHashRoutes?: boolean;
10
+ trackDataAttributes?: boolean;
11
+ trackWebVitals?: boolean;
12
+ webVitalsTimeout?: number;
9
13
  skipPatterns?: string[];
10
14
  maskPatterns?: string[];
11
15
  debug?: boolean;
12
16
  }
17
+ type PropertyValue = string | number | boolean;
13
18
  interface TrackProperties {
14
- [key: string]: any;
19
+ [key: string]: PropertyValue | PropertyValue[];
15
20
  }
16
21
  interface RybbitAPI {
17
22
  init: (config: RybbitConfig) => void;
18
23
  pageview: (path?: string) => void;
19
24
  event: (name: string, properties?: TrackProperties) => void;
20
- trackOutboundLink: (url: string, text?: string, target?: string) => void;
25
+ outbound: (url: string, text?: string, target?: string) => void;
26
+ identify: (userId: string) => void;
27
+ clearUserId: () => void;
28
+ getUserId: () => string | null;
29
+ cleanup: () => void;
21
30
  }
22
31
 
23
32
  declare const rybbit: RybbitAPI;
package/dist/index.d.ts CHANGED
@@ -6,18 +6,27 @@ interface RybbitConfig {
6
6
  autoTrackSpaRoutes?: boolean;
7
7
  trackQuerystring?: boolean;
8
8
  trackOutboundLinks?: boolean;
9
+ trackHashRoutes?: boolean;
10
+ trackDataAttributes?: boolean;
11
+ trackWebVitals?: boolean;
12
+ webVitalsTimeout?: number;
9
13
  skipPatterns?: string[];
10
14
  maskPatterns?: string[];
11
15
  debug?: boolean;
12
16
  }
17
+ type PropertyValue = string | number | boolean;
13
18
  interface TrackProperties {
14
- [key: string]: any;
19
+ [key: string]: PropertyValue | PropertyValue[];
15
20
  }
16
21
  interface RybbitAPI {
17
22
  init: (config: RybbitConfig) => void;
18
23
  pageview: (path?: string) => void;
19
24
  event: (name: string, properties?: TrackProperties) => void;
20
- trackOutboundLink: (url: string, text?: string, target?: string) => void;
25
+ outbound: (url: string, text?: string, target?: string) => void;
26
+ identify: (userId: string) => void;
27
+ clearUserId: () => void;
28
+ getUserId: () => string | null;
29
+ cleanup: () => void;
21
30
  }
22
31
 
23
32
  declare const rybbit: RybbitAPI;
package/dist/index.js CHANGED
@@ -1,7 +1,7 @@
1
1
  /*!
2
- * @rybbit/js v0.1.0
2
+ * @rybbit/js v0.2.0
3
3
  * Rybbit Web SDK
4
4
  * (c) 2025 Rybbit
5
5
  * Released under the AGPL-3.0-only license.
6
6
  */
7
- "use strict";var T=Object.defineProperty;var D=Object.getOwnPropertyDescriptor;var K=Object.getOwnPropertyNames,w=Object.getOwnPropertySymbols;var C=Object.prototype.hasOwnProperty,$=Object.prototype.propertyIsEnumerable;var E=(e,t,i)=>t in e?T(e,t,{enumerable:!0,configurable:!0,writable:!0,value:i}):e[t]=i,y=(e,t)=>{for(var i in t||(t={}))C.call(t,i)&&E(e,i,t[i]);if(w)for(var i of w(t))$.call(t,i)&&E(e,i,t[i]);return e};var z=(e,t)=>{for(var i in t)T(e,i,{get:t[i],enumerable:!0})},H=(e,t,i,s)=>{if(t&&typeof t=="object"||typeof t=="function")for(let n of K(t))!C.call(e,n)&&n!==i&&T(e,n,{get:()=>t[n],enumerable:!(s=D(t,n))||s.enumerable});return e};var N=e=>H(T({},"__esModule",{value:!0}),e);var j={};z(j,{default:()=>Q});module.exports=N(j);function O(e,t){let i=null;return function(...s){let n=this;i!==null&&clearTimeout(i),i=setTimeout(()=>{i=null,e.apply(n,s)},t)}}function x(e){try{let t=window.location.hostname,i=new URL(e,window.location.href).hostname;return!!i&&i!==t}catch(t){return!1}}function q(e){try{let t="__DOUBLE_ASTERISK_TOKEN__",i="__SINGLE_ASTERISK_TOKEN__",n=e.replace(/\*\*/g,t).replace(/\*/g,i).replace(/[.+?^${}()|[\]\\]/g,"\\$&");n=n.replace(/\//g,"\\/");let c=n.replace(new RegExp(t,"g"),".*").replace(new RegExp(i,"g"),"[^/]+");return new RegExp("^"+c+"$")}catch(t){return r(`Invalid pattern: ${e}`,t),null}}function S(e,t=[]){if(!t||t.length===0)return null;for(let i of t){let s=q(i);if(s&&s.test(e))return i}return null}function o(...e){a.debug&&console.log("[Rybbit]",...e)}function r(...e){console.error("[Rybbit Error]",...e)}var l={debounce:500,autoTrackPageviews:!0,autoTrackSpaRoutes:!0,trackQuerystring:!0,trackOutboundLinks:!0,skipPatterns:[],maskPatterns:[],debug:!1},R=null,a=new Proxy({},{get:(e,t)=>{var i;return R?R[t]:(t!=="debug"&&r("Rybbit SDK accessed before initialization. Call rybbit.init() first."),(i=l[t])!=null?i:void 0)},set:()=>(r("Rybbit config is read-only after initialization."),!1)});function _(e){var p,m,b,k,f,P;if(R)return r("Rybbit SDK already initialized."),!1;if(typeof e!="object"||e===null)return r("Invalid configuration provided to rybbit.init(). Expected an object."),!1;let t=e,i=t.analyticsHost;if(!i)return r("`analyticsHost` is required in Rybbit config and must be a string."),!1;let s=i.replace(/\/$/,""),n=t.siteId;if(n==null||String(n).trim()==="")return r("`siteId` is required in Rybbit config and must be a non-empty string or number."),!1;let c=String(n),u=Array.isArray(t.skipPatterns)?t.skipPatterns:l.skipPatterns,d=Array.isArray(t.maskPatterns)?t.maskPatterns:l.maskPatterns;return R={analyticsHost:s,siteId:c,debounce:Math.max(0,(p=t.debounce)!=null?p:l.debounce),autoTrackPageviews:(m=t.autoTrackPageviews)!=null?m:l.autoTrackPageviews,autoTrackSpaRoutes:(b=t.autoTrackSpaRoutes)!=null?b:l.autoTrackSpaRoutes,trackQuerystring:(k=t.trackQuerystring)!=null?k:l.trackQuerystring,trackOutboundLinks:(f=t.trackOutboundLinks)!=null?f:l.trackOutboundLinks,debug:(P=t.debug)!=null?P:l.debug,skipPatterns:u,maskPatterns:d},!0}var U=!1;function g(e,t={}){if(U){o("Tracking is paused.");return}if(!a||!a.analyticsHost||!a.siteId){r("Rybbit config not available. Ensure rybbit.init() was called successfully.");return}let{eventName:i,properties:s={},pathOverride:n}=t;if(e==="custom_event"&&!i){r("Event name is required and must be a string for custom events.");return}try{let c=new URL(window.location.href),u,d="";if(e==="pageview"&&typeof n=="string"&&n.trim()){o(`Using path override: ${n}`);try{let f=new URL(n,"http://dummybase");u=f.pathname,d=f.search||"",o(`Parsed override path: ${u}, search: ${d}`)}catch(f){r(`Invalid pathOverride format: ${n}. Using window location.`),u=c.pathname,d=a.trackQuerystring?c.search:""}}else u=c.pathname,d=a.trackQuerystring?c.search:"";if(S(u,a.skipPatterns)){o(`Skipping track for path: ${u}`);return}let p=S(u,a.maskPatterns);p&&(o(`Masking path ${u} as ${p}`),u=p,d="");let m=y(y({site_id:a.siteId,hostname:c.hostname,pathname:u,querystring:d,screenWidth:window.innerWidth,screenHeight:window.innerHeight,language:navigator.language,page_title:document.title,referrer:document.referrer||"direct",type:e},e==="custom_event"&&{event_name:i}),(e==="custom_event"||e==="outbound")&&Object.keys(s).length>0&&{properties:JSON.stringify(s)});o("Sending track event:",m);let b=JSON.stringify(m),k=`${a.analyticsHost}/track`;navigator.sendBeacon?navigator.sendBeacon(k,new Blob([b],{type:"application/json"}))||(r("sendBeacon failed, falling back to fetch."),L(k,b)):L(k,b)}catch(c){r("Error during tracking:",c)}}function L(e,t){fetch(e,{method:"POST",headers:{"Content-Type":"application/json"},body:t,mode:"cors",keepalive:!0}).catch(i=>{r("Fetch request failed:",i)})}var h,I=!1;function A(){if(I){o("Automatic tracking already set up.");return}if(!a.autoTrackPageviews){o("Automatic pageview tracking is disabled.");return}if(o("Setting up automatic tracking..."),h=a.debounce&&a.debounce>0?O(()=>g("pageview"),a.debounce):()=>g("pageview"),requestAnimationFrame(()=>{h()}),a.autoTrackSpaRoutes){o("Setting up SPA route change tracking.");let e=history.pushState,t=history.replaceState;history.pushState=function(...i){e.apply(this,i),h()},history.replaceState=function(...i){t.apply(this,i),h()},window.addEventListener("popstate",h)}else o("SPA route change tracking is disabled.");a.trackOutboundLinks?(o("Setting up outbound link tracking."),document.addEventListener("click",M,!0)):o("Outbound link tracking is disabled."),I=!0}function M(e){let i=e.target.closest("a");if(i&&i.href&&x(i.href)){o("Outbound link clicked:",i.href);let s={url:i.href,text:i.innerText||i.textContent||"",target:i.target||"_self"};g("outbound",{properties:s})}}var v=!1,B={init:e=>{if(v){r("Rybbit SDK already initialized. Call init() only once.");return}_(e)&&(v=!0,o("SDK Initialized. Version: 0.1.0"),o("Config:",y({},a)),A())},pageview:e=>{if(!v){r("Rybbit SDK not initialized. Call rybbit.init() first.");return}g("pageview",{pathOverride:e})},event:(e,t)=>{if(!v){r("Rybbit SDK not initialized. Call rybbit.init() first.");return}if(!e){r("Event name is required and must be a string.");return}g("custom_event",{eventName:e,properties:t})},trackOutboundLink:(e,t="",i="_self")=>{if(!v){r("Rybbit SDK not initialized. Call rybbit.init() first.");return}if(!e){r("Outbound link URL is required and must be a string.");return}g("outbound",{properties:{url:e,text:t,target:i}})}},Q=B;
7
+ "use strict";var D=Object.defineProperty;var Ht=Object.getOwnPropertyDescriptor;var Ut=Object.getOwnPropertyNames,st=Object.getOwnPropertySymbols;var lt=Object.prototype.hasOwnProperty,Nt=Object.prototype.propertyIsEnumerable;var N=(e,t,i)=>t in e?D(e,t,{enumerable:!0,configurable:!0,writable:!0,value:i}):e[t]=i,m=(e,t)=>{for(var i in t||(t={}))lt.call(t,i)&&N(e,i,t[i]);if(st)for(var i of st(t))Nt.call(t,i)&&N(e,i,t[i]);return e};var Ft=(e,t)=>{for(var i in t)D(e,i,{get:t[i],enumerable:!0})},zt=(e,t,i,r)=>{if(t&&typeof t=="object"||typeof t=="function")for(let n of Ut(t))!lt.call(e,n)&&n!==i&&D(e,n,{get:()=>t[n],enumerable:!(r=Ht(t,n))||r.enumerable});return e};var $t=e=>zt(D({},"__esModule",{value:!0}),e);var y=(e,t,i)=>N(e,typeof t!="symbol"?t+"":t,i);var Yt={};Ft(Yt,{default:()=>Jt});module.exports=$t(Yt);function ct(e,t){let i=null;return function(...r){let n=this;i!==null&&clearTimeout(i),i=setTimeout(()=>{i=null,e.apply(n,r)},t)}}function ut(e){try{let t=window.location.hostname,i=new URL(e,window.location.href).hostname;return!!i&&i!==t}catch(t){return!1}}function Bt(e){try{let t="__DOUBLE_ASTERISK_TOKEN__",i="__SINGLE_ASTERISK_TOKEN__",n=e.replace(/\*\*/g,t).replace(/\*/g,i).replace(/[.+?^${}()|[\]\\]/g,"\\$&");n=n.replace(/\//g,"\\/");let u=n.replace(new RegExp(t,"g"),".*").replace(new RegExp(i,"g"),"[^/]+");return new RegExp("^"+u+"$")}catch(t){return o(`Invalid pattern: ${e}`,t),null}}function F(e,t=[]){if(!t||t.length===0)return null;for(let i of t){let r=Bt(i);if(r&&r.test(e))return i}return null}function s(...e){l.debug&&console.log("[Rybbit]",...e)}function o(...e){l.debug&&console.error("[Rybbit Error]",...e)}function z(){let e=new URL(window.location.href),t=e.pathname;return l.trackHashRoutes&&e.hash&&(t+=e.hash),t}var g={debounce:500,autoTrackPageviews:!0,autoTrackSpaRoutes:!0,trackQuerystring:!0,trackOutboundLinks:!0,trackHashRoutes:!0,trackDataAttributes:!0,trackWebVitals:!0,webVitalsTimeout:2e4,skipPatterns:[],maskPatterns:[],debug:!1},O=null,l=new Proxy({},{get:(e,t)=>{var i;return O?O[t]:(t!=="debug"&&o("Rybbit SDK accessed before initialization. Call rybbit.init() first."),(i=g[t])!=null?i:void 0)},set:()=>(o("Rybbit config is read-only after initialization."),!1)});function dt(e){var d,f,w,C,P,S,rt,nt,at,ot;if(O)return o("Rybbit SDK already initialized."),!1;if(typeof e!="object"||e===null)return o("Invalid configuration provided to rybbit.init(). Expected an object."),!1;let t=e,i=t.analyticsHost;if(!i)return o("`analyticsHost` is required in Rybbit config and must be a string."),!1;let r=i.replace(/\/$/,""),n=t.siteId;if(n==null||String(n).trim()==="")return o("`siteId` is required in Rybbit config and must be a non-empty string or number."),!1;let u=String(n),c=Array.isArray(t.skipPatterns)?t.skipPatterns:g.skipPatterns,a=Array.isArray(t.maskPatterns)?t.maskPatterns:g.maskPatterns;return O={analyticsHost:r,siteId:u,debounce:Math.max(0,(d=t.debounce)!=null?d:g.debounce),autoTrackPageviews:(f=t.autoTrackPageviews)!=null?f:g.autoTrackPageviews,autoTrackSpaRoutes:(w=t.autoTrackSpaRoutes)!=null?w:g.autoTrackSpaRoutes,trackQuerystring:(C=t.trackQuerystring)!=null?C:g.trackQuerystring,trackOutboundLinks:(P=t.trackOutboundLinks)!=null?P:g.trackOutboundLinks,trackHashRoutes:(S=t.trackHashRoutes)!=null?S:g.trackHashRoutes,trackDataAttributes:(rt=t.trackDataAttributes)!=null?rt:g.trackDataAttributes,trackWebVitals:(nt=t.trackWebVitals)!=null?nt:g.trackWebVitals,webVitalsTimeout:Math.max(1e3,(at=t.webVitalsTimeout)!=null?at:g.webVitalsTimeout),skipPatterns:c,maskPatterns:a,debug:(ot=t.debug)!=null?ot:g.debug},!0}var v=null,$=!1;try{let e=localStorage.getItem("rybbit-user-id");e&&(v=e),localStorage.getItem("disable-rybbit")!==null&&($=!0)}catch(e){o("localStorage unavailable")}typeof window!="undefined"&&window.__RYBBIT_OPTOUT__&&($=!0);function p(e,t={}){if($){s("Opted out of tracking.");return}if(!l||!l.analyticsHost||!l.siteId){o("Rybbit config not available. Ensure rybbit.init() was called successfully.");return}let{eventName:i,properties:r,pathOverride:n,webVitals:u}=t;if((e==="custom_event"||e==="performance")&&!i){o("Event name is required and must be a string for performance or custom events.");return}try{let c=new URL(window.location.href),a,d="";if(e==="pageview"&&typeof n=="string"&&n.trim()){s(`Using path override: ${n}`);try{let S=new URL(n,"http://dummybase");a=S.pathname,d=S.search||"",s(`Parsed override path: ${a}, search: ${d}`)}catch(S){o(`Invalid pathOverride format: ${n}. Using window location.`),a=z(),d=l.trackQuerystring?c.search:""}}else a=z(),d=l.trackQuerystring?c.search:"";if(e!=="performance"&&F(a,l.skipPatterns)){s(`Skipping track for path: ${a}`);return}let f=F(a,l.maskPatterns);f&&e!=="performance"&&(s(`Masking path ${a} as ${f}`),a=f,d="");let w=m(m(m(m({site_id:l.siteId,hostname:c.hostname,pathname:a,querystring:d,screenWidth:window.innerWidth,screenHeight:window.innerHeight,language:navigator.language,page_title:document.title,referrer:document.referrer||"direct",type:e},(e==="custom_event"||e==="performance")&&{event_name:i}),(e==="custom_event"||e==="outbound")&&Object.keys(r!=null?r:{}).length>0&&{properties:JSON.stringify(r)}),e==="performance"&&u&&m({},u)),v&&{user_id:v});s("Sending track event:",w);let C=JSON.stringify(w),P=`${l.analyticsHost}/track`;navigator.sendBeacon?navigator.sendBeacon(P,new Blob([C],{type:"application/json"}))||(o("sendBeacon failed, falling back to fetch."),ft(P,C)):ft(P,C)}catch(c){o("Error during tracking:",c)}}function ft(e,t){fetch(e,{method:"POST",headers:{"Content-Type":"application/json"},body:t,mode:"cors",keepalive:!0}).catch(i=>{o("Fetch request failed:",i)})}function gt(e){if(e.trim()===""){o("User ID must be a non-empty string");return}v=e.trim();try{localStorage.setItem("rybbit-user-id",v),s("User identified:",v)}catch(t){o("Could not persist user ID to localStorage")}}function pt(){v=null;try{localStorage.removeItem("rybbit-user-id"),s("User ID cleared")}catch(e){o("Could not remove user ID from localStorage")}}function mt(){return v}var k,_=!1;function bt(){if(_){s("Automatic tracking already set up.");return}if(!l.autoTrackPageviews){s("Automatic pageview tracking is disabled.");return}if(s("Setting up automatic tracking..."),k=l.debounce&&l.debounce>0?ct(()=>p("pageview"),l.debounce):()=>p("pageview"),requestAnimationFrame(()=>{k()}),l.autoTrackSpaRoutes){s("Setting up SPA route change tracking.");let e=history.pushState,t=history.replaceState;history.pushState=function(...i){e.apply(this,i),k()},history.replaceState=function(...i){t.apply(this,i),k()},window.addEventListener("popstate",k)}else s("SPA route change tracking is disabled.");l.trackHashRoutes?window.addEventListener("hashchange",k):s("Hash route tracking is disabled."),_=!0}function ht(){if(!l.trackDataAttributes){s("Data attribute tracking is disabled.");return}s("Setting up data attribute and outbound link tracking."),document.addEventListener("click",yt,!0)}function yt(e){if(!(e.target instanceof Element))return;let t=e.target;for(;t;){if(t.hasAttribute("data-rybbit-event")){let i=t.getAttribute("data-rybbit-event");if(i){let r={};for(let n of t.attributes)if(n.name.startsWith("data-rybbit-prop-")){let u=n.name.replace("data-rybbit-prop-","");r[u]=n.value}s("Data attribute event triggered:",i,r),p("custom_event",{eventName:i,properties:r})}break}t=t.parentElement}if(l.trackOutboundLinks&&e.target instanceof Element){let i=e.target.closest("a");if(i&&i.href&&ut(i.href)){s("Outbound link clicked:",i.href);let r={url:i.href,text:i.innerText||i.textContent||"",target:i.target||"_self"};p("outbound",{properties:r})}}}function vt(){_&&(s("Cleaning up automatic tracking listeners."),window.removeEventListener("popstate",k),window.removeEventListener("hashchange",k),document.removeEventListener("click",yt,!0),_=!1)}var Lt=-1,E=e=>{addEventListener("pageshow",t=>{t.persisted&&(Lt=t.timeStamp,e(t))},!0)},b=(e,t,i,r)=>{let n,u;return c=>{t.value>=0&&(c||r)&&(u=t.value-(n!=null?n:0),(u||n===void 0)&&(n=t.value,t.delta=u,t.rating=((a,d)=>a>d[1]?"poor":a>d[0]?"needs-improvement":"good")(t.value,i),e(t)))}},Y=e=>{requestAnimationFrame(()=>requestAnimationFrame(()=>e()))},X=()=>{let e=performance.getEntriesByType("navigation")[0];if(e&&e.responseStart>0&&e.responseStart<performance.now())return e},L=()=>{var t;let e=X();return(t=e==null?void 0:e.activationStart)!=null?t:0},h=(e,t=-1)=>{let i=X(),r="navigate";return Lt>=0?r="back-forward-cache":i&&(document.prerendering||L()>0?r="prerender":document.wasDiscarded?r="restore":i.type&&(r=i.type.replace(/_/g,"-"))),{name:e,value:t,rating:"good",delta:0,entries:[],id:`v5-${Date.now()}-${Math.floor(8999999999999*Math.random())+1e12}`,navigationType:r}},B=new WeakMap;function Z(e,t){return B.get(e)||B.set(e,new t),B.get(e)}var q=class{constructor(){y(this,"t");y(this,"i",0);y(this,"o",[])}h(t){var n;if(t.hadRecentInput)return;let i=this.o[0],r=this.o.at(-1);this.i&&i&&r&&t.startTime-r.startTime<1e3&&t.startTime-i.startTime<5e3?(this.i+=t.value,this.o.push(t)):(this.i=t.value,this.o=[t]),(n=this.t)==null||n.call(this,t)}},A=(e,t,i={})=>{try{if(PerformanceObserver.supportedEntryTypes.includes(e)){let r=new PerformanceObserver(n=>{Promise.resolve().then(()=>{t(n.getEntries())})});return r.observe(m({type:e,buffered:!0},i)),r}}catch(r){}},tt=e=>{let t=!1;return()=>{t||(e(),t=!0)}},R=-1,kt=()=>document.visibilityState!=="hidden"||document.prerendering?1/0:0,V=e=>{document.visibilityState==="hidden"&&R>-1&&(R=e.type==="visibilitychange"?e.timeStamp:0,Kt())},Tt=()=>{addEventListener("visibilitychange",V,!0),addEventListener("prerenderingchange",V,!0)},Kt=()=>{removeEventListener("visibilitychange",V,!0),removeEventListener("prerenderingchange",V,!0)},At=()=>{var e;if(R<0){let t=L(),i=document.prerendering||(e=globalThis.performance.getEntriesByType("visibility-state").filter(r=>r.name==="hidden"&&r.startTime>t)[0])==null?void 0:e.startTime;R=i!=null?i:kt(),Tt(),E(()=>{setTimeout(()=>{R=kt(),Tt()})})}return{get firstHiddenTime(){return R}}},W=e=>{document.prerendering?addEventListener("prerenderingchange",()=>e(),!0):e()},wt=[1800,3e3],et=(e,t={})=>{W(()=>{let i=At(),r,n=h("FCP"),u=A("paint",c=>{for(let a of c)a.name==="first-contentful-paint"&&(u.disconnect(),a.startTime<i.firstHiddenTime&&(n.value=Math.max(a.startTime-L(),0),n.entries.push(a),r(!0)))});u&&(r=b(e,n,wt,t.reportAllChanges),E(c=>{n=h("FCP"),r=b(e,n,wt,t.reportAllChanges),Y(()=>{n.value=performance.now()-c.timeStamp,r(!0)})}))})},St=[.1,.25],xt=(e,t={})=>{et(tt(()=>{let i,r=h("CLS",0),n=Z(t,q),u=a=>{for(let d of a)n.h(d);n.i>r.value&&(r.value=n.i,r.entries=n.o,i())},c=A("layout-shift",u);c&&(i=b(e,r,St,t.reportAllChanges),document.addEventListener("visibilitychange",()=>{document.visibilityState==="hidden"&&(u(c.takeRecords()),i(!0))}),E(()=>{n.i=0,r=h("CLS",0),i=b(e,r,St,t.reportAllChanges),Y(()=>i())}),setTimeout(i))}))},Dt=0,K=1/0,M=0,qt=e=>{for(let t of e)t.interactionId&&(K=Math.min(K,t.interactionId),M=Math.max(M,t.interactionId),Dt=M?(M-K)/7+1:0)},j,Ct=()=>{var e;return j?Dt:(e=performance.interactionCount)!=null?e:0},jt=()=>{"interactionCount"in performance||j||(j=A("event",qt,{type:"event",buffered:!0,durationThreshold:0}))},Pt=0,Q=class{constructor(){y(this,"u",[]);y(this,"l",new Map);y(this,"m");y(this,"v")}p(){Pt=Ct(),this.u.length=0,this.l.clear()}P(){let t=Math.min(this.u.length-1,Math.floor((Ct()-Pt)/50));return this.u[t]}h(t){var n,u;if((n=this.m)==null||n.call(this,t),!t.interactionId&&t.entryType!=="first-input")return;let i=this.u.at(-1),r=this.l.get(t.interactionId);if(r||this.u.length<10||t.duration>i.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((c,a)=>a.T-c.T),this.u.length>10){let c=this.u.splice(10);for(let a of c)this.l.delete(a.id)}(u=this.v)==null||u.call(this,r)}}},Ot=e=>{let t=globalThis.requestIdleCallback||setTimeout;document.visibilityState==="hidden"?e():(e=tt(e),document.addEventListener("visibilitychange",e,{once:!0}),t(()=>{e(),document.removeEventListener("visibilitychange",e)}))},Rt=[200,500],_t=(e,t={})=>{globalThis.PerformanceEventTiming&&"interactionId"in PerformanceEventTiming.prototype&&W(()=>{var a;jt();let i,r=h("INP"),n=Z(t,Q),u=d=>{Ot(()=>{for(let w of d)n.h(w);let f=n.P();f&&f.T!==r.value&&(r.value=f.T,r.entries=f.entries,i())})},c=A("event",u,{durationThreshold:(a=t.durationThreshold)!=null?a:40});i=b(e,r,Rt,t.reportAllChanges),c&&(c.observe({type:"first-input",buffered:!0}),document.addEventListener("visibilitychange",()=>{document.visibilityState==="hidden"&&(u(c.takeRecords()),i(!0))}),E(()=>{n.p(),r=h("INP"),i=b(e,r,Rt,t.reportAllChanges)}))})},G=class{constructor(){y(this,"m")}h(t){var i;(i=this.m)==null||i.call(this,t)}},Et=[2500,4e3],Mt=(e,t={})=>{W(()=>{let i=At(),r,n=h("LCP"),u=Z(t,G),c=d=>{t.reportAllChanges||(d=d.slice(-1));for(let f of d)u.h(f),f.startTime<i.firstHiddenTime&&(n.value=Math.max(f.startTime-L(),0),n.entries=[f],r())},a=A("largest-contentful-paint",c);if(a){r=b(e,n,Et,t.reportAllChanges);let d=tt(()=>{c(a.takeRecords()),a.disconnect(),r(!0)});for(let f of["keydown","click","visibilitychange"])addEventListener(f,()=>Ot(d),{capture:!0,once:!0});E(f=>{n=h("LCP"),r=b(e,n,Et,t.reportAllChanges),Y(()=>{n.value=performance.now()-f.timeStamp,r(!0)})})}})},It=[800,1800],J=e=>{document.prerendering?W(()=>J(e)):document.readyState!=="complete"?addEventListener("load",()=>J(e),!0):setTimeout(e)},Vt=(e,t={})=>{let i=h("TTFB"),r=b(e,i,It,t.reportAllChanges);J(()=>{let n=X();n&&(i.value=Math.max(n.responseStart-L(),0),i.entries=[n],r(!0),E(()=>{i=h("TTFB",0),r=b(e,i,It,t.reportAllChanges),r(!0)}))})};var U={lcp:null,cls:null,inp:null,fcp:null,ttfb:null},I=!1,H=null;function Qt(){if(I)return;Object.values(U).every(t=>t!==null)&&it()}function it(){I||(I=!0,H&&(clearTimeout(H),H=null),s("Sending web vitals data:",U),p("performance",{eventName:"web-vitals",webVitals:U}))}function x(e){if(I)return;let t=e.name.toLowerCase();U[t]=e.value,s(`Collected ${t}:`,e.value),Qt()}function Wt(){if(!l.trackWebVitals){s("Web vitals tracking is disabled.");return}s("Initializing web vitals tracking...");try{Mt(x),xt(x),_t(x),et(x),Vt(x),H=setTimeout(()=>{I||(s("Web vitals timeout reached, sending collected metrics."),it())},l.webVitalsTimeout||2e4),window.addEventListener("beforeunload",()=>{I||it()}),s("Web vitals tracking initialized successfully.")}catch(e){o("Error setting up web vitals tracking:",e)}}var T=!1,Gt={init:e=>{if(T){o("Rybbit SDK already initialized. Call init() only once.");return}dt(e)&&(T=!0,s("Config:",m({},l)),bt(),ht(),Wt())},pageview:e=>{if(!T){o("Rybbit SDK not initialized. Call rybbit.init() first.");return}p("pageview",{pathOverride:e})},event:(e,t)=>{if(!T){o("Rybbit SDK not initialized. Call rybbit.init() first.");return}if(!e){o("Event name is required and must be a string.");return}p("custom_event",{eventName:e,properties:t})},outbound:(e,t="",i="_self")=>{if(!T){o("Rybbit SDK not initialized. Call rybbit.init() first.");return}if(!e){o("Outbound link URL is required and must be a string.");return}p("outbound",{properties:{url:e,text:t,target:i}})},identify:e=>{if(!T){o("Rybbit SDK not initialized. Call rybbit.init() first.");return}gt(e)},clearUserId:()=>{if(!T){o("Rybbit SDK not initialized. Call rybbit.init() first.");return}pt()},getUserId:()=>T?mt():(o("Rybbit SDK not initialized. Call rybbit.init() first."),null),cleanup:vt},Jt=Gt;
package/dist/index.mjs CHANGED
@@ -1,7 +1,7 @@
1
1
  /*!
2
- * @rybbit/js v0.1.0
2
+ * @rybbit/js v0.2.0
3
3
  * Rybbit Web SDK
4
4
  * (c) 2025 Rybbit
5
5
  * Released under the AGPL-3.0-only license.
6
6
  */
7
- var I=Object.defineProperty;var P=Object.getOwnPropertySymbols;var A=Object.prototype.hasOwnProperty,D=Object.prototype.propertyIsEnumerable;var w=(i,t,e)=>t in i?I(i,t,{enumerable:!0,configurable:!0,writable:!0,value:e}):i[t]=e,y=(i,t)=>{for(var e in t||(t={}))A.call(t,e)&&w(i,e,t[e]);if(P)for(var e of P(t))D.call(t,e)&&w(i,e,t[e]);return i};function E(i,t){let e=null;return function(...s){let o=this;e!==null&&clearTimeout(e),e=setTimeout(()=>{e=null,i.apply(o,s)},t)}}function C(i){try{let t=window.location.hostname,e=new URL(i,window.location.href).hostname;return!!e&&e!==t}catch(t){return!1}}function K(i){try{let t="__DOUBLE_ASTERISK_TOKEN__",e="__SINGLE_ASTERISK_TOKEN__",o=i.replace(/\*\*/g,t).replace(/\*/g,e).replace(/[.+?^${}()|[\]\\]/g,"\\$&");o=o.replace(/\//g,"\\/");let c=o.replace(new RegExp(t,"g"),".*").replace(new RegExp(e,"g"),"[^/]+");return new RegExp("^"+c+"$")}catch(t){return n(`Invalid pattern: ${i}`,t),null}}function R(i,t=[]){if(!t||t.length===0)return null;for(let e of t){let s=K(e);if(s&&s.test(i))return e}return null}function a(...i){r.debug&&console.log("[Rybbit]",...i)}function n(...i){console.error("[Rybbit Error]",...i)}var l={debounce:500,autoTrackPageviews:!0,autoTrackSpaRoutes:!0,trackQuerystring:!0,trackOutboundLinks:!0,skipPatterns:[],maskPatterns:[],debug:!1},T=null,r=new Proxy({},{get:(i,t)=>{var e;return T?T[t]:(t!=="debug"&&n("Rybbit SDK accessed before initialization. Call rybbit.init() first."),(e=l[t])!=null?e:void 0)},set:()=>(n("Rybbit config is read-only after initialization."),!1)});function O(i){var p,m,b,k,f,S;if(T)return n("Rybbit SDK already initialized."),!1;if(typeof i!="object"||i===null)return n("Invalid configuration provided to rybbit.init(). Expected an object."),!1;let t=i,e=t.analyticsHost;if(!e)return n("`analyticsHost` is required in Rybbit config and must be a string."),!1;let s=e.replace(/\/$/,""),o=t.siteId;if(o==null||String(o).trim()==="")return n("`siteId` is required in Rybbit config and must be a non-empty string or number."),!1;let c=String(o),u=Array.isArray(t.skipPatterns)?t.skipPatterns:l.skipPatterns,d=Array.isArray(t.maskPatterns)?t.maskPatterns:l.maskPatterns;return T={analyticsHost:s,siteId:c,debounce:Math.max(0,(p=t.debounce)!=null?p:l.debounce),autoTrackPageviews:(m=t.autoTrackPageviews)!=null?m:l.autoTrackPageviews,autoTrackSpaRoutes:(b=t.autoTrackSpaRoutes)!=null?b:l.autoTrackSpaRoutes,trackQuerystring:(k=t.trackQuerystring)!=null?k:l.trackQuerystring,trackOutboundLinks:(f=t.trackOutboundLinks)!=null?f:l.trackOutboundLinks,debug:(S=t.debug)!=null?S:l.debug,skipPatterns:u,maskPatterns:d},!0}var $=!1;function g(i,t={}){if($){a("Tracking is paused.");return}if(!r||!r.analyticsHost||!r.siteId){n("Rybbit config not available. Ensure rybbit.init() was called successfully.");return}let{eventName:e,properties:s={},pathOverride:o}=t;if(i==="custom_event"&&!e){n("Event name is required and must be a string for custom events.");return}try{let c=new URL(window.location.href),u,d="";if(i==="pageview"&&typeof o=="string"&&o.trim()){a(`Using path override: ${o}`);try{let f=new URL(o,"http://dummybase");u=f.pathname,d=f.search||"",a(`Parsed override path: ${u}, search: ${d}`)}catch(f){n(`Invalid pathOverride format: ${o}. Using window location.`),u=c.pathname,d=r.trackQuerystring?c.search:""}}else u=c.pathname,d=r.trackQuerystring?c.search:"";if(R(u,r.skipPatterns)){a(`Skipping track for path: ${u}`);return}let p=R(u,r.maskPatterns);p&&(a(`Masking path ${u} as ${p}`),u=p,d="");let m=y(y({site_id:r.siteId,hostname:c.hostname,pathname:u,querystring:d,screenWidth:window.innerWidth,screenHeight:window.innerHeight,language:navigator.language,page_title:document.title,referrer:document.referrer||"direct",type:i},i==="custom_event"&&{event_name:e}),(i==="custom_event"||i==="outbound")&&Object.keys(s).length>0&&{properties:JSON.stringify(s)});a("Sending track event:",m);let b=JSON.stringify(m),k=`${r.analyticsHost}/track`;navigator.sendBeacon?navigator.sendBeacon(k,new Blob([b],{type:"application/json"}))||(n("sendBeacon failed, falling back to fetch."),x(k,b)):x(k,b)}catch(c){n("Error during tracking:",c)}}function x(i,t){fetch(i,{method:"POST",headers:{"Content-Type":"application/json"},body:t,mode:"cors",keepalive:!0}).catch(e=>{n("Fetch request failed:",e)})}var h,_=!1;function L(){if(_){a("Automatic tracking already set up.");return}if(!r.autoTrackPageviews){a("Automatic pageview tracking is disabled.");return}if(a("Setting up automatic tracking..."),h=r.debounce&&r.debounce>0?E(()=>g("pageview"),r.debounce):()=>g("pageview"),requestAnimationFrame(()=>{h()}),r.autoTrackSpaRoutes){a("Setting up SPA route change tracking.");let i=history.pushState,t=history.replaceState;history.pushState=function(...e){i.apply(this,e),h()},history.replaceState=function(...e){t.apply(this,e),h()},window.addEventListener("popstate",h)}else a("SPA route change tracking is disabled.");r.trackOutboundLinks?(a("Setting up outbound link tracking."),document.addEventListener("click",z,!0)):a("Outbound link tracking is disabled."),_=!0}function z(i){let e=i.target.closest("a");if(e&&e.href&&C(e.href)){a("Outbound link clicked:",e.href);let s={url:e.href,text:e.innerText||e.textContent||"",target:e.target||"_self"};g("outbound",{properties:s})}}var v=!1,H={init:i=>{if(v){n("Rybbit SDK already initialized. Call init() only once.");return}O(i)&&(v=!0,a("SDK Initialized. Version: 0.1.0"),a("Config:",y({},r)),L())},pageview:i=>{if(!v){n("Rybbit SDK not initialized. Call rybbit.init() first.");return}g("pageview",{pathOverride:i})},event:(i,t)=>{if(!v){n("Rybbit SDK not initialized. Call rybbit.init() first.");return}if(!i){n("Event name is required and must be a string.");return}g("custom_event",{eventName:i,properties:t})},trackOutboundLink:(i,t="",e="_self")=>{if(!v){n("Rybbit SDK not initialized. Call rybbit.init() first.");return}if(!i){n("Outbound link URL is required and must be a string.");return}g("outbound",{properties:{url:i,text:t,target:e}})}},nt=H;export{nt as default};
7
+ var Vt=Object.defineProperty;var ot=Object.getOwnPropertySymbols;var Wt=Object.prototype.hasOwnProperty,Ht=Object.prototype.propertyIsEnumerable;var U=(e,t,i)=>t in e?Vt(e,t,{enumerable:!0,configurable:!0,writable:!0,value:i}):e[t]=i,m=(e,t)=>{for(var i in t||(t={}))Wt.call(t,i)&&U(e,i,t[i]);if(ot)for(var i of ot(t))Ht.call(t,i)&&U(e,i,t[i]);return e};var y=(e,t,i)=>U(e,typeof t!="symbol"?t+"":t,i);function st(e,t){let i=null;return function(...r){let n=this;i!==null&&clearTimeout(i),i=setTimeout(()=>{i=null,e.apply(n,r)},t)}}function lt(e){try{let t=window.location.hostname,i=new URL(e,window.location.href).hostname;return!!i&&i!==t}catch(t){return!1}}function Ut(e){try{let t="__DOUBLE_ASTERISK_TOKEN__",i="__SINGLE_ASTERISK_TOKEN__",n=e.replace(/\*\*/g,t).replace(/\*/g,i).replace(/[.+?^${}()|[\]\\]/g,"\\$&");n=n.replace(/\//g,"\\/");let u=n.replace(new RegExp(t,"g"),".*").replace(new RegExp(i,"g"),"[^/]+");return new RegExp("^"+u+"$")}catch(t){return o(`Invalid pattern: ${e}`,t),null}}function N(e,t=[]){if(!t||t.length===0)return null;for(let i of t){let r=Ut(i);if(r&&r.test(e))return i}return null}function s(...e){l.debug&&console.log("[Rybbit]",...e)}function o(...e){l.debug&&console.error("[Rybbit Error]",...e)}function F(){let e=new URL(window.location.href),t=e.pathname;return l.trackHashRoutes&&e.hash&&(t+=e.hash),t}var g={debounce:500,autoTrackPageviews:!0,autoTrackSpaRoutes:!0,trackQuerystring:!0,trackOutboundLinks:!0,trackHashRoutes:!0,trackDataAttributes:!0,trackWebVitals:!0,webVitalsTimeout:2e4,skipPatterns:[],maskPatterns:[],debug:!1},D=null,l=new Proxy({},{get:(e,t)=>{var i;return D?D[t]:(t!=="debug"&&o("Rybbit SDK accessed before initialization. Call rybbit.init() first."),(i=g[t])!=null?i:void 0)},set:()=>(o("Rybbit config is read-only after initialization."),!1)});function ct(e){var d,f,w,C,P,S,it,rt,nt,at;if(D)return o("Rybbit SDK already initialized."),!1;if(typeof e!="object"||e===null)return o("Invalid configuration provided to rybbit.init(). Expected an object."),!1;let t=e,i=t.analyticsHost;if(!i)return o("`analyticsHost` is required in Rybbit config and must be a string."),!1;let r=i.replace(/\/$/,""),n=t.siteId;if(n==null||String(n).trim()==="")return o("`siteId` is required in Rybbit config and must be a non-empty string or number."),!1;let u=String(n),c=Array.isArray(t.skipPatterns)?t.skipPatterns:g.skipPatterns,a=Array.isArray(t.maskPatterns)?t.maskPatterns:g.maskPatterns;return D={analyticsHost:r,siteId:u,debounce:Math.max(0,(d=t.debounce)!=null?d:g.debounce),autoTrackPageviews:(f=t.autoTrackPageviews)!=null?f:g.autoTrackPageviews,autoTrackSpaRoutes:(w=t.autoTrackSpaRoutes)!=null?w:g.autoTrackSpaRoutes,trackQuerystring:(C=t.trackQuerystring)!=null?C:g.trackQuerystring,trackOutboundLinks:(P=t.trackOutboundLinks)!=null?P:g.trackOutboundLinks,trackHashRoutes:(S=t.trackHashRoutes)!=null?S:g.trackHashRoutes,trackDataAttributes:(it=t.trackDataAttributes)!=null?it:g.trackDataAttributes,trackWebVitals:(rt=t.trackWebVitals)!=null?rt:g.trackWebVitals,webVitalsTimeout:Math.max(1e3,(nt=t.webVitalsTimeout)!=null?nt:g.webVitalsTimeout),skipPatterns:c,maskPatterns:a,debug:(at=t.debug)!=null?at:g.debug},!0}var v=null,z=!1;try{let e=localStorage.getItem("rybbit-user-id");e&&(v=e),localStorage.getItem("disable-rybbit")!==null&&(z=!0)}catch(e){o("localStorage unavailable")}typeof window!="undefined"&&window.__RYBBIT_OPTOUT__&&(z=!0);function p(e,t={}){if(z){s("Opted out of tracking.");return}if(!l||!l.analyticsHost||!l.siteId){o("Rybbit config not available. Ensure rybbit.init() was called successfully.");return}let{eventName:i,properties:r,pathOverride:n,webVitals:u}=t;if((e==="custom_event"||e==="performance")&&!i){o("Event name is required and must be a string for performance or custom events.");return}try{let c=new URL(window.location.href),a,d="";if(e==="pageview"&&typeof n=="string"&&n.trim()){s(`Using path override: ${n}`);try{let S=new URL(n,"http://dummybase");a=S.pathname,d=S.search||"",s(`Parsed override path: ${a}, search: ${d}`)}catch(S){o(`Invalid pathOverride format: ${n}. Using window location.`),a=F(),d=l.trackQuerystring?c.search:""}}else a=F(),d=l.trackQuerystring?c.search:"";if(e!=="performance"&&N(a,l.skipPatterns)){s(`Skipping track for path: ${a}`);return}let f=N(a,l.maskPatterns);f&&e!=="performance"&&(s(`Masking path ${a} as ${f}`),a=f,d="");let w=m(m(m(m({site_id:l.siteId,hostname:c.hostname,pathname:a,querystring:d,screenWidth:window.innerWidth,screenHeight:window.innerHeight,language:navigator.language,page_title:document.title,referrer:document.referrer||"direct",type:e},(e==="custom_event"||e==="performance")&&{event_name:i}),(e==="custom_event"||e==="outbound")&&Object.keys(r!=null?r:{}).length>0&&{properties:JSON.stringify(r)}),e==="performance"&&u&&m({},u)),v&&{user_id:v});s("Sending track event:",w);let C=JSON.stringify(w),P=`${l.analyticsHost}/track`;navigator.sendBeacon?navigator.sendBeacon(P,new Blob([C],{type:"application/json"}))||(o("sendBeacon failed, falling back to fetch."),ut(P,C)):ut(P,C)}catch(c){o("Error during tracking:",c)}}function ut(e,t){fetch(e,{method:"POST",headers:{"Content-Type":"application/json"},body:t,mode:"cors",keepalive:!0}).catch(i=>{o("Fetch request failed:",i)})}function dt(e){if(e.trim()===""){o("User ID must be a non-empty string");return}v=e.trim();try{localStorage.setItem("rybbit-user-id",v),s("User identified:",v)}catch(t){o("Could not persist user ID to localStorage")}}function ft(){v=null;try{localStorage.removeItem("rybbit-user-id"),s("User ID cleared")}catch(e){o("Could not remove user ID from localStorage")}}function gt(){return v}var k,O=!1;function pt(){if(O){s("Automatic tracking already set up.");return}if(!l.autoTrackPageviews){s("Automatic pageview tracking is disabled.");return}if(s("Setting up automatic tracking..."),k=l.debounce&&l.debounce>0?st(()=>p("pageview"),l.debounce):()=>p("pageview"),requestAnimationFrame(()=>{k()}),l.autoTrackSpaRoutes){s("Setting up SPA route change tracking.");let e=history.pushState,t=history.replaceState;history.pushState=function(...i){e.apply(this,i),k()},history.replaceState=function(...i){t.apply(this,i),k()},window.addEventListener("popstate",k)}else s("SPA route change tracking is disabled.");l.trackHashRoutes?window.addEventListener("hashchange",k):s("Hash route tracking is disabled."),O=!0}function mt(){if(!l.trackDataAttributes){s("Data attribute tracking is disabled.");return}s("Setting up data attribute and outbound link tracking."),document.addEventListener("click",bt,!0)}function bt(e){if(!(e.target instanceof Element))return;let t=e.target;for(;t;){if(t.hasAttribute("data-rybbit-event")){let i=t.getAttribute("data-rybbit-event");if(i){let r={};for(let n of t.attributes)if(n.name.startsWith("data-rybbit-prop-")){let u=n.name.replace("data-rybbit-prop-","");r[u]=n.value}s("Data attribute event triggered:",i,r),p("custom_event",{eventName:i,properties:r})}break}t=t.parentElement}if(l.trackOutboundLinks&&e.target instanceof Element){let i=e.target.closest("a");if(i&&i.href&&lt(i.href)){s("Outbound link clicked:",i.href);let r={url:i.href,text:i.innerText||i.textContent||"",target:i.target||"_self"};p("outbound",{properties:r})}}}function ht(){O&&(s("Cleaning up automatic tracking listeners."),window.removeEventListener("popstate",k),window.removeEventListener("hashchange",k),document.removeEventListener("click",bt,!0),O=!1)}var Et=-1,E=e=>{addEventListener("pageshow",t=>{t.persisted&&(Et=t.timeStamp,e(t))},!0)},b=(e,t,i,r)=>{let n,u;return c=>{t.value>=0&&(c||r)&&(u=t.value-(n!=null?n:0),(u||n===void 0)&&(n=t.value,t.delta=u,t.rating=((a,d)=>a>d[1]?"poor":a>d[0]?"needs-improvement":"good")(t.value,i),e(t)))}},J=e=>{requestAnimationFrame(()=>requestAnimationFrame(()=>e()))},Y=()=>{let e=performance.getEntriesByType("navigation")[0];if(e&&e.responseStart>0&&e.responseStart<performance.now())return e},L=()=>{var t;let e=Y();return(t=e==null?void 0:e.activationStart)!=null?t:0},h=(e,t=-1)=>{let i=Y(),r="navigate";return Et>=0?r="back-forward-cache":i&&(document.prerendering||L()>0?r="prerender":document.wasDiscarded?r="restore":i.type&&(r=i.type.replace(/_/g,"-"))),{name:e,value:t,rating:"good",delta:0,entries:[],id:`v5-${Date.now()}-${Math.floor(8999999999999*Math.random())+1e12}`,navigationType:r}},$=new WeakMap;function X(e,t){return $.get(e)||$.set(e,new t),$.get(e)}var K=class{constructor(){y(this,"t");y(this,"i",0);y(this,"o",[])}h(t){var n;if(t.hadRecentInput)return;let i=this.o[0],r=this.o.at(-1);this.i&&i&&r&&t.startTime-r.startTime<1e3&&t.startTime-i.startTime<5e3?(this.i+=t.value,this.o.push(t)):(this.i=t.value,this.o=[t]),(n=this.t)==null||n.call(this,t)}},A=(e,t,i={})=>{try{if(PerformanceObserver.supportedEntryTypes.includes(e)){let r=new PerformanceObserver(n=>{Promise.resolve().then(()=>{t(n.getEntries())})});return r.observe(m({type:e,buffered:!0},i)),r}}catch(r){}},Z=e=>{let t=!1;return()=>{t||(e(),t=!0)}},R=-1,yt=()=>document.visibilityState!=="hidden"||document.prerendering?1/0:0,M=e=>{document.visibilityState==="hidden"&&R>-1&&(R=e.type==="visibilitychange"?e.timeStamp:0,Nt())},vt=()=>{addEventListener("visibilitychange",M,!0),addEventListener("prerenderingchange",M,!0)},Nt=()=>{removeEventListener("visibilitychange",M,!0),removeEventListener("prerenderingchange",M,!0)},It=()=>{var e;if(R<0){let t=L(),i=document.prerendering||(e=globalThis.performance.getEntriesByType("visibility-state").filter(r=>r.name==="hidden"&&r.startTime>t)[0])==null?void 0:e.startTime;R=i!=null?i:yt(),vt(),E(()=>{setTimeout(()=>{R=yt(),vt()})})}return{get firstHiddenTime(){return R}}},V=e=>{document.prerendering?addEventListener("prerenderingchange",()=>e(),!0):e()},kt=[1800,3e3],tt=(e,t={})=>{V(()=>{let i=It(),r,n=h("FCP"),u=A("paint",c=>{for(let a of c)a.name==="first-contentful-paint"&&(u.disconnect(),a.startTime<i.firstHiddenTime&&(n.value=Math.max(a.startTime-L(),0),n.entries.push(a),r(!0)))});u&&(r=b(e,n,kt,t.reportAllChanges),E(c=>{n=h("FCP"),r=b(e,n,kt,t.reportAllChanges),J(()=>{n.value=performance.now()-c.timeStamp,r(!0)})}))})},Tt=[.1,.25],Lt=(e,t={})=>{tt(Z(()=>{let i,r=h("CLS",0),n=X(t,K),u=a=>{for(let d of a)n.h(d);n.i>r.value&&(r.value=n.i,r.entries=n.o,i())},c=A("layout-shift",u);c&&(i=b(e,r,Tt,t.reportAllChanges),document.addEventListener("visibilitychange",()=>{document.visibilityState==="hidden"&&(u(c.takeRecords()),i(!0))}),E(()=>{n.i=0,r=h("CLS",0),i=b(e,r,Tt,t.reportAllChanges),J(()=>i())}),setTimeout(i))}))},At=0,B=1/0,_=0,Ft=e=>{for(let t of e)t.interactionId&&(B=Math.min(B,t.interactionId),_=Math.max(_,t.interactionId),At=_?(_-B)/7+1:0)},q,wt=()=>{var e;return q?At:(e=performance.interactionCount)!=null?e:0},zt=()=>{"interactionCount"in performance||q||(q=A("event",Ft,{type:"event",buffered:!0,durationThreshold:0}))},St=0,j=class{constructor(){y(this,"u",[]);y(this,"l",new Map);y(this,"m");y(this,"v")}p(){St=wt(),this.u.length=0,this.l.clear()}P(){let t=Math.min(this.u.length-1,Math.floor((wt()-St)/50));return this.u[t]}h(t){var n,u;if((n=this.m)==null||n.call(this,t),!t.interactionId&&t.entryType!=="first-input")return;let i=this.u.at(-1),r=this.l.get(t.interactionId);if(r||this.u.length<10||t.duration>i.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((c,a)=>a.T-c.T),this.u.length>10){let c=this.u.splice(10);for(let a of c)this.l.delete(a.id)}(u=this.v)==null||u.call(this,r)}}},xt=e=>{let t=globalThis.requestIdleCallback||setTimeout;document.visibilityState==="hidden"?e():(e=Z(e),document.addEventListener("visibilitychange",e,{once:!0}),t(()=>{e(),document.removeEventListener("visibilitychange",e)}))},Ct=[200,500],Dt=(e,t={})=>{globalThis.PerformanceEventTiming&&"interactionId"in PerformanceEventTiming.prototype&&V(()=>{var a;zt();let i,r=h("INP"),n=X(t,j),u=d=>{xt(()=>{for(let w of d)n.h(w);let f=n.P();f&&f.T!==r.value&&(r.value=f.T,r.entries=f.entries,i())})},c=A("event",u,{durationThreshold:(a=t.durationThreshold)!=null?a:40});i=b(e,r,Ct,t.reportAllChanges),c&&(c.observe({type:"first-input",buffered:!0}),document.addEventListener("visibilitychange",()=>{document.visibilityState==="hidden"&&(u(c.takeRecords()),i(!0))}),E(()=>{n.p(),r=h("INP"),i=b(e,r,Ct,t.reportAllChanges)}))})},Q=class{constructor(){y(this,"m")}h(t){var i;(i=this.m)==null||i.call(this,t)}},Pt=[2500,4e3],Ot=(e,t={})=>{V(()=>{let i=It(),r,n=h("LCP"),u=X(t,Q),c=d=>{t.reportAllChanges||(d=d.slice(-1));for(let f of d)u.h(f),f.startTime<i.firstHiddenTime&&(n.value=Math.max(f.startTime-L(),0),n.entries=[f],r())},a=A("largest-contentful-paint",c);if(a){r=b(e,n,Pt,t.reportAllChanges);let d=Z(()=>{c(a.takeRecords()),a.disconnect(),r(!0)});for(let f of["keydown","click","visibilitychange"])addEventListener(f,()=>xt(d),{capture:!0,once:!0});E(f=>{n=h("LCP"),r=b(e,n,Pt,t.reportAllChanges),J(()=>{n.value=performance.now()-f.timeStamp,r(!0)})})}})},Rt=[800,1800],G=e=>{document.prerendering?V(()=>G(e)):document.readyState!=="complete"?addEventListener("load",()=>G(e),!0):setTimeout(e)},_t=(e,t={})=>{let i=h("TTFB"),r=b(e,i,Rt,t.reportAllChanges);G(()=>{let n=Y();n&&(i.value=Math.max(n.responseStart-L(),0),i.entries=[n],r(!0),E(()=>{i=h("TTFB",0),r=b(e,i,Rt,t.reportAllChanges),r(!0)}))})};var H={lcp:null,cls:null,inp:null,fcp:null,ttfb:null},I=!1,W=null;function $t(){if(I)return;Object.values(H).every(t=>t!==null)&&et()}function et(){I||(I=!0,W&&(clearTimeout(W),W=null),s("Sending web vitals data:",H),p("performance",{eventName:"web-vitals",webVitals:H}))}function x(e){if(I)return;let t=e.name.toLowerCase();H[t]=e.value,s(`Collected ${t}:`,e.value),$t()}function Mt(){if(!l.trackWebVitals){s("Web vitals tracking is disabled.");return}s("Initializing web vitals tracking...");try{Ot(x),Lt(x),Dt(x),tt(x),_t(x),W=setTimeout(()=>{I||(s("Web vitals timeout reached, sending collected metrics."),et())},l.webVitalsTimeout||2e4),window.addEventListener("beforeunload",()=>{I||et()}),s("Web vitals tracking initialized successfully.")}catch(e){o("Error setting up web vitals tracking:",e)}}var T=!1,Bt={init:e=>{if(T){o("Rybbit SDK already initialized. Call init() only once.");return}ct(e)&&(T=!0,s("Config:",m({},l)),pt(),mt(),Mt())},pageview:e=>{if(!T){o("Rybbit SDK not initialized. Call rybbit.init() first.");return}p("pageview",{pathOverride:e})},event:(e,t)=>{if(!T){o("Rybbit SDK not initialized. Call rybbit.init() first.");return}if(!e){o("Event name is required and must be a string.");return}p("custom_event",{eventName:e,properties:t})},outbound:(e,t="",i="_self")=>{if(!T){o("Rybbit SDK not initialized. Call rybbit.init() first.");return}if(!e){o("Outbound link URL is required and must be a string.");return}p("outbound",{properties:{url:e,text:t,target:i}})},identify:e=>{if(!T){o("Rybbit SDK not initialized. Call rybbit.init() first.");return}dt(e)},clearUserId:()=>{if(!T){o("Rybbit SDK not initialized. Call rybbit.init() first.");return}ft()},getUserId:()=>T?gt():(o("Rybbit SDK not initialized. Call rybbit.init() first."),null),cleanup:ht},he=Bt;export{he as default};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rybbit/js",
3
- "version": "0.1.0",
3
+ "version": "0.2.0",
4
4
  "description": "Rybbit Web SDK",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.mjs",
@@ -19,7 +19,7 @@
19
19
  },
20
20
  "repository": {
21
21
  "type": "git",
22
- "url": "https://github.com/rybbit-io/rybbit-js.git"
22
+ "url": "git+https://github.com/rybbit-io/rybbit-js.git"
23
23
  },
24
24
  "keywords": [
25
25
  "rybbit",
@@ -37,7 +37,8 @@
37
37
  "homepage": "https://github.com/rybbit-io/rybbit-js",
38
38
  "devDependencies": {
39
39
  "@types/node": "^22.14.1",
40
- "tsup": "^8.4.0",
41
- "typescript": "^5.8.3"
40
+ "tsup": "^8.5.0",
41
+ "typescript": "^5.8.3",
42
+ "web-vitals": "^5.0.3"
42
43
  }
43
44
  }