alphana-sdk 0.4.5 → 0.5.6

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.
@@ -1 +1 @@
1
- "use strict";var AlphanaSDK=(()=>{var I=Object.defineProperty;var j=Object.getOwnPropertyDescriptor;var F=Object.getOwnPropertyNames;var V=Object.prototype.hasOwnProperty;var G=(o,t)=>{for(var e in t)I(o,e,{get:t[e],enumerable:!0})},W=(o,t,e,i)=>{if(t&&typeof t=="object"||typeof t=="function")for(let n of F(t))!V.call(o,n)&&n!==e&&I(o,n,{get:()=>t[n],enumerable:!(i=j(t,n))||i.enumerable});return o};var z=o=>W(I({},"__esModule",{value:!0}),o);var Y={};G(Y,{DEFAULT_ENDPOINT:()=>x,LogCapture:()=>g,UserTracker:()=>T,renderHeatmap:()=>_});var O="__ut_vid__";function y(){return typeof crypto!="undefined"&&typeof crypto.randomUUID=="function"?crypto.randomUUID():"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g,o=>{let t=Math.random()*16|0;return(o==="x"?t:t&3|8).toString(16)})}function D(){if(typeof localStorage=="undefined")return y();try{let o=localStorage.getItem(O);if(o)return o;let t=y();return localStorage.setItem(O,t),t}catch(o){return y()}}async function M(){try{let o=await fetch("https://ipapi.co/json/",{method:"GET",headers:{Accept:"application/json"}});if(!o.ok)return null;let t=await o.json();return t.error?null:{country:typeof t.country_code=="string"?t.country_code:"",countryName:typeof t.country_name=="string"?t.country_name:"",city:typeof t.city=="string"?t.city:void 0,region:typeof t.region=="string"?t.region:void 0,latitude:typeof t.latitude=="number"?t.latitude:void 0,longitude:typeof t.longitude=="number"?t.longitude:void 0}}catch(o){return null}}var b=class b{constructor({emit:t,sessionId:e}){this.previousPath="";this.originalPushState=null;this.originalReplaceState=null;this.pageEntryTime=0;this.handlePopState=()=>{this.handleNavigation()};this.emit=t,this.sessionId=e}init(){this.recordPageView(window.location.pathname+window.location.search),window.addEventListener("popstate",this.handlePopState),this.originalPushState=history.pushState.bind(history);let t=this.originalPushState;history.pushState=(i,n,s)=>{t(i,n,s),this.handleNavigation()},this.originalReplaceState=history.replaceState.bind(history);let e=this.originalReplaceState;history.replaceState=(i,n,s)=>{e(i,n,s),this.handleNavigation()}}destroy(){window.removeEventListener("popstate",this.handlePopState),this.originalPushState&&(history.pushState=this.originalPushState),this.originalReplaceState&&(history.replaceState=this.originalReplaceState)}handleNavigation(){let t=window.location.pathname+window.location.search;if(t!==this.previousPath){if(this.previousPath&&this.pageEntryTime>0){let e=Date.now()-this.pageEntryTime;e<=b.UTURN_THRESHOLD_MS&&this.emit({type:"uturn",data:{fromPath:this.previousPath,toPath:t,timeOnPageMs:e,timestamp:Date.now(),sessionId:this.sessionId}})}this.recordPageView(t)}}recordPageView(t){this.previousPath=t,this.pageEntryTime=Date.now(),this.emit({type:"pageview",data:{path:t,title:document.title,timestamp:Date.now(),sessionId:this.sessionId,referrer:document.referrer||void 0}}),window.dispatchEvent(new CustomEvent("tracker:navigate",{detail:{path:t,title:document.title}}))}};b.UTURN_THRESHOLD_MS=5e3;var k=b;var P=class{constructor({emit:t,sessionId:e}){this.currentPath="";this.startTime=0;this.tracking=!1;this.handleNavigate=t=>{this.stopTracking(),this.currentPath=t.detail.path,this.startTracking()};this.handleVisibilityChange=()=>{document.hidden?this.stopTracking():this.startTracking()};this.handleUnload=()=>{this.stopTracking()};this.emit=t,this.sessionId=e}init(){this.currentPath=window.location.pathname+window.location.search,this.startTracking(),window.addEventListener("tracker:navigate",this.handleNavigate),document.addEventListener("visibilitychange",this.handleVisibilityChange),window.addEventListener("beforeunload",this.handleUnload),window.addEventListener("pagehide",this.handleUnload)}destroy(){this.stopTracking(),window.removeEventListener("tracker:navigate",this.handleNavigate),document.removeEventListener("visibilitychange",this.handleVisibilityChange),window.removeEventListener("beforeunload",this.handleUnload),window.removeEventListener("pagehide",this.handleUnload)}startTracking(){this.startTime=Date.now(),this.tracking=!0}stopTracking(){if(!this.tracking||!this.currentPath)return;let t=Date.now()-this.startTime;if(t<100){this.tracking=!1;return}this.emit({type:"timespent",data:{path:this.currentPath,duration:t,sessionId:this.sessionId,timestamp:Date.now()}}),this.tracking=!1}};function R(o,t){let e=0;return(...i)=>{let n=Date.now();n-e>=t&&(e=n,o(...i))}}var h=class h{constructor({emit:t,sessionId:e,sampleRate:i=.3,maxPoints:n=2e3,allowedPaths:s}){this.currentPath="";this.pointCounts={};this.recentClicks=[];this.handleMouseMove=t=>{if(Math.random()>this.sampleRate)return;let e=document.documentElement.scrollWidth,i=document.documentElement.scrollHeight,n=t.clientY+window.scrollY;this.recordPoint({x:t.clientX,y:n,xPct:e>0?t.clientX/e*100:0,yPct:i>0?n/i*100:0,pw:e,ph:i,type:"move"})};this.handleClick=t=>{if(Date.now()-this.lastTouchTime<500)return;let e=document.documentElement.scrollWidth,i=document.documentElement.scrollHeight,n=t.clientY+window.scrollY,s=this.getClickTarget(t);this.recordPoint({x:t.clientX,y:n,xPct:e>0?t.clientX/e*100:0,yPct:i>0?n/i*100:0,pw:e,ph:i,type:"click",...s?{target:s}:{}}),this.checkRageClick(t.clientX,n,this.currentPath)};this.lastTouchTime=0;this.handleTouchEnd=t=>{let e=t.changedTouches[0];if(!e)return;let i=document.documentElement.scrollWidth,n=document.documentElement.scrollHeight,s=e.clientY+window.scrollY;this.lastTouchTime=Date.now(),this.recordPoint({x:e.clientX,y:s,xPct:i>0?e.clientX/i*100:0,yPct:n>0?s/n*100:0,pw:i,ph:n,type:"click"}),this.checkRageClick(e.clientX,s,this.currentPath)};this.handleScroll=()=>{if(Math.random()>this.sampleRate)return;let t=document.documentElement.scrollWidth,e=document.documentElement.scrollHeight,i=window.innerWidth,n=window.scrollX,s=window.scrollY,r=n+i/2;this.recordPoint({x:i/2,y:s,xPct:t>0?r/t*100:50,yPct:e>0?s/e*100:0,pw:t,ph:e,type:"scroll"})};this.handleNavigate=t=>{this.currentPath=t.detail.path};this.emit=t,this.sessionId=e,this.sampleRate=i,this.maxPoints=n,this.allowedPaths=s&&s.length>0?new Set(s):null,this.throttledMouseMove=R(this.handleMouseMove,50),this.throttledScroll=R(this.handleScroll,100)}init(){this.currentPath=window.location.pathname+window.location.search,document.addEventListener("mousemove",this.throttledMouseMove),document.addEventListener("click",this.handleClick),document.addEventListener("touchend",this.handleTouchEnd,{passive:!0}),window.addEventListener("scroll",this.throttledScroll,{passive:!0}),window.addEventListener("tracker:navigate",this.handleNavigate)}destroy(){document.removeEventListener("mousemove",this.throttledMouseMove),document.removeEventListener("click",this.handleClick),document.removeEventListener("touchend",this.handleTouchEnd),window.removeEventListener("scroll",this.throttledScroll),window.removeEventListener("tracker:navigate",this.handleNavigate)}canRecord(){var t;return this.allowedPaths!==null&&!this.allowedPaths.has(this.currentPath)?!1:((t=this.pointCounts[this.currentPath])!=null?t:0)<this.maxPoints}recordPoint(t){var e;this.canRecord()&&(this.pointCounts[this.currentPath]=((e=this.pointCounts[this.currentPath])!=null?e:0)+1,this.emit({type:"heatmap",data:{...t,path:this.currentPath,timestamp:Date.now()}}))}getClickTarget(t){var n,s,r,a;let e=t.target;return e&&(e.getAttribute("aria-label")||((n=e.closest("[aria-label]"))==null?void 0:n.getAttribute("aria-label"))||e.getAttribute("data-track-label")||e.getAttribute("id")||(e instanceof HTMLButtonElement||e instanceof HTMLAnchorElement?(s=e.innerText)==null?void 0:s.trim().slice(0,60):(a=(r=e.closest("button, a"))==null?void 0:r.textContent)==null?void 0:a.trim().slice(0,60)))||void 0}checkRageClick(t,e,i){let n=Date.now();this.recentClicks=this.recentClicks.filter(r=>n-r.t<h.RAGE_WINDOW_MS),this.recentClicks.push({x:t,y:e,t:n});let s=this.recentClicks.filter(r=>Math.hypot(r.x-t,r.y-e)<=h.RAGE_RADIUS_PX);s.length>=h.RAGE_THRESHOLD&&(this.emit({type:"rageclik",data:{path:i,x:t,y:e,count:s.length,timestamp:n,sessionId:this.sessionId}}),this.recentClicks=[])}};h.RAGE_THRESHOLD=3,h.RAGE_WINDOW_MS=1e3,h.RAGE_RADIUS_PX=50;var S=h;var g=class{constructor(t){this.prevOnError=null;this.prevOnUnhandledRejection=null;this.initialized=!1;try{let e=new URL(t.endpoint),i=e.pathname.replace(/\/$/,"").split("/");i.pop(),e.pathname=i.join("/")||"/",this.endpoint=e.toString().replace(/\/$/,"")}catch(e){this.endpoint=t.endpoint}this.sessionId=t.sessionId,this.appId=t.appId,this.authHeaders=t.secretKey?{Authorization:`Bearer ${t.secretKey}`}:{}}init(){typeof window=="undefined"||this.initialized||(this.origInfo=console.info.bind(console),this.origWarn=console.warn.bind(console),this.origError=console.error.bind(console),console.info=(...t)=>{this.origInfo(...t),this.send("info",this.format(t))},console.warn=(...t)=>{this.origWarn(...t),this.send("warn",this.format(t))},console.error=(...t)=>{this.origError(...t);let[e]=t,i=e instanceof Error?e.stack:void 0;this.send("error",this.format(t),{stack:i})},this.prevOnError=window.onerror,window.onerror=(t,e,i,n,s)=>(this.send("error",String(t),{stack:s==null?void 0:s.stack,meta:{src:e,line:i,col:n}}),typeof this.prevOnError=="function"?this.prevOnError(t,e,i,n,s):!1),this.prevOnUnhandledRejection=t=>{let e=t.reason,i=e instanceof Error?e.message:String(e!=null?e:"Unhandled promise rejection");this.send("error",i,{stack:e instanceof Error?e.stack:void 0})},window.addEventListener("unhandledrejection",this.prevOnUnhandledRejection),this.initialized=!0)}destroy(){this.initialized&&(console.info=this.origInfo,console.warn=this.origWarn,console.error=this.origError,window.onerror=this.prevOnError,this.prevOnUnhandledRejection&&window.removeEventListener("unhandledrejection",this.prevOnUnhandledRejection),this.initialized=!1)}capture(t,e,i){this.send(t,e,i)}format(t){return t.map(e=>{if(e instanceof Error)return e.message;if(typeof e=="object")try{return JSON.stringify(e)}catch(i){return String(e)}return String(e)}).join(" ")}send(t,e,i){let n={sessionId:this.sessionId,...this.appId?{appId:this.appId}:{},level:t,message:e,url:typeof window!="undefined"?window.location.href:void 0,stack:i==null?void 0:i.stack,meta:i==null?void 0:i.meta,timestamp:Date.now()},s=`${this.endpoint}/logs/ingest`,r=JSON.stringify(n);fetch(s,{method:"POST",headers:{"Content-Type":"application/json",...this.authHeaders},body:r,keepalive:!0}).catch(a=>{this.origError&&this.origError("[user-tracker] Failed to send log:",a)})}};var x="https://api.alphana.ir/api/events",K={endpoint:x,trackNavigation:!0,trackTime:!0,trackHeatmap:!0,trackLogs:!0,trackSnapshots:!0,mouseSampleRate:.3,maxHeatmapPoints:2e3,batchSize:20,flushInterval:5e3},T=class{constructor(t={}){this.initialized=!1;this.subscribers=new Set;this.queue=[];this.flushTimer=null;this.heartbeatTimer=null;this.location=null;this.handleVisibilityChange=()=>{document.visibilityState==="hidden"&&(this.queue.length>0&&this.flushBeacon(),this.sendDeactivate())};this.handlePageHide=()=>{this.queue.length>0&&this.flushBeacon(),this.sendDeactivate()};this.handleNavigate=t=>{};var e;this.cfg={...K,...t};try{new URL(this.cfg.endpoint)}catch(i){throw new Error(`[alpha-tracker] Invalid endpoint URL: "${this.cfg.endpoint}"`)}this.session={id:(e=t.sessionId)!=null?e:y(),visitorId:D(),startedAt:Date.now(),pageViews:[],timeSpent:{},heatmap:{}}}init(){if(typeof window=="undefined"||this.initialized)return this;let t=this.emit.bind(this),{id:e}=this.session;return this.cfg.trackNavigation&&(this.navigation=new k({emit:t,sessionId:e}),this.navigation.init()),this.cfg.trackTime&&(this.time=new P({emit:t,sessionId:e}),this.time.init()),this.cfg.trackHeatmap&&(this.heatmap=new S({emit:t,sessionId:e,sampleRate:this.cfg.mouseSampleRate,maxPoints:this.cfg.maxHeatmapPoints,allowedPaths:this.cfg.heatmapPages}),this.heatmap.init()),this.cfg.endpoint&&(this.flushTimer=setInterval(()=>{this.queue.length>0&&this.flush()},this.cfg.flushInterval),M().then(i=>{this.location=i,i&&(this.session.location=i)}),window.addEventListener("visibilitychange",this.handleVisibilityChange),window.addEventListener("pagehide",this.handlePageHide),this.heartbeatTimer=setInterval(()=>{document.visibilityState!=="hidden"&&this.sendHeartbeat()},3e4),this.cfg.trackLogs&&(this.logCapture=new g({endpoint:this.cfg.endpoint,sessionId:this.session.id,secretKey:this.cfg.secretKey,appId:this.cfg.appId}),this.logCapture.init())),this.initialized=!0,this}destroy(){var t,e,i,n;this.flushTimer!==null&&(clearInterval(this.flushTimer),this.flushTimer=null),this.heartbeatTimer!==null&&(clearInterval(this.heartbeatTimer),this.heartbeatTimer=null),typeof window!="undefined"&&(window.removeEventListener("visibilitychange",this.handleVisibilityChange),window.removeEventListener("pagehide",this.handlePageHide)),(t=this.navigation)==null||t.destroy(),(e=this.time)==null||e.destroy(),(i=this.heatmap)==null||i.destroy(),(n=this.logCapture)==null||n.destroy(),typeof window!="undefined"&&window.removeEventListener("tracker:navigate",this.handleNavigate),this.queue.length>0&&this.cfg.endpoint&&this.flushBeacon(),this.initialized=!1}async sendHeartbeat(){if(!this.cfg.endpoint)return;let t=`${this.cfg.endpoint}/heartbeat`,e=this.cfg.secretKey?{Authorization:`Bearer ${this.cfg.secretKey}`}:{},i=JSON.stringify({sessionId:this.session.id,visitorId:this.session.visitorId,path:typeof window!="undefined"?window.location.pathname:"/",active:!0,...this.cfg.appId?{appId:this.cfg.appId}:{},...this.location?{location:this.location}:{}});try{await fetch(t,{method:"POST",headers:{"Content-Type":"application/json",...e},body:i,keepalive:!0})}catch(n){}}sendDeactivate(){if(!this.cfg.endpoint)return;let t=`${this.cfg.endpoint}/heartbeat`,e=this.cfg.secretKey?{Authorization:`Bearer ${this.cfg.secretKey}`}:{},i=JSON.stringify({sessionId:this.session.id,path:typeof window!="undefined"?window.location.pathname:"/",active:!1,...this.cfg.appId?{appId:this.cfg.appId}:{}});typeof navigator!="undefined"&&navigator.sendBeacon?navigator.sendBeacon(t,new Blob([i],{type:"application/json"})):fetch(t,{method:"POST",headers:{"Content-Type":"application/json",...e},body:i,keepalive:!0}).catch(()=>{})}emit(t){var e,i,n;switch(t.type){case"pageview":this.session.pageViews.push(t.data);break;case"timespent":{let s=(e=this.session.timeSpent[t.data.path])!=null?e:0;this.session.timeSpent[t.data.path]=s+t.data.duration;break}case"heatmap":{let s=t.data.path;this.session.heatmap[s]||(this.session.heatmap[s]=[]);let r=this.session.heatmap[s];r.length<this.cfg.maxHeatmapPoints&&r.push(t.data);break}case"rageclik":case"uturn":break}this.subscribers.forEach(s=>s(t)),(n=(i=this.cfg).onEvent)==null||n.call(i,t),this.cfg.endpoint&&(this.queue.push(t),this.queue.length>=this.cfg.batchSize&&this.flush())}subscribe(t){return this.subscribers.add(t),()=>this.subscribers.delete(t)}trackPageView(t){let e=t!=null?t:typeof window!="undefined"?window.location.pathname+window.location.search:"/";this.emit({type:"pageview",data:{path:e,title:typeof document!="undefined"?document.title:"",timestamp:Date.now(),sessionId:this.session.id,referrer:typeof document!="undefined"&&document.referrer||void 0}}),typeof window!="undefined"&&window.dispatchEvent(new CustomEvent("tracker:navigate",{detail:{path:e,title:document.title}}))}getSession(){return this.session}getPageViews(){return[...this.session.pageViews]}getTimeSpent(){return{...this.session.timeSpent}}getHeatmapData(t){var e;return t!==void 0?[...(e=this.session.heatmap[t])!=null?e:[]]:Object.entries(this.session.heatmap).reduce((i,[n,s])=>(i[n]=[...s],i),{})}async flush(){if(this.queue.length===0)return;let t=this.queue.splice(0);await this.sendBatch(t)}flushBeacon(){if(this.queue.length===0)return;let t=this.queue.splice(0),e=`${this.cfg.endpoint}/batch`,i=new Blob([this.buildBatchBody(t)],{type:"application/json"});typeof navigator!="undefined"&&navigator.sendBeacon?navigator.sendBeacon(e,i):this.sendBatch(t)}buildBatchBody(t){var e;return JSON.stringify({...this.cfg.appId?{appId:this.cfg.appId}:{},visitorId:this.session.visitorId,location:(e=this.location)!=null?e:void 0,events:t.map(i=>({sessionId:this.session.id,type:i.type,data:i.data}))})}async sendBatch(t){let e=`${this.cfg.endpoint}/batch`,i=this.cfg.secretKey?{Authorization:`Bearer ${this.cfg.secretKey}`}:{};try{await fetch(e,{method:"POST",headers:{"Content-Type":"application/json",...i},body:this.buildBatchBody(t),keepalive:!0})}catch(n){}}};function X(){let o=[[0,0,255],[0,255,255],[0,255,0],[255,255,0],[255,128,0],[255,0,0]],t=[],e=51;for(let i=0;i<o.length-1;i++){let[n,s,r]=o[i],[a,l,m]=o[i+1];for(let d=0;d<e;d++){let v=d/e;t.push([Math.round(n+(a-n)*v),Math.round(s+(l-s)*v),Math.round(r+(m-r)*v)])}}return t}var N=X();function _(o,t,e={}){let{radius:i=25,maxOpacity:n=.85,minOpacity:s=0}=e,r=o.getContext("2d");if(!r)return;let{width:a,height:l}=o;if(r.clearRect(0,0,a,l),t.length===0)return;let m=document.createElement("canvas");m.width=a,m.height=l;let d=m.getContext("2d");if(!d)return;for(let c of t){let p=c.xPct/100*a,u=c.yPct/100*l,E=c.type==="click"?i*1.6:i,f=d.createRadialGradient(p,u,0,p,u,E);f.addColorStop(0,"rgba(0,0,0,0.15)"),f.addColorStop(1,"rgba(0,0,0,0)"),d.fillStyle=f,d.beginPath(),d.arc(p,u,E,0,Math.PI*2),d.fill()}let v=d.getImageData(0,0,a,l),L=r.createImageData(a,l),C=v.data,w=L.data,H=N.length-1;for(let c=0;c<C.length;c+=4){let p=C[c+3];if(p===0)continue;let u=p/255,E=Math.min(Math.floor(u*H),H),[f,A,B]=N[E],U=s+u*(n-s);w[c]=f,w[c+1]=A,w[c+2]=B,w[c+3]=Math.round(U*255)}r.putImageData(L,0,0)}return z(Y);})();
1
+ "use strict";var AlphanaSDK=(()=>{var I=Object.defineProperty;var U=Object.getOwnPropertyDescriptor;var j=Object.getOwnPropertyNames;var V=Object.prototype.hasOwnProperty;var G=(r,t)=>{for(var e in t)I(r,e,{get:t[e],enumerable:!0})},z=(r,t,e,i)=>{if(t&&typeof t=="object"||typeof t=="function")for(let n of j(t))!V.call(r,n)&&n!==e&&I(r,n,{get:()=>t[n],enumerable:!(i=U(t,n))||i.enumerable});return r};var W=r=>z(I({},"__esModule",{value:!0}),r);var X={};G(X,{DEFAULT_ENDPOINT:()=>x,LogCapture:()=>g,UserTracker:()=>T,renderHeatmap:()=>F});var O="__ut_vid__";function y(){return typeof crypto!="undefined"&&typeof crypto.randomUUID=="function"?crypto.randomUUID():"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g,r=>{let t=Math.random()*16|0;return(r==="x"?t:t&3|8).toString(16)})}function D(){if(typeof localStorage=="undefined")return y();try{let r=localStorage.getItem(O);if(r)return r;let t=y();return localStorage.setItem(O,t),t}catch(r){return y()}}async function M(){try{let r=await fetch("https://ipapi.co/json/",{method:"GET",headers:{Accept:"application/json"}});if(!r.ok)return null;let t=await r.json();return t.error?null:{country:typeof t.country_code=="string"?t.country_code:"",countryName:typeof t.country_name=="string"?t.country_name:"",city:typeof t.city=="string"?t.city:void 0,region:typeof t.region=="string"?t.region:void 0,latitude:typeof t.latitude=="number"?t.latitude:void 0,longitude:typeof t.longitude=="number"?t.longitude:void 0}}catch(r){return null}}var P=class P{constructor({emit:t,sessionId:e}){this.previousPath="";this.originalPushState=null;this.originalReplaceState=null;this.pageEntryTime=0;this.handlePopState=()=>{this.handleNavigation()};this.emit=t,this.sessionId=e}init(){this.recordPageView(window.location.pathname+window.location.search),window.addEventListener("popstate",this.handlePopState),this.originalPushState=history.pushState.bind(history);let t=this.originalPushState;history.pushState=(i,n,s)=>{t(i,n,s),this.handleNavigation()},this.originalReplaceState=history.replaceState.bind(history);let e=this.originalReplaceState;history.replaceState=(i,n,s)=>{e(i,n,s),this.handleNavigation()}}destroy(){window.removeEventListener("popstate",this.handlePopState),this.originalPushState&&(history.pushState=this.originalPushState),this.originalReplaceState&&(history.replaceState=this.originalReplaceState)}handleNavigation(){let t=window.location.pathname+window.location.search;if(t!==this.previousPath){if(this.previousPath&&this.pageEntryTime>0){let e=Date.now()-this.pageEntryTime;e<=P.UTURN_THRESHOLD_MS&&this.emit({type:"uturn",data:{fromPath:this.previousPath,toPath:t,timeOnPageMs:e,timestamp:Date.now(),sessionId:this.sessionId}})}this.recordPageView(t)}}recordPageView(t){this.previousPath=t,this.pageEntryTime=Date.now(),this.emit({type:"pageview",data:{path:t,title:document.title,timestamp:Date.now(),sessionId:this.sessionId,referrer:document.referrer||void 0}}),window.dispatchEvent(new CustomEvent("tracker:navigate",{detail:{path:t,title:document.title}}))}};P.UTURN_THRESHOLD_MS=5e3;var E=P;var k=class{constructor({emit:t,sessionId:e}){this.currentPath="";this.startTime=0;this.tracking=!1;this.handleNavigate=t=>{this.stopTracking(),this.currentPath=t.detail.path,this.startTracking()};this.handleVisibilityChange=()=>{document.hidden?this.stopTracking():this.startTracking()};this.handleUnload=()=>{this.stopTracking()};this.emit=t,this.sessionId=e}init(){this.currentPath=window.location.pathname+window.location.search,this.startTracking(),window.addEventListener("tracker:navigate",this.handleNavigate),document.addEventListener("visibilitychange",this.handleVisibilityChange),window.addEventListener("beforeunload",this.handleUnload),window.addEventListener("pagehide",this.handleUnload)}destroy(){this.stopTracking(),window.removeEventListener("tracker:navigate",this.handleNavigate),document.removeEventListener("visibilitychange",this.handleVisibilityChange),window.removeEventListener("beforeunload",this.handleUnload),window.removeEventListener("pagehide",this.handleUnload)}startTracking(){this.startTime=Date.now(),this.tracking=!0}stopTracking(){if(!this.tracking||!this.currentPath)return;let t=Date.now()-this.startTime;if(t<100){this.tracking=!1;return}this.emit({type:"timespent",data:{path:this.currentPath,duration:t,sessionId:this.sessionId,timestamp:Date.now()}}),this.tracking=!1}};function R(r,t){let e=0;return(...i)=>{let n=Date.now();n-e>=t&&(e=n,r(...i))}}var h=class h{constructor({emit:t,sessionId:e,sampleRate:i=.3,maxPoints:n=2e3,allowedPaths:s}){this.currentPath="";this.pointCounts={};this.recentClicks=[];this.handleMouseMove=t=>{if(Math.random()>this.sampleRate)return;let e=document.documentElement.scrollWidth,i=document.documentElement.scrollHeight,n=t.clientY+window.scrollY;this.recordPoint({x:t.clientX,y:n,xPct:e>0?t.clientX/e*100:0,yPct:i>0?n/i*100:0,pw:e,ph:i,type:"move"})};this.handleClick=t=>{if(Date.now()-this.lastTouchTime<500)return;let e=document.documentElement.scrollWidth,i=document.documentElement.scrollHeight,n=t.clientY+window.scrollY,s=this.getClickTarget(t);this.recordPoint({x:t.clientX,y:n,xPct:e>0?t.clientX/e*100:0,yPct:i>0?n/i*100:0,pw:e,ph:i,type:"click",...s?{target:s}:{}}),this.checkRageClick(t.clientX,n,this.currentPath)};this.lastTouchTime=0;this.handleTouchEnd=t=>{let e=t.changedTouches[0];if(!e)return;let i=document.documentElement.scrollWidth,n=document.documentElement.scrollHeight,s=e.clientY+window.scrollY;this.lastTouchTime=Date.now(),this.recordPoint({x:e.clientX,y:s,xPct:i>0?e.clientX/i*100:0,yPct:n>0?s/n*100:0,pw:i,ph:n,type:"click"}),this.checkRageClick(e.clientX,s,this.currentPath)};this.handleScroll=()=>{if(Math.random()>this.sampleRate)return;let t=document.documentElement.scrollWidth,e=document.documentElement.scrollHeight,i=window.innerWidth,n=window.scrollX,s=window.scrollY,o=n+i/2;this.recordPoint({x:i/2,y:s,xPct:t>0?o/t*100:50,yPct:e>0?s/e*100:0,pw:t,ph:e,type:"scroll"})};this.handleNavigate=t=>{this.currentPath=t.detail.path};this.emit=t,this.sessionId=e,this.sampleRate=i,this.maxPoints=n,this.allowedPaths=s&&s.length>0?new Set(s):null,this.throttledMouseMove=R(this.handleMouseMove,50),this.throttledScroll=R(this.handleScroll,100)}init(){this.currentPath=window.location.pathname+window.location.search,document.addEventListener("mousemove",this.throttledMouseMove),document.addEventListener("click",this.handleClick),document.addEventListener("touchend",this.handleTouchEnd,{passive:!0}),window.addEventListener("scroll",this.throttledScroll,{passive:!0}),window.addEventListener("tracker:navigate",this.handleNavigate)}destroy(){document.removeEventListener("mousemove",this.throttledMouseMove),document.removeEventListener("click",this.handleClick),document.removeEventListener("touchend",this.handleTouchEnd),window.removeEventListener("scroll",this.throttledScroll),window.removeEventListener("tracker:navigate",this.handleNavigate)}canRecord(){var t;return this.allowedPaths!==null&&!this.allowedPaths.has(this.currentPath)?!1:((t=this.pointCounts[this.currentPath])!=null?t:0)<this.maxPoints}recordPoint(t){var e;this.canRecord()&&(this.pointCounts[this.currentPath]=((e=this.pointCounts[this.currentPath])!=null?e:0)+1,this.emit({type:"heatmap",data:{...t,path:this.currentPath,timestamp:Date.now()}}))}getClickTarget(t){var n,s,o,a;let e=t.target;return e&&(e.getAttribute("aria-label")||((n=e.closest("[aria-label]"))==null?void 0:n.getAttribute("aria-label"))||e.getAttribute("data-track-label")||e.getAttribute("id")||(e instanceof HTMLButtonElement||e instanceof HTMLAnchorElement?(s=e.innerText)==null?void 0:s.trim().slice(0,60):(a=(o=e.closest("button, a"))==null?void 0:o.textContent)==null?void 0:a.trim().slice(0,60)))||void 0}checkRageClick(t,e,i){let n=Date.now();this.recentClicks=this.recentClicks.filter(o=>n-o.t<h.RAGE_WINDOW_MS),this.recentClicks.push({x:t,y:e,t:n});let s=this.recentClicks.filter(o=>Math.hypot(o.x-t,o.y-e)<=h.RAGE_RADIUS_PX);s.length>=h.RAGE_THRESHOLD&&(this.emit({type:"rageclik",data:{path:i,x:t,y:e,count:s.length,timestamp:n,sessionId:this.sessionId}}),this.recentClicks=[])}};h.RAGE_THRESHOLD=3,h.RAGE_WINDOW_MS=1e3,h.RAGE_RADIUS_PX=50;var S=h;var g=class{constructor(t){this.prevOnError=null;this.prevOnUnhandledRejection=null;this.initialized=!1;try{let e=new URL(t.endpoint),i=e.pathname.replace(/\/$/,"").split("/");i.pop(),e.pathname=i.join("/")||"/",this.endpoint=e.toString().replace(/\/$/,"")}catch(e){this.endpoint=t.endpoint}this.sessionId=t.sessionId,this.appId=t.appId,this.authHeaders=t.secretKey?{Authorization:`Bearer ${t.secretKey}`}:{}}init(){typeof window=="undefined"||this.initialized||(this.origInfo=console.info.bind(console),this.origWarn=console.warn.bind(console),this.origError=console.error.bind(console),console.info=(...t)=>{this.origInfo(...t),this.send("info",this.format(t))},console.warn=(...t)=>{this.origWarn(...t),this.send("warn",this.format(t))},console.error=(...t)=>{this.origError(...t);let[e]=t,i=e instanceof Error?e.stack:void 0;this.send("error",this.format(t),{stack:i})},this.prevOnError=window.onerror,window.onerror=(t,e,i,n,s)=>(this.send("error",String(t),{stack:s==null?void 0:s.stack,meta:{src:e,line:i,col:n}}),typeof this.prevOnError=="function"?this.prevOnError(t,e,i,n,s):!1),this.prevOnUnhandledRejection=t=>{let e=t.reason,i=e instanceof Error?e.message:String(e!=null?e:"Unhandled promise rejection");this.send("error",i,{stack:e instanceof Error?e.stack:void 0})},window.addEventListener("unhandledrejection",this.prevOnUnhandledRejection),this.initialized=!0)}destroy(){this.initialized&&(console.info=this.origInfo,console.warn=this.origWarn,console.error=this.origError,window.onerror=this.prevOnError,this.prevOnUnhandledRejection&&window.removeEventListener("unhandledrejection",this.prevOnUnhandledRejection),this.initialized=!1)}capture(t,e,i){this.send(t,e,i)}format(t){return t.map(e=>{if(e instanceof Error)return e.message;if(typeof e=="object")try{return JSON.stringify(e)}catch(i){return String(e)}return String(e)}).join(" ")}send(t,e,i){let n={sessionId:this.sessionId,...this.appId?{appId:this.appId}:{},level:t,message:e,url:typeof window!="undefined"?window.location.href:void 0,stack:i==null?void 0:i.stack,meta:i==null?void 0:i.meta,timestamp:Date.now()},s=`${this.endpoint}/logs/ingest`,o=JSON.stringify(n);fetch(s,{method:"POST",headers:{"Content-Type":"application/json",...this.authHeaders},body:o,keepalive:!0}).catch(a=>{this.origError&&this.origError("[user-tracker] Failed to send log:",a)})}};var x="https://api.alphana.ir/api/events",K={endpoint:x,trackNavigation:!0,trackTime:!0,trackHeatmap:!0,trackLogs:!0,mouseSampleRate:.3,maxHeatmapPoints:2e3,batchSize:20,flushInterval:5e3},T=class{constructor(t={}){this.initialized=!1;this.subscribers=new Set;this.queue=[];this.flushTimer=null;this.heartbeatTimer=null;this.location=null;this.userProperties={};this.flags={};this.flagSubscribers=new Set;this.handleVisibilityChange=()=>{document.visibilityState==="hidden"&&(this.queue.length>0&&this.flushBeacon(),this.sendDeactivate())};this.handlePageHide=()=>{this.queue.length>0&&this.flushBeacon(),this.sendDeactivate()};this.handleNavigate=t=>{};var e;this.cfg={...K,...t};try{new URL(this.cfg.endpoint)}catch(i){throw new Error(`[alpha-tracker] Invalid endpoint URL: "${this.cfg.endpoint}"`)}this.session={id:(e=t.sessionId)!=null?e:y(),visitorId:D(),startedAt:Date.now(),pageViews:[],timeSpent:{},heatmap:{}}}init(){if(typeof window=="undefined"||this.initialized)return this;let t=this.emit.bind(this),{id:e}=this.session;return this.cfg.trackNavigation&&(this.navigation=new E({emit:t,sessionId:e}),this.navigation.init()),this.cfg.trackTime&&(this.time=new k({emit:t,sessionId:e}),this.time.init()),this.cfg.trackHeatmap&&(this.heatmap=new S({emit:t,sessionId:e,sampleRate:this.cfg.mouseSampleRate,maxPoints:this.cfg.maxHeatmapPoints,allowedPaths:this.cfg.heatmapPages}),this.heatmap.init()),this.cfg.endpoint&&(this.flushTimer=setInterval(()=>{this.queue.length>0&&this.flush()},this.cfg.flushInterval),M().then(i=>{this.location=i,i&&(this.session.location=i)}),window.addEventListener("visibilitychange",this.handleVisibilityChange),window.addEventListener("pagehide",this.handlePageHide),this.heartbeatTimer=setInterval(()=>{document.visibilityState!=="hidden"&&this.sendHeartbeat()},3e4),this.cfg.trackLogs&&(this.logCapture=new g({endpoint:this.cfg.endpoint,sessionId:this.session.id,secretKey:this.cfg.secretKey,appId:this.cfg.appId}),this.logCapture.init())),this.initialized=!0,this.fetchFlags(),this}destroy(){var t,e,i,n;this.flushTimer!==null&&(clearInterval(this.flushTimer),this.flushTimer=null),this.heartbeatTimer!==null&&(clearInterval(this.heartbeatTimer),this.heartbeatTimer=null),typeof window!="undefined"&&(window.removeEventListener("visibilitychange",this.handleVisibilityChange),window.removeEventListener("pagehide",this.handlePageHide)),(t=this.navigation)==null||t.destroy(),(e=this.time)==null||e.destroy(),(i=this.heatmap)==null||i.destroy(),(n=this.logCapture)==null||n.destroy(),typeof window!="undefined"&&window.removeEventListener("tracker:navigate",this.handleNavigate),this.queue.length>0&&this.cfg.endpoint&&this.flushBeacon(),this.initialized=!1}async sendHeartbeat(){if(!this.cfg.endpoint)return;let t=`${this.cfg.endpoint}/heartbeat`,e=this.cfg.secretKey?{Authorization:`Bearer ${this.cfg.secretKey}`}:{},i=JSON.stringify({sessionId:this.session.id,visitorId:this.session.visitorId,path:typeof window!="undefined"?window.location.pathname:"/",active:!0,...this.cfg.appId?{appId:this.cfg.appId}:{},...this.location?{location:this.location}:{}});try{await fetch(t,{method:"POST",headers:{"Content-Type":"application/json",...e},body:i,keepalive:!0})}catch(n){}}sendDeactivate(){if(!this.cfg.endpoint)return;let t=`${this.cfg.endpoint}/heartbeat`,e=this.cfg.secretKey?{Authorization:`Bearer ${this.cfg.secretKey}`}:{},i=JSON.stringify({sessionId:this.session.id,path:typeof window!="undefined"?window.location.pathname:"/",active:!1,...this.cfg.appId?{appId:this.cfg.appId}:{}});typeof navigator!="undefined"&&navigator.sendBeacon?navigator.sendBeacon(t,new Blob([i],{type:"application/json"})):fetch(t,{method:"POST",headers:{"Content-Type":"application/json",...e},body:i,keepalive:!0}).catch(()=>{})}emit(t){var e,i,n;switch(t.type){case"pageview":this.session.pageViews.push(t.data);break;case"timespent":{let s=(e=this.session.timeSpent[t.data.path])!=null?e:0;this.session.timeSpent[t.data.path]=s+t.data.duration;break}case"heatmap":{let s=t.data.path;this.session.heatmap[s]||(this.session.heatmap[s]=[]);let o=this.session.heatmap[s];o.length<this.cfg.maxHeatmapPoints&&o.push(t.data);break}case"rageclik":case"uturn":break}this.subscribers.forEach(s=>s(t)),(n=(i=this.cfg).onEvent)==null||n.call(i,t),this.cfg.endpoint&&(this.queue.push(t),this.queue.length>=this.cfg.batchSize&&this.flush())}subscribe(t){return this.subscribers.add(t),()=>this.subscribers.delete(t)}trackPageView(t){let e=t!=null?t:typeof window!="undefined"?window.location.pathname+window.location.search:"/";this.emit({type:"pageview",data:{path:e,title:typeof document!="undefined"?document.title:"",timestamp:Date.now(),sessionId:this.session.id,referrer:typeof document!="undefined"&&document.referrer||void 0}}),typeof window!="undefined"&&window.dispatchEvent(new CustomEvent("tracker:navigate",{detail:{path:e,title:document.title}}))}identify(t){this.userProperties={...this.userProperties,...t},this.fetchFlags()}getFlags(){return{...this.flags}}isFeatureEnabled(t){return this.flags[t]===!0}onFlagsChange(t){return this.flagSubscribers.add(t),()=>this.flagSubscribers.delete(t)}async fetchFlags(){if(!this.cfg.endpoint||!this.cfg.secretKey)return;let t=this.cfg.endpoint.replace(/\/events$/,"")+"/feature-flags/evaluate";try{let e=await fetch(t,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${this.cfg.secretKey}`},body:JSON.stringify({userProperties:this.userProperties})});if(!e.ok)return;let i=await e.json();this.flags=i,this.flagSubscribers.forEach(n=>n({...this.flags}))}catch(e){}}getSession(){return this.session}getPageViews(){return[...this.session.pageViews]}getTimeSpent(){return{...this.session.timeSpent}}getHeatmapData(t){var e;return t!==void 0?[...(e=this.session.heatmap[t])!=null?e:[]]:Object.entries(this.session.heatmap).reduce((i,[n,s])=>(i[n]=[...s],i),{})}async flush(){if(this.queue.length===0)return;let t=this.queue.splice(0);await this.sendBatch(t)}flushBeacon(){if(this.queue.length===0)return;let t=this.queue.splice(0),e=`${this.cfg.endpoint}/batch`,i=new Blob([this.buildBatchBody(t)],{type:"application/json"});typeof navigator!="undefined"&&navigator.sendBeacon?navigator.sendBeacon(e,i):this.sendBatch(t)}buildBatchBody(t){var e;return JSON.stringify({...this.cfg.appId?{appId:this.cfg.appId}:{},visitorId:this.session.visitorId,location:(e=this.location)!=null?e:void 0,events:t.map(i=>({sessionId:this.session.id,type:i.type,data:i.data}))})}async sendBatch(t){let e=`${this.cfg.endpoint}/batch`,i=this.cfg.secretKey?{Authorization:`Bearer ${this.cfg.secretKey}`}:{};try{await fetch(e,{method:"POST",headers:{"Content-Type":"application/json",...i},body:this.buildBatchBody(t),keepalive:!0})}catch(n){}}};function $(){let r=[[0,0,255],[0,255,255],[0,255,0],[255,255,0],[255,128,0],[255,0,0]],t=[],e=51;for(let i=0;i<r.length-1;i++){let[n,s,o]=r[i],[a,l,m]=r[i+1];for(let d=0;d<e;d++){let v=d/e;t.push([Math.round(n+(a-n)*v),Math.round(s+(l-s)*v),Math.round(o+(m-o)*v)])}}return t}var N=$();function F(r,t,e={}){let{radius:i=25,maxOpacity:n=.85,minOpacity:s=0}=e,o=r.getContext("2d");if(!o)return;let{width:a,height:l}=r;if(o.clearRect(0,0,a,l),t.length===0)return;let m=document.createElement("canvas");m.width=a,m.height=l;let d=m.getContext("2d");if(!d)return;for(let c of t){let p=c.xPct/100*a,u=c.yPct/100*l,b=c.type==="click"?i*1.6:i,f=d.createRadialGradient(p,u,0,p,u,b);f.addColorStop(0,"rgba(0,0,0,0.15)"),f.addColorStop(1,"rgba(0,0,0,0)"),d.fillStyle=f,d.beginPath(),d.arc(p,u,b,0,Math.PI*2),d.fill()}let v=d.getImageData(0,0,a,l),L=o.createImageData(a,l),C=v.data,w=L.data,H=N.length-1;for(let c=0;c<C.length;c+=4){let p=C[c+3];if(p===0)continue;let u=p/255,b=Math.min(Math.floor(u*H),H),[f,_,A]=N[b],B=s+u*(n-s);w[c]=f,w[c+1]=_,w[c+2]=A,w[c+3]=Math.round(B*255)}o.putImageData(L,0,0)}return W(X);})();
package/dist/index.d.mts CHANGED
@@ -214,6 +214,7 @@ declare class LogCapture {
214
214
 
215
215
  declare const DEFAULT_ENDPOINT = "https://api.alphana.ir/api/events";
216
216
  type SubscriberFn = (event: TrackerEvent) => void;
217
+ type FlagSubscriberFn = (flags: Record<string, boolean>) => void;
217
218
  declare class UserTracker {
218
219
  private readonly cfg;
219
220
  private session;
@@ -229,6 +230,9 @@ declare class UserTracker {
229
230
  private flushTimer;
230
231
  private heartbeatTimer;
231
232
  private location;
233
+ private userProperties;
234
+ private flags;
235
+ private readonly flagSubscribers;
232
236
  constructor(config?: TrackerConfig);
233
237
  /**
234
238
  * Attach event listeners and start tracking.
@@ -274,6 +278,38 @@ declare class UserTracker {
274
278
  * ```
275
279
  */
276
280
  trackPageView(path?: string): void;
281
+ /**
282
+ * Identify the current user with a set of properties.
283
+ * Properties are merged with any previously set ones and used for feature
284
+ * flag targeting (e.g. `email`, `plan`, `country`).
285
+ * Automatically triggers a flag re-evaluation.
286
+ *
287
+ * ```ts
288
+ * tracker.identify({ email: 'user@example.com', plan: 'pro' });
289
+ * ```
290
+ */
291
+ identify(properties: Record<string, string>): void;
292
+ /**
293
+ * Returns the latest evaluated feature flags as `{ [key]: boolean }`.
294
+ * Flags are fetched on `init()` and after every `identify()` call.
295
+ */
296
+ getFlags(): Record<string, boolean>;
297
+ /**
298
+ * Returns `true` if the given flag is currently enabled for this user.
299
+ * Returns `false` for unknown flags or before flags have loaded.
300
+ */
301
+ isFeatureEnabled(flagKey: string): boolean;
302
+ /**
303
+ * Subscribe to flag changes. Called whenever flags are re-evaluated.
304
+ * Returns an unsubscribe function.
305
+ *
306
+ * ```ts
307
+ * const unsub = tracker.onFlagsChange(flags => console.log(flags));
308
+ * ```
309
+ */
310
+ onFlagsChange(fn: FlagSubscriberFn): () => void;
311
+ /** Fetch (or re-fetch) flags from the backend evaluate endpoint. */
312
+ fetchFlags(): Promise<void>;
277
313
  /** A read-only snapshot of the current session. */
278
314
  getSession(): Readonly<SessionData>;
279
315
  /** All page views recorded so far. */
package/dist/index.d.ts CHANGED
@@ -214,6 +214,7 @@ declare class LogCapture {
214
214
 
215
215
  declare const DEFAULT_ENDPOINT = "https://api.alphana.ir/api/events";
216
216
  type SubscriberFn = (event: TrackerEvent) => void;
217
+ type FlagSubscriberFn = (flags: Record<string, boolean>) => void;
217
218
  declare class UserTracker {
218
219
  private readonly cfg;
219
220
  private session;
@@ -229,6 +230,9 @@ declare class UserTracker {
229
230
  private flushTimer;
230
231
  private heartbeatTimer;
231
232
  private location;
233
+ private userProperties;
234
+ private flags;
235
+ private readonly flagSubscribers;
232
236
  constructor(config?: TrackerConfig);
233
237
  /**
234
238
  * Attach event listeners and start tracking.
@@ -274,6 +278,38 @@ declare class UserTracker {
274
278
  * ```
275
279
  */
276
280
  trackPageView(path?: string): void;
281
+ /**
282
+ * Identify the current user with a set of properties.
283
+ * Properties are merged with any previously set ones and used for feature
284
+ * flag targeting (e.g. `email`, `plan`, `country`).
285
+ * Automatically triggers a flag re-evaluation.
286
+ *
287
+ * ```ts
288
+ * tracker.identify({ email: 'user@example.com', plan: 'pro' });
289
+ * ```
290
+ */
291
+ identify(properties: Record<string, string>): void;
292
+ /**
293
+ * Returns the latest evaluated feature flags as `{ [key]: boolean }`.
294
+ * Flags are fetched on `init()` and after every `identify()` call.
295
+ */
296
+ getFlags(): Record<string, boolean>;
297
+ /**
298
+ * Returns `true` if the given flag is currently enabled for this user.
299
+ * Returns `false` for unknown flags or before flags have loaded.
300
+ */
301
+ isFeatureEnabled(flagKey: string): boolean;
302
+ /**
303
+ * Subscribe to flag changes. Called whenever flags are re-evaluated.
304
+ * Returns an unsubscribe function.
305
+ *
306
+ * ```ts
307
+ * const unsub = tracker.onFlagsChange(flags => console.log(flags));
308
+ * ```
309
+ */
310
+ onFlagsChange(fn: FlagSubscriberFn): () => void;
311
+ /** Fetch (or re-fetch) flags from the backend evaluate endpoint. */
312
+ fetchFlags(): Promise<void>;
277
313
  /** A read-only snapshot of the current session. */
278
314
  getSession(): Readonly<SessionData>;
279
315
  /** All page views recorded so far. */
package/dist/index.js CHANGED
@@ -1,3 +1,3 @@
1
- 'use strict';var C="__ut_vid__";function f(){return typeof crypto!="undefined"&&typeof crypto.randomUUID=="function"?crypto.randomUUID():"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g,r=>{let t=Math.random()*16|0;return (r==="x"?t:t&3|8).toString(16)})}function H(){if(typeof localStorage=="undefined")return f();try{let r=localStorage.getItem(C);if(r)return r;let t=f();return localStorage.setItem(C,t),t}catch(r){return f()}}async function O(){try{let r=await fetch("https://ipapi.co/json/",{method:"GET",headers:{Accept:"application/json"}});if(!r.ok)return null;let t=await r.json();return t.error?null:{country:typeof t.country_code=="string"?t.country_code:"",countryName:typeof t.country_name=="string"?t.country_name:"",city:typeof t.city=="string"?t.city:void 0,region:typeof t.region=="string"?t.region:void 0,latitude:typeof t.latitude=="number"?t.latitude:void 0,longitude:typeof t.longitude=="number"?t.longitude:void 0}}catch(r){return null}}var b=class b{constructor({emit:t,sessionId:e}){this.previousPath="";this.originalPushState=null;this.originalReplaceState=null;this.pageEntryTime=0;this.handlePopState=()=>{this.handleNavigation();};this.emit=t,this.sessionId=e;}init(){this.recordPageView(window.location.pathname+window.location.search),window.addEventListener("popstate",this.handlePopState),this.originalPushState=history.pushState.bind(history);let t=this.originalPushState;history.pushState=(i,n,s)=>{t(i,n,s),this.handleNavigation();},this.originalReplaceState=history.replaceState.bind(history);let e=this.originalReplaceState;history.replaceState=(i,n,s)=>{e(i,n,s),this.handleNavigation();};}destroy(){window.removeEventListener("popstate",this.handlePopState),this.originalPushState&&(history.pushState=this.originalPushState),this.originalReplaceState&&(history.replaceState=this.originalReplaceState);}handleNavigation(){let t=window.location.pathname+window.location.search;if(t!==this.previousPath){if(this.previousPath&&this.pageEntryTime>0){let e=Date.now()-this.pageEntryTime;e<=b.UTURN_THRESHOLD_MS&&this.emit({type:"uturn",data:{fromPath:this.previousPath,toPath:t,timeOnPageMs:e,timestamp:Date.now(),sessionId:this.sessionId}});}this.recordPageView(t);}}recordPageView(t){this.previousPath=t,this.pageEntryTime=Date.now(),this.emit({type:"pageview",data:{path:t,title:document.title,timestamp:Date.now(),sessionId:this.sessionId,referrer:document.referrer||void 0}}),window.dispatchEvent(new CustomEvent("tracker:navigate",{detail:{path:t,title:document.title}}));}};b.UTURN_THRESHOLD_MS=5e3;var k=b;var P=class{constructor({emit:t,sessionId:e}){this.currentPath="";this.startTime=0;this.tracking=false;this.handleNavigate=t=>{this.stopTracking(),this.currentPath=t.detail.path,this.startTracking();};this.handleVisibilityChange=()=>{document.hidden?this.stopTracking():this.startTracking();};this.handleUnload=()=>{this.stopTracking();};this.emit=t,this.sessionId=e;}init(){this.currentPath=window.location.pathname+window.location.search,this.startTracking(),window.addEventListener("tracker:navigate",this.handleNavigate),document.addEventListener("visibilitychange",this.handleVisibilityChange),window.addEventListener("beforeunload",this.handleUnload),window.addEventListener("pagehide",this.handleUnload);}destroy(){this.stopTracking(),window.removeEventListener("tracker:navigate",this.handleNavigate),document.removeEventListener("visibilitychange",this.handleVisibilityChange),window.removeEventListener("beforeunload",this.handleUnload),window.removeEventListener("pagehide",this.handleUnload);}startTracking(){this.startTime=Date.now(),this.tracking=true;}stopTracking(){if(!this.tracking||!this.currentPath)return;let t=Date.now()-this.startTime;if(t<100){this.tracking=false;return}this.emit({type:"timespent",data:{path:this.currentPath,duration:t,sessionId:this.sessionId,timestamp:Date.now()}}),this.tracking=false;}};function T(r,t){let e=0;return (...i)=>{let n=Date.now();n-e>=t&&(e=n,r(...i));}}var h=class h{constructor({emit:t,sessionId:e,sampleRate:i=.3,maxPoints:n=2e3,allowedPaths:s}){this.currentPath="";this.pointCounts={};this.recentClicks=[];this.handleMouseMove=t=>{if(Math.random()>this.sampleRate)return;let e=document.documentElement.scrollWidth,i=document.documentElement.scrollHeight,n=t.clientY+window.scrollY;this.recordPoint({x:t.clientX,y:n,xPct:e>0?t.clientX/e*100:0,yPct:i>0?n/i*100:0,pw:e,ph:i,type:"move"});};this.handleClick=t=>{if(Date.now()-this.lastTouchTime<500)return;let e=document.documentElement.scrollWidth,i=document.documentElement.scrollHeight,n=t.clientY+window.scrollY,s=this.getClickTarget(t);this.recordPoint({x:t.clientX,y:n,xPct:e>0?t.clientX/e*100:0,yPct:i>0?n/i*100:0,pw:e,ph:i,type:"click",...s?{target:s}:{}}),this.checkRageClick(t.clientX,n,this.currentPath);};this.lastTouchTime=0;this.handleTouchEnd=t=>{let e=t.changedTouches[0];if(!e)return;let i=document.documentElement.scrollWidth,n=document.documentElement.scrollHeight,s=e.clientY+window.scrollY;this.lastTouchTime=Date.now(),this.recordPoint({x:e.clientX,y:s,xPct:i>0?e.clientX/i*100:0,yPct:n>0?s/n*100:0,pw:i,ph:n,type:"click"}),this.checkRageClick(e.clientX,s,this.currentPath);};this.handleScroll=()=>{if(Math.random()>this.sampleRate)return;let t=document.documentElement.scrollWidth,e=document.documentElement.scrollHeight,i=window.innerWidth,n=window.scrollX,s=window.scrollY,o=n+i/2;this.recordPoint({x:i/2,y:s,xPct:t>0?o/t*100:50,yPct:e>0?s/e*100:0,pw:t,ph:e,type:"scroll"});};this.handleNavigate=t=>{this.currentPath=t.detail.path;};this.emit=t,this.sessionId=e,this.sampleRate=i,this.maxPoints=n,this.allowedPaths=s&&s.length>0?new Set(s):null,this.throttledMouseMove=T(this.handleMouseMove,50),this.throttledScroll=T(this.handleScroll,100);}init(){this.currentPath=window.location.pathname+window.location.search,document.addEventListener("mousemove",this.throttledMouseMove),document.addEventListener("click",this.handleClick),document.addEventListener("touchend",this.handleTouchEnd,{passive:true}),window.addEventListener("scroll",this.throttledScroll,{passive:true}),window.addEventListener("tracker:navigate",this.handleNavigate);}destroy(){document.removeEventListener("mousemove",this.throttledMouseMove),document.removeEventListener("click",this.handleClick),document.removeEventListener("touchend",this.handleTouchEnd),window.removeEventListener("scroll",this.throttledScroll),window.removeEventListener("tracker:navigate",this.handleNavigate);}canRecord(){var t;return this.allowedPaths!==null&&!this.allowedPaths.has(this.currentPath)?false:((t=this.pointCounts[this.currentPath])!=null?t:0)<this.maxPoints}recordPoint(t){var e;this.canRecord()&&(this.pointCounts[this.currentPath]=((e=this.pointCounts[this.currentPath])!=null?e:0)+1,this.emit({type:"heatmap",data:{...t,path:this.currentPath,timestamp:Date.now()}}));}getClickTarget(t){var n,s,o,a;let e=t.target;return e&&(e.getAttribute("aria-label")||((n=e.closest("[aria-label]"))==null?void 0:n.getAttribute("aria-label"))||e.getAttribute("data-track-label")||e.getAttribute("id")||(e instanceof HTMLButtonElement||e instanceof HTMLAnchorElement?(s=e.innerText)==null?void 0:s.trim().slice(0,60):(a=(o=e.closest("button, a"))==null?void 0:o.textContent)==null?void 0:a.trim().slice(0,60)))||void 0}checkRageClick(t,e,i){let n=Date.now();this.recentClicks=this.recentClicks.filter(o=>n-o.t<h.RAGE_WINDOW_MS),this.recentClicks.push({x:t,y:e,t:n});let s=this.recentClicks.filter(o=>Math.hypot(o.x-t,o.y-e)<=h.RAGE_RADIUS_PX);s.length>=h.RAGE_THRESHOLD&&(this.emit({type:"rageclik",data:{path:i,x:t,y:e,count:s.length,timestamp:n,sessionId:this.sessionId}}),this.recentClicks=[]);}};h.RAGE_THRESHOLD=3,h.RAGE_WINDOW_MS=1e3,h.RAGE_RADIUS_PX=50;var S=h;var y=class{constructor(t){this.prevOnError=null;this.prevOnUnhandledRejection=null;this.initialized=false;try{let e=new URL(t.endpoint),i=e.pathname.replace(/\/$/,"").split("/");i.pop(),e.pathname=i.join("/")||"/",this.endpoint=e.toString().replace(/\/$/,"");}catch(e){this.endpoint=t.endpoint;}this.sessionId=t.sessionId,this.appId=t.appId,this.authHeaders=t.secretKey?{Authorization:`Bearer ${t.secretKey}`}:{};}init(){typeof window=="undefined"||this.initialized||(this.origInfo=console.info.bind(console),this.origWarn=console.warn.bind(console),this.origError=console.error.bind(console),console.info=(...t)=>{this.origInfo(...t),this.send("info",this.format(t));},console.warn=(...t)=>{this.origWarn(...t),this.send("warn",this.format(t));},console.error=(...t)=>{this.origError(...t);let[e]=t,i=e instanceof Error?e.stack:void 0;this.send("error",this.format(t),{stack:i});},this.prevOnError=window.onerror,window.onerror=(t,e,i,n,s)=>(this.send("error",String(t),{stack:s==null?void 0:s.stack,meta:{src:e,line:i,col:n}}),typeof this.prevOnError=="function"?this.prevOnError(t,e,i,n,s):false),this.prevOnUnhandledRejection=t=>{let e=t.reason,i=e instanceof Error?e.message:String(e!=null?e:"Unhandled promise rejection");this.send("error",i,{stack:e instanceof Error?e.stack:void 0});},window.addEventListener("unhandledrejection",this.prevOnUnhandledRejection),this.initialized=true);}destroy(){this.initialized&&(console.info=this.origInfo,console.warn=this.origWarn,console.error=this.origError,window.onerror=this.prevOnError,this.prevOnUnhandledRejection&&window.removeEventListener("unhandledrejection",this.prevOnUnhandledRejection),this.initialized=false);}capture(t,e,i){this.send(t,e,i);}format(t){return t.map(e=>{if(e instanceof Error)return e.message;if(typeof e=="object")try{return JSON.stringify(e)}catch(i){return String(e)}return String(e)}).join(" ")}send(t,e,i){let n={sessionId:this.sessionId,...this.appId?{appId:this.appId}:{},level:t,message:e,url:typeof window!="undefined"?window.location.href:void 0,stack:i==null?void 0:i.stack,meta:i==null?void 0:i.meta,timestamp:Date.now()},s=`${this.endpoint}/logs/ingest`,o=JSON.stringify(n);fetch(s,{method:"POST",headers:{"Content-Type":"application/json",...this.authHeaders},body:o,keepalive:true}).catch(a=>{this.origError&&this.origError("[user-tracker] Failed to send log:",a);});}};var D="https://api.alphana.ir/api/events",B={endpoint:D,trackNavigation:true,trackTime:true,trackHeatmap:true,trackLogs:true,trackSnapshots:true,mouseSampleRate:.3,maxHeatmapPoints:2e3,batchSize:20,flushInterval:5e3},I=class{constructor(t={}){this.initialized=false;this.subscribers=new Set;this.queue=[];this.flushTimer=null;this.heartbeatTimer=null;this.location=null;this.handleVisibilityChange=()=>{document.visibilityState==="hidden"&&(this.queue.length>0&&this.flushBeacon(),this.sendDeactivate());};this.handlePageHide=()=>{this.queue.length>0&&this.flushBeacon(),this.sendDeactivate();};this.handleNavigate=t=>{};var e;this.cfg={...B,...t};try{new URL(this.cfg.endpoint);}catch(i){throw new Error(`[alpha-tracker] Invalid endpoint URL: "${this.cfg.endpoint}"`)}this.session={id:(e=t.sessionId)!=null?e:f(),visitorId:H(),startedAt:Date.now(),pageViews:[],timeSpent:{},heatmap:{}};}init(){if(typeof window=="undefined"||this.initialized)return this;let t=this.emit.bind(this),{id:e}=this.session;return this.cfg.trackNavigation&&(this.navigation=new k({emit:t,sessionId:e}),this.navigation.init()),this.cfg.trackTime&&(this.time=new P({emit:t,sessionId:e}),this.time.init()),this.cfg.trackHeatmap&&(this.heatmap=new S({emit:t,sessionId:e,sampleRate:this.cfg.mouseSampleRate,maxPoints:this.cfg.maxHeatmapPoints,allowedPaths:this.cfg.heatmapPages}),this.heatmap.init()),this.cfg.endpoint&&(this.flushTimer=setInterval(()=>{this.queue.length>0&&this.flush();},this.cfg.flushInterval),O().then(i=>{this.location=i,i&&(this.session.location=i);}),window.addEventListener("visibilitychange",this.handleVisibilityChange),window.addEventListener("pagehide",this.handlePageHide),this.heartbeatTimer=setInterval(()=>{document.visibilityState!=="hidden"&&this.sendHeartbeat();},3e4),this.cfg.trackLogs&&(this.logCapture=new y({endpoint:this.cfg.endpoint,sessionId:this.session.id,secretKey:this.cfg.secretKey,appId:this.cfg.appId}),this.logCapture.init())),this.initialized=true,this}destroy(){var t,e,i,n;this.flushTimer!==null&&(clearInterval(this.flushTimer),this.flushTimer=null),this.heartbeatTimer!==null&&(clearInterval(this.heartbeatTimer),this.heartbeatTimer=null),typeof window!="undefined"&&(window.removeEventListener("visibilitychange",this.handleVisibilityChange),window.removeEventListener("pagehide",this.handlePageHide)),(t=this.navigation)==null||t.destroy(),(e=this.time)==null||e.destroy(),(i=this.heatmap)==null||i.destroy(),(n=this.logCapture)==null||n.destroy(),typeof window!="undefined"&&window.removeEventListener("tracker:navigate",this.handleNavigate),this.queue.length>0&&this.cfg.endpoint&&this.flushBeacon(),this.initialized=false;}async sendHeartbeat(){if(!this.cfg.endpoint)return;let t=`${this.cfg.endpoint}/heartbeat`,e=this.cfg.secretKey?{Authorization:`Bearer ${this.cfg.secretKey}`}:{},i=JSON.stringify({sessionId:this.session.id,visitorId:this.session.visitorId,path:typeof window!="undefined"?window.location.pathname:"/",active:true,...this.cfg.appId?{appId:this.cfg.appId}:{},...this.location?{location:this.location}:{}});try{await fetch(t,{method:"POST",headers:{"Content-Type":"application/json",...e},body:i,keepalive:!0});}catch(n){}}sendDeactivate(){if(!this.cfg.endpoint)return;let t=`${this.cfg.endpoint}/heartbeat`,e=this.cfg.secretKey?{Authorization:`Bearer ${this.cfg.secretKey}`}:{},i=JSON.stringify({sessionId:this.session.id,path:typeof window!="undefined"?window.location.pathname:"/",active:false,...this.cfg.appId?{appId:this.cfg.appId}:{}});typeof navigator!="undefined"&&navigator.sendBeacon?navigator.sendBeacon(t,new Blob([i],{type:"application/json"})):fetch(t,{method:"POST",headers:{"Content-Type":"application/json",...e},body:i,keepalive:true}).catch(()=>{});}emit(t){var e,i,n;switch(t.type){case "pageview":this.session.pageViews.push(t.data);break;case "timespent":{let s=(e=this.session.timeSpent[t.data.path])!=null?e:0;this.session.timeSpent[t.data.path]=s+t.data.duration;break}case "heatmap":{let s=t.data.path;this.session.heatmap[s]||(this.session.heatmap[s]=[]);let o=this.session.heatmap[s];o.length<this.cfg.maxHeatmapPoints&&o.push(t.data);break}}this.subscribers.forEach(s=>s(t)),(n=(i=this.cfg).onEvent)==null||n.call(i,t),this.cfg.endpoint&&(this.queue.push(t),this.queue.length>=this.cfg.batchSize&&this.flush());}subscribe(t){return this.subscribers.add(t),()=>this.subscribers.delete(t)}trackPageView(t){let e=t!=null?t:typeof window!="undefined"?window.location.pathname+window.location.search:"/";this.emit({type:"pageview",data:{path:e,title:typeof document!="undefined"?document.title:"",timestamp:Date.now(),sessionId:this.session.id,referrer:typeof document!="undefined"&&document.referrer||void 0}}),typeof window!="undefined"&&window.dispatchEvent(new CustomEvent("tracker:navigate",{detail:{path:e,title:document.title}}));}getSession(){return this.session}getPageViews(){return [...this.session.pageViews]}getTimeSpent(){return {...this.session.timeSpent}}getHeatmapData(t){var e;return t!==void 0?[...(e=this.session.heatmap[t])!=null?e:[]]:Object.entries(this.session.heatmap).reduce((i,[n,s])=>(i[n]=[...s],i),{})}async flush(){if(this.queue.length===0)return;let t=this.queue.splice(0);await this.sendBatch(t);}flushBeacon(){if(this.queue.length===0)return;let t=this.queue.splice(0),e=`${this.cfg.endpoint}/batch`,i=new Blob([this.buildBatchBody(t)],{type:"application/json"});typeof navigator!="undefined"&&navigator.sendBeacon?navigator.sendBeacon(e,i):this.sendBatch(t);}buildBatchBody(t){var e;return JSON.stringify({...this.cfg.appId?{appId:this.cfg.appId}:{},visitorId:this.session.visitorId,location:(e=this.location)!=null?e:void 0,events:t.map(i=>({sessionId:this.session.id,type:i.type,data:i.data}))})}async sendBatch(t){let e=`${this.cfg.endpoint}/batch`,i=this.cfg.secretKey?{Authorization:`Bearer ${this.cfg.secretKey}`}:{};try{await fetch(e,{method:"POST",headers:{"Content-Type":"application/json",...i},body:this.buildBatchBody(t),keepalive:!0});}catch(n){}}};function U(){let r=[[0,0,255],[0,255,255],[0,255,0],[255,255,0],[255,128,0],[255,0,0]],t=[],e=51;for(let i=0;i<r.length-1;i++){let[n,s,o]=r[i],[a,l,g]=r[i+1];for(let d=0;d<e;d++){let m=d/e;t.push([Math.round(n+(a-n)*m),Math.round(s+(l-s)*m),Math.round(o+(g-o)*m)]);}}return t}var M=U();function j(r,t,e={}){let{radius:i=25,maxOpacity:n=.85,minOpacity:s=0}=e,o=r.getContext("2d");if(!o)return;let{width:a,height:l}=r;if(o.clearRect(0,0,a,l),t.length===0)return;let g=document.createElement("canvas");g.width=a,g.height=l;let d=g.getContext("2d");if(!d)return;for(let c of t){let p=c.xPct/100*a,u=c.yPct/100*l,E=c.type==="click"?i*1.6:i,v=d.createRadialGradient(p,u,0,p,u,E);v.addColorStop(0,"rgba(0,0,0,0.15)"),v.addColorStop(1,"rgba(0,0,0,0)"),d.fillStyle=v,d.beginPath(),d.arc(p,u,E,0,Math.PI*2),d.fill();}let m=d.getImageData(0,0,a,l),R=o.createImageData(a,l),x=m.data,w=R.data,L=M.length-1;for(let c=0;c<x.length;c+=4){let p=x[c+3];if(p===0)continue;let u=p/255,E=Math.min(Math.floor(u*L),L),[v,N,_]=M[E],A=s+u*(n-s);w[c]=v,w[c+1]=N,w[c+2]=_,w[c+3]=Math.round(A*255);}o.putImageData(R,0,0);}
2
- exports.DEFAULT_ENDPOINT=D;exports.LogCapture=y;exports.UserTracker=I;exports.renderHeatmap=j;//# sourceMappingURL=index.js.map
1
+ 'use strict';var C="__ut_vid__";function f(){return typeof crypto!="undefined"&&typeof crypto.randomUUID=="function"?crypto.randomUUID():"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g,o=>{let t=Math.random()*16|0;return (o==="x"?t:t&3|8).toString(16)})}function H(){if(typeof localStorage=="undefined")return f();try{let o=localStorage.getItem(C);if(o)return o;let t=f();return localStorage.setItem(C,t),t}catch(o){return f()}}async function O(){try{let o=await fetch("https://ipapi.co/json/",{method:"GET",headers:{Accept:"application/json"}});if(!o.ok)return null;let t=await o.json();return t.error?null:{country:typeof t.country_code=="string"?t.country_code:"",countryName:typeof t.country_name=="string"?t.country_name:"",city:typeof t.city=="string"?t.city:void 0,region:typeof t.region=="string"?t.region:void 0,latitude:typeof t.latitude=="number"?t.latitude:void 0,longitude:typeof t.longitude=="number"?t.longitude:void 0}}catch(o){return null}}var P=class P{constructor({emit:t,sessionId:e}){this.previousPath="";this.originalPushState=null;this.originalReplaceState=null;this.pageEntryTime=0;this.handlePopState=()=>{this.handleNavigation();};this.emit=t,this.sessionId=e;}init(){this.recordPageView(window.location.pathname+window.location.search),window.addEventListener("popstate",this.handlePopState),this.originalPushState=history.pushState.bind(history);let t=this.originalPushState;history.pushState=(i,n,s)=>{t(i,n,s),this.handleNavigation();},this.originalReplaceState=history.replaceState.bind(history);let e=this.originalReplaceState;history.replaceState=(i,n,s)=>{e(i,n,s),this.handleNavigation();};}destroy(){window.removeEventListener("popstate",this.handlePopState),this.originalPushState&&(history.pushState=this.originalPushState),this.originalReplaceState&&(history.replaceState=this.originalReplaceState);}handleNavigation(){let t=window.location.pathname+window.location.search;if(t!==this.previousPath){if(this.previousPath&&this.pageEntryTime>0){let e=Date.now()-this.pageEntryTime;e<=P.UTURN_THRESHOLD_MS&&this.emit({type:"uturn",data:{fromPath:this.previousPath,toPath:t,timeOnPageMs:e,timestamp:Date.now(),sessionId:this.sessionId}});}this.recordPageView(t);}}recordPageView(t){this.previousPath=t,this.pageEntryTime=Date.now(),this.emit({type:"pageview",data:{path:t,title:document.title,timestamp:Date.now(),sessionId:this.sessionId,referrer:document.referrer||void 0}}),window.dispatchEvent(new CustomEvent("tracker:navigate",{detail:{path:t,title:document.title}}));}};P.UTURN_THRESHOLD_MS=5e3;var E=P;var k=class{constructor({emit:t,sessionId:e}){this.currentPath="";this.startTime=0;this.tracking=false;this.handleNavigate=t=>{this.stopTracking(),this.currentPath=t.detail.path,this.startTracking();};this.handleVisibilityChange=()=>{document.hidden?this.stopTracking():this.startTracking();};this.handleUnload=()=>{this.stopTracking();};this.emit=t,this.sessionId=e;}init(){this.currentPath=window.location.pathname+window.location.search,this.startTracking(),window.addEventListener("tracker:navigate",this.handleNavigate),document.addEventListener("visibilitychange",this.handleVisibilityChange),window.addEventListener("beforeunload",this.handleUnload),window.addEventListener("pagehide",this.handleUnload);}destroy(){this.stopTracking(),window.removeEventListener("tracker:navigate",this.handleNavigate),document.removeEventListener("visibilitychange",this.handleVisibilityChange),window.removeEventListener("beforeunload",this.handleUnload),window.removeEventListener("pagehide",this.handleUnload);}startTracking(){this.startTime=Date.now(),this.tracking=true;}stopTracking(){if(!this.tracking||!this.currentPath)return;let t=Date.now()-this.startTime;if(t<100){this.tracking=false;return}this.emit({type:"timespent",data:{path:this.currentPath,duration:t,sessionId:this.sessionId,timestamp:Date.now()}}),this.tracking=false;}};function T(o,t){let e=0;return (...i)=>{let n=Date.now();n-e>=t&&(e=n,o(...i));}}var h=class h{constructor({emit:t,sessionId:e,sampleRate:i=.3,maxPoints:n=2e3,allowedPaths:s}){this.currentPath="";this.pointCounts={};this.recentClicks=[];this.handleMouseMove=t=>{if(Math.random()>this.sampleRate)return;let e=document.documentElement.scrollWidth,i=document.documentElement.scrollHeight,n=t.clientY+window.scrollY;this.recordPoint({x:t.clientX,y:n,xPct:e>0?t.clientX/e*100:0,yPct:i>0?n/i*100:0,pw:e,ph:i,type:"move"});};this.handleClick=t=>{if(Date.now()-this.lastTouchTime<500)return;let e=document.documentElement.scrollWidth,i=document.documentElement.scrollHeight,n=t.clientY+window.scrollY,s=this.getClickTarget(t);this.recordPoint({x:t.clientX,y:n,xPct:e>0?t.clientX/e*100:0,yPct:i>0?n/i*100:0,pw:e,ph:i,type:"click",...s?{target:s}:{}}),this.checkRageClick(t.clientX,n,this.currentPath);};this.lastTouchTime=0;this.handleTouchEnd=t=>{let e=t.changedTouches[0];if(!e)return;let i=document.documentElement.scrollWidth,n=document.documentElement.scrollHeight,s=e.clientY+window.scrollY;this.lastTouchTime=Date.now(),this.recordPoint({x:e.clientX,y:s,xPct:i>0?e.clientX/i*100:0,yPct:n>0?s/n*100:0,pw:i,ph:n,type:"click"}),this.checkRageClick(e.clientX,s,this.currentPath);};this.handleScroll=()=>{if(Math.random()>this.sampleRate)return;let t=document.documentElement.scrollWidth,e=document.documentElement.scrollHeight,i=window.innerWidth,n=window.scrollX,s=window.scrollY,r=n+i/2;this.recordPoint({x:i/2,y:s,xPct:t>0?r/t*100:50,yPct:e>0?s/e*100:0,pw:t,ph:e,type:"scroll"});};this.handleNavigate=t=>{this.currentPath=t.detail.path;};this.emit=t,this.sessionId=e,this.sampleRate=i,this.maxPoints=n,this.allowedPaths=s&&s.length>0?new Set(s):null,this.throttledMouseMove=T(this.handleMouseMove,50),this.throttledScroll=T(this.handleScroll,100);}init(){this.currentPath=window.location.pathname+window.location.search,document.addEventListener("mousemove",this.throttledMouseMove),document.addEventListener("click",this.handleClick),document.addEventListener("touchend",this.handleTouchEnd,{passive:true}),window.addEventListener("scroll",this.throttledScroll,{passive:true}),window.addEventListener("tracker:navigate",this.handleNavigate);}destroy(){document.removeEventListener("mousemove",this.throttledMouseMove),document.removeEventListener("click",this.handleClick),document.removeEventListener("touchend",this.handleTouchEnd),window.removeEventListener("scroll",this.throttledScroll),window.removeEventListener("tracker:navigate",this.handleNavigate);}canRecord(){var t;return this.allowedPaths!==null&&!this.allowedPaths.has(this.currentPath)?false:((t=this.pointCounts[this.currentPath])!=null?t:0)<this.maxPoints}recordPoint(t){var e;this.canRecord()&&(this.pointCounts[this.currentPath]=((e=this.pointCounts[this.currentPath])!=null?e:0)+1,this.emit({type:"heatmap",data:{...t,path:this.currentPath,timestamp:Date.now()}}));}getClickTarget(t){var n,s,r,a;let e=t.target;return e&&(e.getAttribute("aria-label")||((n=e.closest("[aria-label]"))==null?void 0:n.getAttribute("aria-label"))||e.getAttribute("data-track-label")||e.getAttribute("id")||(e instanceof HTMLButtonElement||e instanceof HTMLAnchorElement?(s=e.innerText)==null?void 0:s.trim().slice(0,60):(a=(r=e.closest("button, a"))==null?void 0:r.textContent)==null?void 0:a.trim().slice(0,60)))||void 0}checkRageClick(t,e,i){let n=Date.now();this.recentClicks=this.recentClicks.filter(r=>n-r.t<h.RAGE_WINDOW_MS),this.recentClicks.push({x:t,y:e,t:n});let s=this.recentClicks.filter(r=>Math.hypot(r.x-t,r.y-e)<=h.RAGE_RADIUS_PX);s.length>=h.RAGE_THRESHOLD&&(this.emit({type:"rageclik",data:{path:i,x:t,y:e,count:s.length,timestamp:n,sessionId:this.sessionId}}),this.recentClicks=[]);}};h.RAGE_THRESHOLD=3,h.RAGE_WINDOW_MS=1e3,h.RAGE_RADIUS_PX=50;var S=h;var y=class{constructor(t){this.prevOnError=null;this.prevOnUnhandledRejection=null;this.initialized=false;try{let e=new URL(t.endpoint),i=e.pathname.replace(/\/$/,"").split("/");i.pop(),e.pathname=i.join("/")||"/",this.endpoint=e.toString().replace(/\/$/,"");}catch(e){this.endpoint=t.endpoint;}this.sessionId=t.sessionId,this.appId=t.appId,this.authHeaders=t.secretKey?{Authorization:`Bearer ${t.secretKey}`}:{};}init(){typeof window=="undefined"||this.initialized||(this.origInfo=console.info.bind(console),this.origWarn=console.warn.bind(console),this.origError=console.error.bind(console),console.info=(...t)=>{this.origInfo(...t),this.send("info",this.format(t));},console.warn=(...t)=>{this.origWarn(...t),this.send("warn",this.format(t));},console.error=(...t)=>{this.origError(...t);let[e]=t,i=e instanceof Error?e.stack:void 0;this.send("error",this.format(t),{stack:i});},this.prevOnError=window.onerror,window.onerror=(t,e,i,n,s)=>(this.send("error",String(t),{stack:s==null?void 0:s.stack,meta:{src:e,line:i,col:n}}),typeof this.prevOnError=="function"?this.prevOnError(t,e,i,n,s):false),this.prevOnUnhandledRejection=t=>{let e=t.reason,i=e instanceof Error?e.message:String(e!=null?e:"Unhandled promise rejection");this.send("error",i,{stack:e instanceof Error?e.stack:void 0});},window.addEventListener("unhandledrejection",this.prevOnUnhandledRejection),this.initialized=true);}destroy(){this.initialized&&(console.info=this.origInfo,console.warn=this.origWarn,console.error=this.origError,window.onerror=this.prevOnError,this.prevOnUnhandledRejection&&window.removeEventListener("unhandledrejection",this.prevOnUnhandledRejection),this.initialized=false);}capture(t,e,i){this.send(t,e,i);}format(t){return t.map(e=>{if(e instanceof Error)return e.message;if(typeof e=="object")try{return JSON.stringify(e)}catch(i){return String(e)}return String(e)}).join(" ")}send(t,e,i){let n={sessionId:this.sessionId,...this.appId?{appId:this.appId}:{},level:t,message:e,url:typeof window!="undefined"?window.location.href:void 0,stack:i==null?void 0:i.stack,meta:i==null?void 0:i.meta,timestamp:Date.now()},s=`${this.endpoint}/logs/ingest`,r=JSON.stringify(n);fetch(s,{method:"POST",headers:{"Content-Type":"application/json",...this.authHeaders},body:r,keepalive:true}).catch(a=>{this.origError&&this.origError("[user-tracker] Failed to send log:",a);});}};var D="https://api.alphana.ir/api/events",A={endpoint:D,trackNavigation:true,trackTime:true,trackHeatmap:true,trackLogs:true,mouseSampleRate:.3,maxHeatmapPoints:2e3,batchSize:20,flushInterval:5e3},I=class{constructor(t={}){this.initialized=false;this.subscribers=new Set;this.queue=[];this.flushTimer=null;this.heartbeatTimer=null;this.location=null;this.userProperties={};this.flags={};this.flagSubscribers=new Set;this.handleVisibilityChange=()=>{document.visibilityState==="hidden"&&(this.queue.length>0&&this.flushBeacon(),this.sendDeactivate());};this.handlePageHide=()=>{this.queue.length>0&&this.flushBeacon(),this.sendDeactivate();};this.handleNavigate=t=>{};var e;this.cfg={...A,...t};try{new URL(this.cfg.endpoint);}catch(i){throw new Error(`[alpha-tracker] Invalid endpoint URL: "${this.cfg.endpoint}"`)}this.session={id:(e=t.sessionId)!=null?e:f(),visitorId:H(),startedAt:Date.now(),pageViews:[],timeSpent:{},heatmap:{}};}init(){if(typeof window=="undefined"||this.initialized)return this;let t=this.emit.bind(this),{id:e}=this.session;return this.cfg.trackNavigation&&(this.navigation=new E({emit:t,sessionId:e}),this.navigation.init()),this.cfg.trackTime&&(this.time=new k({emit:t,sessionId:e}),this.time.init()),this.cfg.trackHeatmap&&(this.heatmap=new S({emit:t,sessionId:e,sampleRate:this.cfg.mouseSampleRate,maxPoints:this.cfg.maxHeatmapPoints,allowedPaths:this.cfg.heatmapPages}),this.heatmap.init()),this.cfg.endpoint&&(this.flushTimer=setInterval(()=>{this.queue.length>0&&this.flush();},this.cfg.flushInterval),O().then(i=>{this.location=i,i&&(this.session.location=i);}),window.addEventListener("visibilitychange",this.handleVisibilityChange),window.addEventListener("pagehide",this.handlePageHide),this.heartbeatTimer=setInterval(()=>{document.visibilityState!=="hidden"&&this.sendHeartbeat();},3e4),this.cfg.trackLogs&&(this.logCapture=new y({endpoint:this.cfg.endpoint,sessionId:this.session.id,secretKey:this.cfg.secretKey,appId:this.cfg.appId}),this.logCapture.init())),this.initialized=true,this.fetchFlags(),this}destroy(){var t,e,i,n;this.flushTimer!==null&&(clearInterval(this.flushTimer),this.flushTimer=null),this.heartbeatTimer!==null&&(clearInterval(this.heartbeatTimer),this.heartbeatTimer=null),typeof window!="undefined"&&(window.removeEventListener("visibilitychange",this.handleVisibilityChange),window.removeEventListener("pagehide",this.handlePageHide)),(t=this.navigation)==null||t.destroy(),(e=this.time)==null||e.destroy(),(i=this.heatmap)==null||i.destroy(),(n=this.logCapture)==null||n.destroy(),typeof window!="undefined"&&window.removeEventListener("tracker:navigate",this.handleNavigate),this.queue.length>0&&this.cfg.endpoint&&this.flushBeacon(),this.initialized=false;}async sendHeartbeat(){if(!this.cfg.endpoint)return;let t=`${this.cfg.endpoint}/heartbeat`,e=this.cfg.secretKey?{Authorization:`Bearer ${this.cfg.secretKey}`}:{},i=JSON.stringify({sessionId:this.session.id,visitorId:this.session.visitorId,path:typeof window!="undefined"?window.location.pathname:"/",active:true,...this.cfg.appId?{appId:this.cfg.appId}:{},...this.location?{location:this.location}:{}});try{await fetch(t,{method:"POST",headers:{"Content-Type":"application/json",...e},body:i,keepalive:!0});}catch(n){}}sendDeactivate(){if(!this.cfg.endpoint)return;let t=`${this.cfg.endpoint}/heartbeat`,e=this.cfg.secretKey?{Authorization:`Bearer ${this.cfg.secretKey}`}:{},i=JSON.stringify({sessionId:this.session.id,path:typeof window!="undefined"?window.location.pathname:"/",active:false,...this.cfg.appId?{appId:this.cfg.appId}:{}});typeof navigator!="undefined"&&navigator.sendBeacon?navigator.sendBeacon(t,new Blob([i],{type:"application/json"})):fetch(t,{method:"POST",headers:{"Content-Type":"application/json",...e},body:i,keepalive:true}).catch(()=>{});}emit(t){var e,i,n;switch(t.type){case "pageview":this.session.pageViews.push(t.data);break;case "timespent":{let s=(e=this.session.timeSpent[t.data.path])!=null?e:0;this.session.timeSpent[t.data.path]=s+t.data.duration;break}case "heatmap":{let s=t.data.path;this.session.heatmap[s]||(this.session.heatmap[s]=[]);let r=this.session.heatmap[s];r.length<this.cfg.maxHeatmapPoints&&r.push(t.data);break}}this.subscribers.forEach(s=>s(t)),(n=(i=this.cfg).onEvent)==null||n.call(i,t),this.cfg.endpoint&&(this.queue.push(t),this.queue.length>=this.cfg.batchSize&&this.flush());}subscribe(t){return this.subscribers.add(t),()=>this.subscribers.delete(t)}trackPageView(t){let e=t!=null?t:typeof window!="undefined"?window.location.pathname+window.location.search:"/";this.emit({type:"pageview",data:{path:e,title:typeof document!="undefined"?document.title:"",timestamp:Date.now(),sessionId:this.session.id,referrer:typeof document!="undefined"&&document.referrer||void 0}}),typeof window!="undefined"&&window.dispatchEvent(new CustomEvent("tracker:navigate",{detail:{path:e,title:document.title}}));}identify(t){this.userProperties={...this.userProperties,...t},this.fetchFlags();}getFlags(){return {...this.flags}}isFeatureEnabled(t){return this.flags[t]===true}onFlagsChange(t){return this.flagSubscribers.add(t),()=>this.flagSubscribers.delete(t)}async fetchFlags(){if(!this.cfg.endpoint||!this.cfg.secretKey)return;let t=this.cfg.endpoint.replace(/\/events$/,"")+"/feature-flags/evaluate";try{let e=await fetch(t,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${this.cfg.secretKey}`},body:JSON.stringify({userProperties:this.userProperties})});if(!e.ok)return;let i=await e.json();this.flags=i,this.flagSubscribers.forEach(n=>n({...this.flags}));}catch(e){}}getSession(){return this.session}getPageViews(){return [...this.session.pageViews]}getTimeSpent(){return {...this.session.timeSpent}}getHeatmapData(t){var e;return t!==void 0?[...(e=this.session.heatmap[t])!=null?e:[]]:Object.entries(this.session.heatmap).reduce((i,[n,s])=>(i[n]=[...s],i),{})}async flush(){if(this.queue.length===0)return;let t=this.queue.splice(0);await this.sendBatch(t);}flushBeacon(){if(this.queue.length===0)return;let t=this.queue.splice(0),e=`${this.cfg.endpoint}/batch`,i=new Blob([this.buildBatchBody(t)],{type:"application/json"});typeof navigator!="undefined"&&navigator.sendBeacon?navigator.sendBeacon(e,i):this.sendBatch(t);}buildBatchBody(t){var e;return JSON.stringify({...this.cfg.appId?{appId:this.cfg.appId}:{},visitorId:this.session.visitorId,location:(e=this.location)!=null?e:void 0,events:t.map(i=>({sessionId:this.session.id,type:i.type,data:i.data}))})}async sendBatch(t){let e=`${this.cfg.endpoint}/batch`,i=this.cfg.secretKey?{Authorization:`Bearer ${this.cfg.secretKey}`}:{};try{await fetch(e,{method:"POST",headers:{"Content-Type":"application/json",...i},body:this.buildBatchBody(t),keepalive:!0});}catch(n){}}};function B(){let o=[[0,0,255],[0,255,255],[0,255,0],[255,255,0],[255,128,0],[255,0,0]],t=[],e=51;for(let i=0;i<o.length-1;i++){let[n,s,r]=o[i],[a,l,g]=o[i+1];for(let d=0;d<e;d++){let m=d/e;t.push([Math.round(n+(a-n)*m),Math.round(s+(l-s)*m),Math.round(r+(g-r)*m)]);}}return t}var M=B();function U(o,t,e={}){let{radius:i=25,maxOpacity:n=.85,minOpacity:s=0}=e,r=o.getContext("2d");if(!r)return;let{width:a,height:l}=o;if(r.clearRect(0,0,a,l),t.length===0)return;let g=document.createElement("canvas");g.width=a,g.height=l;let d=g.getContext("2d");if(!d)return;for(let c of t){let p=c.xPct/100*a,u=c.yPct/100*l,b=c.type==="click"?i*1.6:i,v=d.createRadialGradient(p,u,0,p,u,b);v.addColorStop(0,"rgba(0,0,0,0.15)"),v.addColorStop(1,"rgba(0,0,0,0)"),d.fillStyle=v,d.beginPath(),d.arc(p,u,b,0,Math.PI*2),d.fill();}let m=d.getImageData(0,0,a,l),R=r.createImageData(a,l),x=m.data,w=R.data,L=M.length-1;for(let c=0;c<x.length;c+=4){let p=x[c+3];if(p===0)continue;let u=p/255,b=Math.min(Math.floor(u*L),L),[v,N,F]=M[b],_=s+u*(n-s);w[c]=v,w[c+1]=N,w[c+2]=F,w[c+3]=Math.round(_*255);}r.putImageData(R,0,0);}
2
+ exports.DEFAULT_ENDPOINT=D;exports.LogCapture=y;exports.UserTracker=I;exports.renderHeatmap=U;//# sourceMappingURL=index.js.map
3
3
  //# sourceMappingURL=index.js.map