alphana-sdk 0.3.2 → 0.4.5
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/dist/alphana-sdk.global.js +1 -0
- package/dist/index.d.mts +13 -12
- package/dist/index.d.ts +13 -12
- package/dist/index.js +2 -2
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +2 -2
- package/dist/index.mjs.map +1 -1
- package/dist/react/index.d.mts +13 -12
- package/dist/react/index.d.ts +13 -12
- package/dist/react/index.js +1 -1
- package/dist/react/index.js.map +1 -1
- package/dist/react/index.mjs +1 -1
- package/dist/react/index.mjs.map +1 -1
- package/package.json +4 -2
|
@@ -0,0 +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);})();
|
package/dist/index.d.mts
CHANGED
|
@@ -46,18 +46,16 @@ interface TrackerConfig {
|
|
|
46
46
|
*/
|
|
47
47
|
trackLogs?: boolean;
|
|
48
48
|
/**
|
|
49
|
-
*
|
|
50
|
-
*
|
|
51
|
-
*
|
|
52
|
-
*
|
|
53
|
-
*
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
* Minimum milliseconds between screenshots for the same page path.
|
|
58
|
-
* Defaults to 300 000 (5 minutes). Only used when `trackSnapshots` is true.
|
|
49
|
+
* List of page paths for which heatmap data should be captured.
|
|
50
|
+
* Only paths registered here will be tracked. If empty or undefined, the SDK
|
|
51
|
+
* will send data for all pages (the backend enforces limits at ingest time).
|
|
52
|
+
*
|
|
53
|
+
* Obtain the list of registered paths from the alphana dashboard under
|
|
54
|
+
* "Heatmap Pages" for your app, then pass them here.
|
|
55
|
+
*
|
|
56
|
+
* Example: `heatmapPages: ["/", "/pricing", "/dashboard"]`
|
|
59
57
|
*/
|
|
60
|
-
|
|
58
|
+
heatmapPages?: string[];
|
|
61
59
|
/** Called synchronously for every emitted event. */
|
|
62
60
|
onEvent?: (event: TrackerEvent) => void;
|
|
63
61
|
}
|
|
@@ -94,6 +92,10 @@ interface HeatmapPoint {
|
|
|
94
92
|
x: number;
|
|
95
93
|
/** Absolute Y pixel from the top of the page (includes scroll) */
|
|
96
94
|
y: number;
|
|
95
|
+
/** Page scrollWidth at the time of the event (used for accurate remapping) */
|
|
96
|
+
pw?: number;
|
|
97
|
+
/** Page scrollHeight at the time of the event (used for accurate remapping) */
|
|
98
|
+
ph?: number;
|
|
97
99
|
type: "move" | "click" | "scroll";
|
|
98
100
|
path: string;
|
|
99
101
|
timestamp: number;
|
|
@@ -220,7 +222,6 @@ declare class UserTracker {
|
|
|
220
222
|
private heatmap?;
|
|
221
223
|
/** Public so consumers can call logCapture.capture() for manual log entries. */
|
|
222
224
|
logCapture?: LogCapture;
|
|
223
|
-
private snapshot?;
|
|
224
225
|
private initialized;
|
|
225
226
|
private readonly subscribers;
|
|
226
227
|
/** In-memory queue of events waiting to be flushed. */
|
package/dist/index.d.ts
CHANGED
|
@@ -46,18 +46,16 @@ interface TrackerConfig {
|
|
|
46
46
|
*/
|
|
47
47
|
trackLogs?: boolean;
|
|
48
48
|
/**
|
|
49
|
-
*
|
|
50
|
-
*
|
|
51
|
-
*
|
|
52
|
-
*
|
|
53
|
-
*
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
* Minimum milliseconds between screenshots for the same page path.
|
|
58
|
-
* Defaults to 300 000 (5 minutes). Only used when `trackSnapshots` is true.
|
|
49
|
+
* List of page paths for which heatmap data should be captured.
|
|
50
|
+
* Only paths registered here will be tracked. If empty or undefined, the SDK
|
|
51
|
+
* will send data for all pages (the backend enforces limits at ingest time).
|
|
52
|
+
*
|
|
53
|
+
* Obtain the list of registered paths from the alphana dashboard under
|
|
54
|
+
* "Heatmap Pages" for your app, then pass them here.
|
|
55
|
+
*
|
|
56
|
+
* Example: `heatmapPages: ["/", "/pricing", "/dashboard"]`
|
|
59
57
|
*/
|
|
60
|
-
|
|
58
|
+
heatmapPages?: string[];
|
|
61
59
|
/** Called synchronously for every emitted event. */
|
|
62
60
|
onEvent?: (event: TrackerEvent) => void;
|
|
63
61
|
}
|
|
@@ -94,6 +92,10 @@ interface HeatmapPoint {
|
|
|
94
92
|
x: number;
|
|
95
93
|
/** Absolute Y pixel from the top of the page (includes scroll) */
|
|
96
94
|
y: number;
|
|
95
|
+
/** Page scrollWidth at the time of the event (used for accurate remapping) */
|
|
96
|
+
pw?: number;
|
|
97
|
+
/** Page scrollHeight at the time of the event (used for accurate remapping) */
|
|
98
|
+
ph?: number;
|
|
97
99
|
type: "move" | "click" | "scroll";
|
|
98
100
|
path: string;
|
|
99
101
|
timestamp: number;
|
|
@@ -220,7 +222,6 @@ declare class UserTracker {
|
|
|
220
222
|
private heatmap?;
|
|
221
223
|
/** Public so consumers can call logCapture.capture() for manual log entries. */
|
|
222
224
|
logCapture?: LogCapture;
|
|
223
|
-
private snapshot?;
|
|
224
225
|
private initialized;
|
|
225
226
|
private readonly subscribers;
|
|
226
227
|
/** In-memory queue of events waiting to be flushed. */
|
package/dist/index.js
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
'use strict';var j=require('html2canvas');function _interopDefault(e){return e&&e.__esModule?e:{default:e}}var j__default=/*#__PURE__*/_interopDefault(j);var H="__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 O(){if(typeof localStorage=="undefined")return f();try{let r=localStorage.getItem(H);if(r)return r;let t=f();return localStorage.setItem(H,t),t}catch(r){return f()}}async function D(){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 b=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(r,t){let e=0;return (...i)=>{let n=Date.now();n-e>=t&&(e=n,r(...i));}}var p=class p{constructor({emit:t,sessionId:e,sampleRate:i=.3,maxPoints:n=2e3}){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,type:"move"});};this.handleClick=t=>{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,type:"click",...s?{target:s}:{}}),this.checkRageClick(t.clientX,n,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,type:"scroll"});};this.handleNavigate=t=>{this.currentPath=t.detail.path;};this.emit=t,this.sessionId=e,this.sampleRate=i,this.maxPoints=n,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),window.addEventListener("scroll",this.throttledScroll,{passive:true}),window.addEventListener("tracker:navigate",this.handleNavigate);}destroy(){document.removeEventListener("mousemove",this.throttledMouseMove),document.removeEventListener("click",this.handleClick),window.removeEventListener("scroll",this.throttledScroll),window.removeEventListener("tracker:navigate",this.handleNavigate);}canRecord(){var t;return ((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<p.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)<=p.RAGE_RADIUS_PX);s.length>=p.RAGE_THRESHOLD&&(this.emit({type:"rageclik",data:{path:i,x:t,y:e,count:s.length,timestamp:n,sessionId:this.sessionId}}),this.recentClicks=[]);}};p.RAGE_THRESHOLD=3,p.RAGE_WINDOW_MS=1e3,p.RAGE_RADIUS_PX=50;var S=p;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 F=300*1e3,M="__ut_snap_ts__",I=class{constructor(t){this.lastSentPerPath={};var e;this.snapshotUrl=t.endpoint.replace(/\/events$/,"/snapshots"),this.appId=t.appId,this.secretKey=t.secretKey,this.intervalMs=(e=t.intervalMs)!=null?e:F;try{let i=localStorage.getItem(M);i&&(this.lastSentPerPath=JSON.parse(i));}catch(i){}}async capture(t){var i;if(typeof window=="undefined")return;let e=(i=this.lastSentPerPath[t])!=null?i:0;if(!(Date.now()-e<this.intervalMs))try{let n=document.documentElement,s=getComputedStyle(n).backgroundColor||getComputedStyle(document.body).backgroundColor||"#ffffff",o=await j__default.default(n,{allowTaint:!0,useCORS:!0,logging:!1,scale:window.devicePixelRatio||1,width:n.scrollWidth,height:n.scrollHeight,windowWidth:window.innerWidth,windowHeight:window.innerHeight,scrollX:0,scrollY:0,x:0,y:0,backgroundColor:s,foreignObjectRendering:!1,removeContainer:!0}),a=await new Promise(c=>o.toBlob(c,"image/png"));if(!a)return;let d=new FormData;d.append("screenshot",a,"screenshot.png"),d.append("path",t),d.append("width",String(n.scrollWidth)),d.append("height",String(n.scrollHeight)),this.appId&&d.append("appId",this.appId);let l={};this.secretKey&&(l.Authorization=`Bearer ${this.secretKey}`),await fetch(this.snapshotUrl,{method:"POST",headers:l,body:d}),this.lastSentPerPath[t]=Date.now();try{localStorage.setItem(M,JSON.stringify(this.lastSentPerPath));}catch(c){}}catch(n){}}destroy(){}};var _="https://api.alphana.ir/api/events",K={endpoint:_,trackNavigation:true,trackTime:true,trackHeatmap:true,trackLogs:true,trackSnapshots:true,mouseSampleRate:.3,maxHeatmapPoints:2e3,batchSize:20,flushInterval:5e3},R=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 i;let e=(i=t.detail)==null?void 0:i.path;e&&this.snapshot&&this.snapshot.capture(e);};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:f(),visitorId:O(),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 b({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}),this.heatmap.init()),this.cfg.endpoint&&(this.flushTimer=setInterval(()=>{this.queue.length>0&&this.flush();},this.cfg.flushInterval),D().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.cfg.trackSnapshots!==false&&(this.snapshot=new I({endpoint:this.cfg.endpoint,appId:this.cfg.appId,secretKey:this.cfg.secretKey,intervalMs:this.cfg.snapshotIntervalMs}),this.snapshot.capture(window.location.pathname),window.addEventListener("tracker:navigate",this.handleNavigate))),this.initialized=true,this}destroy(){var t,e,i,n,s;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(),(s=this.snapshot)==null||s.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 V(){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,d,l]=r[i+1];for(let c=0;c<e;c++){let m=c/e;t.push([Math.round(n+(a-n)*m),Math.round(s+(d-s)*m),Math.round(o+(l-o)*m)]);}}return t}var N=V();function G(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:d}=r;if(o.clearRect(0,0,a,d),t.length===0)return;let l=document.createElement("canvas");l.width=a,l.height=d;let c=l.getContext("2d");if(!c)return;for(let h of t){let u=h.xPct/100*a,g=h.yPct/100*d,E=h.type==="click"?i*1.6:i,v=c.createRadialGradient(u,g,0,u,g,E);v.addColorStop(0,"rgba(0,0,0,0.15)"),v.addColorStop(1,"rgba(0,0,0,0)"),c.fillStyle=v,c.beginPath(),c.arc(u,g,E,0,Math.PI*2),c.fill();}let m=c.getImageData(0,0,a,d),x=o.createImageData(a,d),C=m.data,w=x.data,L=N.length-1;for(let h=0;h<C.length;h+=4){let u=C[h+3];if(u===0)continue;let g=u/255,E=Math.min(Math.floor(g*L),L),[v,A,B]=N[E],U=s+g*(n-s);w[h]=v,w[h+1]=A,w[h+2]=B,w[h+3]=Math.round(U*255);}o.putImageData(x,0,0);}
|
|
2
|
-
exports.DEFAULT_ENDPOINT=
|
|
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
|
|
3
3
|
//# sourceMappingURL=index.js.map
|