@bluenath/engage 2.0.0 → 2.0.2

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.
@@ -6,9 +6,10 @@ export declare class EngagePro {
6
6
  private queue;
7
7
  private transport;
8
8
  constructor(config: EngageConfig);
9
- identify: (userId: string, traits?: any) => void;
10
- page: (name?: string, properties?: any) => void;
11
- track: (eventName: string, properties?: any, intelligence?: Partial<AnalyticsEvent>) => void;
9
+ identify: (userId: string, traits?: Record<string, unknown>) => void;
10
+ page: (name?: string, properties?: Record<string, unknown>) => void;
11
+ track: (eventName: string, properties?: Record<string, unknown>, intelligence?: Partial<AnalyticsEvent>) => void;
12
+ trackRevenue: (amount: number | string, properties?: Record<string, unknown>, intelligence?: Partial<AnalyticsEvent>) => void;
12
13
  private parseRef;
13
14
  private processEvent;
14
15
  }
package/dist/index.cjs CHANGED
@@ -1 +1 @@
1
- "use strict";var t=Object.defineProperty,e=(e,n,i)=>((e,n,i)=>n in e?t(e,n,{enumerable:!0,configurable:!0,writable:!0,value:i}):e[n]=i)(e,"symbol"!=typeof n?n+"":n,i);Object.defineProperties(exports,{t:{value:!0},[Symbol.toStringTag]:{value:"Module"}});const n=require("react/jsx-runtime"),i=require("react");let s;const r=new Uint8Array(16);function o(){if(!s&&(s="undefined"!=typeof crypto&&crypto.getRandomValues&&crypto.getRandomValues.bind(crypto),!s))throw new Error("crypto.getRandomValues() not supported. See https://github.com/uuidjs/uuid#getrandomvalues-not-supported");return s(r)}const a=[];for(let E=0;E<256;++E)a.push((E+256).toString(16).slice(1));const c={randomUUID:"undefined"!=typeof crypto&&crypto.randomUUID&&crypto.randomUUID.bind(crypto)};function d(t,e,n){if(c.randomUUID&&!t)return c.randomUUID();const i=(t=t||{}).random||(t.rng||o)();return i[6]=15&i[6]|64,i[8]=63&i[8]|128,function(t,e=0){return a[t[e+0]]+a[t[e+1]]+a[t[e+2]]+a[t[e+3]]+"-"+a[t[e+4]]+a[t[e+5]]+"-"+a[t[e+6]]+a[t[e+7]]+"-"+a[t[e+8]]+a[t[e+9]]+"-"+a[t[e+10]]+a[t[e+11]]+a[t[e+12]]+a[t[e+13]]+a[t[e+14]]+a[t[e+15]]}(i)}const h=t=>{let e=2166136261;const n=t.length;for(let i=0;i<n;i++)e^=t.charCodeAt(i),e+=(e<<1)+(e<<4)+(e<<7)+(e<<8)+(e<<24);return("0000000"+(e>>>0).toString(16)).substr(-8)};class l{constructor(t="local"){e(this,"memoryStore",{}),e(this,"keyPrefix","engage_"),e(this,"domain"),this.type=t,this.domain=this.getCookieDomain()}getItem(t){const e=this.keyPrefix+t;if(this.memoryStore.hasOwnProperty(e))return this.memoryStore[e];try{if("local"===this.type&&this.isBrowser())return window.localStorage.getItem(e);if("cookie"===this.type&&this.isBrowser())return this.getCookie(e)}catch(n){return null}return null}setItem(t,e){const n=this.keyPrefix+t;this.memoryStore[n]=e;try{"local"===this.type&&this.isBrowser()?window.localStorage.setItem(n,e):"cookie"===this.type&&this.isBrowser()&&this.setCookie(n,e,365)}catch(i){this.isQuotaError(i)&&(this.type="memory")}}removeItem(t){const e=this.keyPrefix+t;delete this.memoryStore[e];try{"local"===this.type&&this.isBrowser()?window.localStorage.removeItem(e):"cookie"===this.type&&this.isBrowser()&&this.setCookie(e,"",-1)}catch(n){}}getCookie(t){const e=t+"=",n=document.cookie.split(";");for(let i=0;i<n.length;i++){let t=n[i];for(;" "===t.charAt(0);)t=t.substring(1,t.length);if(0===t.indexOf(e))return decodeURIComponent(t.substring(e.length,t.length))}return null}setCookie(t,e,n){let i="";if(n){const t=new Date;t.setTime(t.getTime()+24*n*60*60*1e3),i="; expires="+t.toUTCString()}document.cookie=`${t}=${encodeURIComponent(e)}${i}; path=/; domain=${this.domain}; SameSite=Lax; Secure`}getCookieDomain(){if(!this.isBrowser())return"";const t=window.location.hostname,e=t.split(".");return 1===e.length||"localhost"===t?"":e.length>2?"."+e.slice(-2).join("."):"."+t}isBrowser(){try{return"undefined"!=typeof window&&void 0!==window.document}catch(t){return!1}}isQuotaError(t){return t instanceof DOMException&&(22===t.code||1014===t.code||"QuotaExceededError"===t.name||"NS_ERROR_DOM_QUOTA_REACHED"===t.name)}}class u{constructor(t){e(this,"storage"),e(this,"SESSION_TIMEOUT",18e5),e(this,"deviceId"),e(this,"sessionId"),e(this,"userId",null),e(this,"currentUrl"),e(this,"referrer"),this.storage=new l(t.persistence),this.deviceId=this.getOrSetDeviceId(),this.sessionId="",this.manageSession(),"undefined"!=typeof window?(this.currentUrl=window.location.href,this.referrer=document.referrer,this.listenToHistory()):(this.currentUrl="",this.referrer="")}getOrSetDeviceId(){const t=this.storage.getItem("device_id");if(t)return t;const e=(()=>{if("undefined"==typeof window)return"server-side-id";const t=navigator,e=window.screen,n={userAgent:t.userAgent||"",screenRes:`${e.width}x${e.height}`,colorDepth:e.colorDepth||0,timezone:(new Date).getTimezoneOffset(),language:t.language||"en-US",platform:t.platform||"unknown",hardwareConcurrency:t.hardwareConcurrency||1,deviceMemory:t.deviceMemory||0},i=[n.platform,n.language,n.screenRes,n.colorDepth,n.timezone,n.hardwareConcurrency,n.deviceMemory].join("|");return`${h(i)}-${h(n.userAgent)}`})();return this.storage.setItem("device_id",e),e}manageSession(){const t=Date.now(),e=this.storage.getItem("session_id"),n=parseInt(this.storage.getItem("last_activity")||"0");if(!e||t-n>this.SESSION_TIMEOUT?(this.sessionId=`sess_${t}_${Math.random().toString(36).substr(2,9)}`,this.storage.setItem("session_id",this.sessionId)):this.sessionId=e,this.storage.setItem("last_activity",t.toString()),"undefined"!=typeof window){const t=()=>this.storage.setItem("last_activity",Date.now().toString());window.addEventListener("click",t),window.addEventListener("scroll",t)}}listenToHistory(){const t=history.pushState;history.pushState=(...e)=>{t.apply(history,e),this.handleUrlChange()},window.addEventListener("popstate",()=>this.handleUrlChange())}handleUrlChange(){const t=window.location.href;t!==this.currentUrl&&(this.referrer=this.currentUrl,this.currentUrl=t)}getPayload(){var t;return{library:{name:"@engagepro/analytics",version:"2.0.0"},user:{anonymousId:this.deviceId,id:this.userId},session:{id:this.sessionId,startTime:parseInt(this.sessionId.split("_")[1]||Date.now().toString())},page:{path:"undefined"!=typeof window?window.location.pathname:"",referrer:this.referrer,title:"undefined"!=typeof document?document.title:"",search:"undefined"!=typeof window?window.location.search:"",url:this.currentUrl},network:{online:"undefined"==typeof navigator||navigator.onLine,downlink:null==(t=navigator.connection)?void 0:t.downlink},screen:{width:"undefined"!=typeof screen?screen.width:0,height:"undefined"!=typeof screen?screen.height:0,density:"undefined"!=typeof window?window.devicePixelRatio:1},device:{fingerprint:this.deviceId,type:this.getDeviceType(),userAgent:"undefined"!=typeof navigator?navigator.userAgent:"server"},locale:"undefined"!=typeof navigator?navigator.language:"en-US",timezone:Intl.DateTimeFormat().resolvedOptions().timeZone}}getDeviceType(){if("undefined"==typeof navigator)return"desktop";const t=navigator.userAgent;return/(tablet|ipad|playbook|silk)|(android(?!.*mobi))/i.test(t)?"tablet":/Mobile|Android|iP(hone|od)|IEMobile|BlackBerry|Kindle|Silk-Accelerated/.test(t)?"mobile":"desktop"}}class f{constructor(t){e(this,"queue",[]),e(this,"storage"),e(this,"transport"),e(this,"STORAGE_KEY","engage_queue_v1"),e(this,"isFlushing",!1),e(this,"flushInterval"),e(this,"retryCount",0),this.transport=t,this.storage=new l("local"),this.load(),"undefined"!=typeof window&&(window.addEventListener("online",()=>{this.retryCount=0,this.flush()}),window.addEventListener("visibilitychange",()=>{"hidden"===document.visibilityState&&this.flush()})),this.startTimer()}startTimer(){this.flushInterval&&clearInterval(this.flushInterval);const t=3e3*Math.pow(2,this.retryCount);this.flushInterval=setInterval(()=>{this.flush()},Math.min(t,3e4))}enqueue(t){this.queue.push(t),this.save(),(this.queue.length>=10||"PURCHASE"===t.standardEvent)&&this.flush()}save(){this.storage.setItem(this.STORAGE_KEY,JSON.stringify(this.queue))}load(){const t=this.storage.getItem(this.STORAGE_KEY);if(t)try{this.queue=JSON.parse(t)}catch(e){this.queue=[]}}async flush(){if(0===this.queue.length||this.isFlushing)return;if("undefined"!=typeof navigator&&!navigator.onLine)return;this.isFlushing=!0;const t=[...this.queue];this.queue=[],this.save();try{if(!(await this.transport.send(t)))throw new Error("Server rejected batch");this.retryCount=0,this.startTimer()}catch(e){this.queue=[...t,...this.queue],this.save(),this.retryCount++,this.startTimer()}finally{this.isFlushing=!1}}}class w{constructor(t){this.apiEndpoint=t}async send(t){const e=JSON.stringify({batch:t,sentAt:(new Date).toISOString()});if("undefined"!=typeof navigator&&navigator.sendBeacon&&e.length<6e4){const t=new Blob([e],{type:"application/json"});if(navigator.sendBeacon(this.apiEndpoint,t))return!0}try{return(await fetch(this.apiEndpoint,{method:"POST",headers:{"Content-Type":"application/json"},body:e,keepalive:!0})).ok}catch(n){return!1}}}const p="https://engage-api.bluenath.com/api/v1/tracking/ingest",y=new Set(["localhost","127.0.0.1"]);class v{constructor(t){e(this,"config"),e(this,"context"),e(this,"queue"),e(this,"transport"),e(this,"identify",(t,e)=>{this.context.userId=t,this.processEvent({event:"Identify",properties:{traits:e},standardEvent:"LOGIN",intent:"identity",confidence:1})}),e(this,"page",(t,e)=>{const n=this.context.getPayload().page;this.processEvent({event:t||n.title||"Unknown Page",properties:{path:n.path,referrer:n.referrer,title:n.title,...e},standardEvent:"PAGE_VIEW",intent:"navigation",confidence:1})}),e(this,"track",(t,e,n)=>{this.processEvent({event:t,properties:e||{},...n})}),this.config=t,this.transport=new w((t=>{if(!t)return p;try{const e=new URL(t);return e.hostname.endsWith("bluenath.com")||y.has(e.hostname)?(e.pathname="/api/v1/tracking/ingest",e.search="",e.hash="",e.toString()):p}catch{return p}})(t.apiHost)),this.context=new u({persistence:t.tracking.useCookies?"cookie":"local"}),this.queue=new f(this.transport)}parseRef(t){if(!t)return{};const e=t.match(/^camp_([^_]+)_cr_([^_]+)$/);return e?{campaignId:e[1],creatorId:e[2]}:{}}processEvent(t){var e,n,i,s,r,o;const a=this.context.getPayload(),c=(null==(e=t.properties)?void 0:e.ref)||new URLSearchParams(a.page.search||"").get("ref")||void 0,h=this.parseRef(c),l=(null==(n=t.properties)?void 0:n.value)??(null==(i=t.properties)?void 0:i.amount),u=Number(l),f={event:t.event,properties:t.properties,standardEvent:t.standardEvent,intent:t.intent,confidence:t.confidence,rawLabel:t.rawLabel,timestamp:(new Date).toISOString(),messageId:d(),writeKey:this.config.writeKey,ref:c,campaignId:(null==(s=t.properties)?void 0:s.campaignId)||h.campaignId,creatorId:(null==(r=t.properties)?void 0:r.creatorId)||h.creatorId,value:Number.isFinite(u)?u:void 0,currency:(null==(o=t.properties)?void 0:o.currency)||"INR",userId:a.user.id||void 0,anonymousId:a.user.anonymousId,context:a};this.config.debug,this.queue.enqueue(f)}}class m{constructor(t){e(this,"analytics"),e(this,"metrics",{}),this.analytics=t,"undefined"!=typeof window&&"PerformanceObserver"in window&&this.observe()}observe(){try{new PerformanceObserver(t=>{for(const e of t.getEntries()){const t=e;t.hadRecentInput||(this.metrics.cls=(this.metrics.cls||0)+t.value)}}).observe({type:"layout-shift",buffered:!0}),new PerformanceObserver(t=>{const e=t.getEntries(),n=e[e.length-1];this.metrics.lcp=n.renderTime||n.loadTime,this.logMetric("LCP",this.metrics.lcp)}).observe({type:"largest-contentful-paint",buffered:!0}),new PerformanceObserver(t=>{const e=t.getEntries()[0];e&&(this.metrics.fid=e.processingStart-e.startTime,this.logMetric("FID",this.metrics.fid))}).observe({type:"first-input",buffered:!0}),window.addEventListener("visibilitychange",()=>{"hidden"===document.visibilityState&&this.metrics.cls&&this.logMetric("CLS",this.metrics.cls)})}catch(t){}}logMetric(t,e){e<0||this.analytics.track(`Core Web Vital: ${t}`,{metric:t,value:Math.round(e)},{standardEvent:"PERFORMANCE",intent:"performance",confidence:1,rawLabel:`${t}: ${Math.round(e)}ms`})}}const g=i.createContext(null);let b=null;exports.EngageProProvider=({children:t,...e})=>{const s=i.useRef(null),r=i.useRef(null);s.current||(s.current=new v(e),"undefined"!=typeof window&&new m(s.current));const o=s.current;return i.useEffect(()=>{if(!e.tracking.autoTrack)return;const t=t=>{const e=t.target.closest('button, a, input[type="submit"], [data-track], .clickable');if(e){const t=Date.now(),n=r.current;n&&n.el===e&&t-n.ts<500?(n.count++,n.ts=t,3===n.count&&(o.track("Rage Click detected",{element:e.tagName},{standardEvent:"RAGE_CLICK",intent:"frustration",confidence:1}),r.current=null)):r.current={el:e,count:1,ts:t};const i=(t=>{let e=(t.innerText||t.value||t.getAttribute("aria-label")||"").trim();if(!e){const n=t.querySelector("img");n&&n.alt&&(e=n.alt);const i=t.querySelector("title");i&&(e=i.textContent||"")}const n=e.slice(0,100),i=n.toLowerCase(),s=(t.id||"").toLowerCase(),r=t.href||"";return/add to (cart|bag)|buy now/.test(i)||s.includes("add-to-cart")?{standard:"ADD_TO_CART",intent:"commerce",label:n,confidence:.9}:/checkout|proceed/.test(i)||r.includes("/checkout")?{standard:"INITIATE_CHECKOUT",intent:"commerce",label:n,confidence:.9}:/place order|pay now/.test(i)||s.includes("place-order")?{standard:"PURCHASE",intent:"commerce",label:n,confidence:.95}:/cancel order/.test(i)||s.includes("cancel")?{standard:"ORDER_CANCEL",intent:"lifecycle",label:n,confidence:.85}:/refund|return/.test(i)||s.includes("refund")?{standard:"ORDER_REFUND",intent:"lifecycle",label:n,confidence:.85}:/track package|shipping/.test(i)?{standard:"TRACK_PACKAGE",intent:"lifecycle",label:n,confidence:.8}:/write review/.test(i)||i.includes("star")&&/^[1-5]/.test(i)?{standard:"RATE_PRODUCT",intent:"engagement",label:n,confidence:.8}:i.includes("search")||s.includes("search")?{standard:"SEARCH",intent:"search",label:n,confidence:.7}:{standard:"GENERIC",intent:"interaction",label:n,confidence:.5}})(e),s="A"===e.tagName;o.track("Interaction",{element:e.tagName.toLowerCase(),id:e.id,destination:s?e.href:void 0},{standardEvent:i.standard,intent:i.intent,rawLabel:i.label,confidence:i.confidence})}},n=t=>{const e=t.target;(t=>"password"===t.getAttribute("type")||"hidden"===t.getAttribute("type")||/password|cvc|card|cc-num|ssn|credit|hidden/i.test(t.getAttribute("name")||t.id||""))(e)||"focusin"!==t.type||e.dataset.tracked||(e.dataset.tracked="true",o.track("Form Start",{field:e.name||e.id},{standardEvent:"FORM_START",intent:"identity"}))},i=()=>{const t=new URLSearchParams(window.location.search);t.has("q")&&o.track("Search Query",{query:t.get("q")},{standardEvent:"SEARCH",intent:"search"}),requestAnimationFrame(()=>o.page())},s=history.pushState;return history.pushState=(...t)=>{s.apply(history,t),i()},window.addEventListener("popstate",i),window.addEventListener("click",t,!0),window.addEventListener("focusin",n,!0),i(),()=>{history.pushState=s,window.removeEventListener("popstate",i),window.removeEventListener("click",t,!0),window.removeEventListener("focusin",n,!0)}},[e.tracking.autoTrack]),n.jsx(g.Provider,{value:o,children:t})},exports.default=v,exports.init=t=>(b||(b=new v(t)),b),exports.useAnalytics=()=>{const t=i.useContext(g);if(!t)throw new Error("useAnalytics must be used within EngageProProvider");return t};
1
+ "use strict";var t=Object.defineProperty,e=(e,n,i)=>((e,n,i)=>n in e?t(e,n,{enumerable:!0,configurable:!0,writable:!0,value:i}):e[n]=i)(e,"symbol"!=typeof n?n+"":n,i);Object.defineProperties(exports,{t:{value:!0},[Symbol.toStringTag]:{value:"Module"}});const n=require("react/jsx-runtime"),i=require("react");let s;const r=new Uint8Array(16);function o(){if(!s&&(s="undefined"!=typeof crypto&&crypto.getRandomValues&&crypto.getRandomValues.bind(crypto),!s))throw new Error("crypto.getRandomValues() not supported. See https://github.com/uuidjs/uuid#getrandomvalues-not-supported");return s(r)}const a=[];for(let S=0;S<256;++S)a.push((S+256).toString(16).slice(1));const c={randomUUID:"undefined"!=typeof crypto&&crypto.randomUUID&&crypto.randomUUID.bind(crypto)};function d(t,e,n){if(c.randomUUID&&!t)return c.randomUUID();const i=(t=t||{}).random||(t.rng||o)();return i[6]=15&i[6]|64,i[8]=63&i[8]|128,function(t,e=0){return a[t[e+0]]+a[t[e+1]]+a[t[e+2]]+a[t[e+3]]+"-"+a[t[e+4]]+a[t[e+5]]+"-"+a[t[e+6]]+a[t[e+7]]+"-"+a[t[e+8]]+a[t[e+9]]+"-"+a[t[e+10]]+a[t[e+11]]+a[t[e+12]]+a[t[e+13]]+a[t[e+14]]+a[t[e+15]]}(i)}const h=t=>{let e=2166136261;const n=t.length;for(let i=0;i<n;i++)e^=t.charCodeAt(i),e+=(e<<1)+(e<<4)+(e<<7)+(e<<8)+(e<<24);return("0000000"+(e>>>0).toString(16)).substr(-8)};class u{constructor(t="local"){e(this,"memoryStore",{}),e(this,"keyPrefix","engage_"),e(this,"domain"),this.type=t,this.domain=this.getCookieDomain()}getItem(t){const e=this.keyPrefix+t;if(this.memoryStore.hasOwnProperty(e))return this.memoryStore[e];try{if("local"===this.type&&this.isBrowser())return window.localStorage.getItem(e);if("cookie"===this.type&&this.isBrowser())return this.getCookie(e)}catch(n){return null}return null}setItem(t,e){const n=this.keyPrefix+t;this.memoryStore[n]=e;try{"local"===this.type&&this.isBrowser()?window.localStorage.setItem(n,e):"cookie"===this.type&&this.isBrowser()&&this.setCookie(n,e,365)}catch(i){this.isQuotaError(i)&&(this.type="memory")}}removeItem(t){const e=this.keyPrefix+t;delete this.memoryStore[e];try{"local"===this.type&&this.isBrowser()?window.localStorage.removeItem(e):"cookie"===this.type&&this.isBrowser()&&this.setCookie(e,"",-1)}catch(n){}}getCookie(t){const e=t+"=",n=document.cookie.split(";");for(let i=0;i<n.length;i++){let t=n[i];for(;" "===t.charAt(0);)t=t.substring(1,t.length);if(0===t.indexOf(e))return decodeURIComponent(t.substring(e.length,t.length))}return null}setCookie(t,e,n){let i="";if(n){const t=new Date;t.setTime(t.getTime()+24*n*60*60*1e3),i="; expires="+t.toUTCString()}document.cookie=`${t}=${encodeURIComponent(e)}${i}; path=/; domain=${this.domain}; SameSite=Lax; Secure`}getCookieDomain(){if(!this.isBrowser())return"";const t=window.location.hostname,e=t.split(".");return 1===e.length||"localhost"===t?"":e.length>2?"."+e.slice(-2).join("."):"."+t}isBrowser(){try{return"undefined"!=typeof window&&void 0!==window.document}catch(t){return!1}}isQuotaError(t){return t instanceof DOMException&&(22===t.code||1014===t.code||"QuotaExceededError"===t.name||"NS_ERROR_DOM_QUOTA_REACHED"===t.name)}}class l{constructor(t){e(this,"storage"),e(this,"SESSION_TIMEOUT",18e5),e(this,"deviceId"),e(this,"sessionId"),e(this,"userId",null),e(this,"currentUrl"),e(this,"referrer"),this.storage=new u(t.persistence),this.deviceId=this.getOrSetDeviceId(),this.sessionId="",this.manageSession(),"undefined"!=typeof window?(this.currentUrl=window.location.href,this.referrer=document.referrer,this.listenToHistory()):(this.currentUrl="",this.referrer="")}getOrSetDeviceId(){const t=this.storage.getItem("device_id");if(t)return t;const e=(()=>{if("undefined"==typeof window)return"server-side-id";const t=navigator,e=window.screen,n={userAgent:t.userAgent||"",screenRes:`${e.width}x${e.height}`,colorDepth:e.colorDepth||0,timezone:(new Date).getTimezoneOffset(),language:t.language||"en-US",platform:t.platform||"unknown",hardwareConcurrency:t.hardwareConcurrency||1,deviceMemory:t.deviceMemory||0},i=[n.platform,n.language,n.screenRes,n.colorDepth,n.timezone,n.hardwareConcurrency,n.deviceMemory].join("|");return`${h(i)}-${h(n.userAgent)}`})();return this.storage.setItem("device_id",e),e}manageSession(){const t=Date.now(),e=this.storage.getItem("session_id"),n=parseInt(this.storage.getItem("last_activity")||"0");if(!e||t-n>this.SESSION_TIMEOUT?(this.sessionId=`sess_${t}_${Math.random().toString(36).substr(2,9)}`,this.storage.setItem("session_id",this.sessionId)):this.sessionId=e,this.storage.setItem("last_activity",t.toString()),"undefined"!=typeof window){const t=()=>this.storage.setItem("last_activity",Date.now().toString());window.addEventListener("click",t),window.addEventListener("scroll",t)}}listenToHistory(){const t=history.pushState;history.pushState=(...e)=>{t.apply(history,e),this.handleUrlChange()},window.addEventListener("popstate",()=>this.handleUrlChange())}handleUrlChange(){const t=window.location.href;t!==this.currentUrl&&(this.referrer=this.currentUrl,this.currentUrl=t)}getPayload(){var t;return{library:{name:"@engagepro/analytics",version:"2.0.0"},user:{anonymousId:this.deviceId,id:this.userId},session:{id:this.sessionId,startTime:parseInt(this.sessionId.split("_")[1]||Date.now().toString())},page:{path:"undefined"!=typeof window?window.location.pathname:"",referrer:this.referrer,title:"undefined"!=typeof document?document.title:"",search:"undefined"!=typeof window?window.location.search:"",url:this.currentUrl},network:{online:"undefined"==typeof navigator||navigator.onLine,downlink:null==(t=navigator.connection)?void 0:t.downlink},screen:{width:"undefined"!=typeof screen?screen.width:0,height:"undefined"!=typeof screen?screen.height:0,density:"undefined"!=typeof window?window.devicePixelRatio:1},device:{fingerprint:this.deviceId,type:this.getDeviceType(),userAgent:"undefined"!=typeof navigator?navigator.userAgent:"server"},locale:"undefined"!=typeof navigator?navigator.language:"en-US",timezone:Intl.DateTimeFormat().resolvedOptions().timeZone}}getDeviceType(){if("undefined"==typeof navigator)return"desktop";const t=navigator.userAgent;return/(tablet|ipad|playbook|silk)|(android(?!.*mobi))/i.test(t)?"tablet":/Mobile|Android|iP(hone|od)|IEMobile|BlackBerry|Kindle|Silk-Accelerated/.test(t)?"mobile":"desktop"}}class f{constructor(t){e(this,"queue",[]),e(this,"storage"),e(this,"transport"),e(this,"STORAGE_KEY","engage_queue_v1"),e(this,"isFlushing",!1),e(this,"flushInterval"),e(this,"retryCount",0),this.transport=t,this.storage=new u("local"),this.load(),"undefined"!=typeof window&&(window.addEventListener("online",()=>{this.retryCount=0,this.flush()}),window.addEventListener("visibilitychange",()=>{"hidden"===document.visibilityState&&this.flush()})),this.startTimer()}startTimer(){this.flushInterval&&clearInterval(this.flushInterval);const t=3e3*Math.pow(2,this.retryCount);this.flushInterval=setInterval(()=>{this.flush()},Math.min(t,3e4))}enqueue(t){this.queue.push(t),this.save(),(this.queue.length>=10||"PURCHASE"===t.standardEvent)&&this.flush()}save(){this.storage.setItem(this.STORAGE_KEY,JSON.stringify(this.queue))}load(){const t=this.storage.getItem(this.STORAGE_KEY);if(t)try{this.queue=JSON.parse(t)}catch(e){this.queue=[]}}async flush(){if(0===this.queue.length||this.isFlushing)return;if("undefined"!=typeof navigator&&!navigator.onLine)return;this.isFlushing=!0;const t=[...this.queue];this.queue=[],this.save();try{if(!(await this.transport.send(t)))throw new Error("Server rejected batch");this.retryCount=0,this.startTimer()}catch(e){this.queue=[...t,...this.queue],this.save(),this.retryCount++,this.startTimer()}finally{this.isFlushing=!1}}}class p{constructor(t){this.apiEndpoint=t}async send(t){const e=JSON.stringify({batch:t,sentAt:(new Date).toISOString()});if("undefined"!=typeof navigator&&navigator.sendBeacon&&e.length<6e4){const t=new Blob([e],{type:"application/json"});if(navigator.sendBeacon(this.apiEndpoint,t))return!0}try{return(await fetch(this.apiEndpoint,{method:"POST",headers:{"Content-Type":"application/json"},body:e,keepalive:!0})).ok}catch(n){return!1}}}const w="https://engage-api.bluenath.com/api/v1/tracking/ingest",y=new Set(["localhost","127.0.0.1"]),v={$:"USD",US$:"USD",USD:"USD","₹":"INR",RS:"INR","RS.":"INR",INR:"INR","€":"EUR",EUR:"EUR","£":"GBP",GBP:"GBP","¥":"JPY",JPY:"JPY"},m=t=>{if("string"!=typeof t)return;const e=t.trim().toUpperCase();return e?v[e]?v[e]:e.includes("₹")||e.startsWith("RS")?"INR":e.includes("$")&&!e.includes("CAD")?"USD":e.includes("€")?"EUR":e.includes("£")?"GBP":e.includes("¥")?"JPY":/^[A-Z]{3}$/.test(e)?e:void 0:void 0};class g{constructor(t){e(this,"config"),e(this,"context"),e(this,"queue"),e(this,"transport"),e(this,"identify",(t,e)=>{this.context.userId=t,this.processEvent({event:"Identify",properties:{traits:e},standardEvent:"LOGIN",intent:"identity",confidence:1})}),e(this,"page",(t,e)=>{const n=this.context.getPayload().page;this.processEvent({event:t||n.title||"Unknown Page",properties:{path:n.path,referrer:n.referrer,title:n.title,...e},standardEvent:"PAGE_VIEW",intent:"navigation",confidence:1})}),e(this,"track",(t,e,n)=>{this.processEvent({event:t,properties:e||{},...n})}),e(this,"trackRevenue",(t,e,n)=>{const i=Math.max(0,(t=>{if("number"==typeof t)return Number.isFinite(t)?t:0;const e=t.trim().replace(/[^0-9.+-]/g,""),n=Number(e);return Number.isFinite(n)?n:0})(t)),s=m(null==e?void 0:e.currency)||m(null==e?void 0:e.currencyCode)||m(null==e?void 0:e.currencySymbol)||("string"==typeof t?m(t):void 0)||"USD";this.track("PURCHASE",{...e||{},value:i,amount:i,valuePaise:Math.round(100*i),amountPaise:Math.round(100*i),currency:s,currencyCode:s},{standardEvent:"PURCHASE",intent:"commerce",confidence:1,...n})}),this.config=t,this.transport=new p((t=>{if(!t)return w;try{const e=new URL(t);return e.hostname.endsWith("bluenath.com")||y.has(e.hostname)?(e.pathname="/api/v1/tracking/ingest",e.search="",e.hash="",e.toString()):w}catch{return w}})(t.apiHost)),this.context=new l({persistence:t.tracking.useCookies?"cookie":"local"}),this.queue=new f(this.transport)}parseRef(t){if(!t)return{};const e=t.match(/^camp_([^_]+)_cr_([^_]+)$/);return e?{campaignId:e[1],creatorId:e[2]}:{}}processEvent(t){const e=this.context.getPayload(),n=t.properties.ref,i=("string"==typeof n?n:void 0)||new URLSearchParams(e.page.search||"").get("ref")||void 0,s=this.parseRef(i),r=t.properties.value??t.properties.amount??t.properties.valuePaise??t.properties.amountPaise,o=Number(r),a=t.properties.campaignId,c=t.properties.creatorId,h=t.properties.currency,u={event:t.event,properties:t.properties,standardEvent:t.standardEvent,intent:t.intent,confidence:t.confidence,rawLabel:t.rawLabel,timestamp:(new Date).toISOString(),messageId:d(),writeKey:this.config.writeKey,ref:i,campaignId:("string"==typeof a?a:void 0)||s.campaignId,creatorId:("string"==typeof c?c:void 0)||s.creatorId,value:Number.isFinite(o)?Math.round(o):void 0,valuePaise:Number.isFinite(o)?Math.round(100*o):void 0,currency:("string"==typeof h?h:void 0)||"USD",userId:e.user.id||void 0,anonymousId:e.user.anonymousId,context:e};this.config.debug,this.queue.enqueue(u)}}class b{constructor(t){e(this,"analytics"),e(this,"metrics",{}),this.analytics=t,"undefined"!=typeof window&&"PerformanceObserver"in window&&this.observe()}observe(){try{new PerformanceObserver(t=>{for(const e of t.getEntries()){const t=e;t.hadRecentInput||(this.metrics.cls=(this.metrics.cls||0)+t.value)}}).observe({type:"layout-shift",buffered:!0}),new PerformanceObserver(t=>{const e=t.getEntries(),n=e[e.length-1];this.metrics.lcp=n.renderTime||n.loadTime,this.logMetric("LCP",this.metrics.lcp)}).observe({type:"largest-contentful-paint",buffered:!0}),new PerformanceObserver(t=>{const e=t.getEntries()[0];e&&(this.metrics.fid=e.processingStart-e.startTime,this.logMetric("FID",this.metrics.fid))}).observe({type:"first-input",buffered:!0}),window.addEventListener("visibilitychange",()=>{"hidden"===document.visibilityState&&this.metrics.cls&&this.logMetric("CLS",this.metrics.cls)})}catch(t){}}logMetric(t,e){e<0||this.analytics.track(`Core Web Vital: ${t}`,{metric:t,value:Math.round(e)},{standardEvent:"PERFORMANCE",intent:"performance",confidence:1,rawLabel:`${t}: ${Math.round(e)}ms`})}}const E=i.createContext(null);let R=null;exports.EngageProProvider=({children:t,...e})=>{const s=i.useRef(null),r=i.useRef(null);s.current||(s.current=new g(e),"undefined"!=typeof window&&new b(s.current));const o=s.current;return i.useEffect(()=>{if(!e.tracking.autoTrack)return;const t=t=>{const e=t.target.closest('button, a, input[type="submit"], [data-track], .clickable');if(e){const t=Date.now(),n=r.current;n&&n.el===e&&t-n.ts<500?(n.count++,n.ts=t,3===n.count&&(o.track("Rage Click detected",{element:e.tagName},{standardEvent:"RAGE_CLICK",intent:"frustration",confidence:1}),r.current=null)):r.current={el:e,count:1,ts:t};const i=(t=>{let e=(t.innerText||t.value||t.getAttribute("aria-label")||"").trim();if(!e){const n=t.querySelector("img");n&&n.alt&&(e=n.alt);const i=t.querySelector("title");i&&(e=i.textContent||"")}const n=e.slice(0,100),i=n.toLowerCase(),s=(t.id||"").toLowerCase(),r=t.href||"";return/add to (cart|bag)|buy now/.test(i)||s.includes("add-to-cart")?{standard:"ADD_TO_CART",intent:"commerce",label:n,confidence:.9}:/checkout|proceed/.test(i)||r.includes("/checkout")?{standard:"INITIATE_CHECKOUT",intent:"commerce",label:n,confidence:.9}:/place order|pay now/.test(i)||s.includes("place-order")?{standard:"PURCHASE",intent:"commerce",label:n,confidence:.95}:/cancel order/.test(i)||s.includes("cancel")?{standard:"ORDER_CANCEL",intent:"lifecycle",label:n,confidence:.85}:/refund|return/.test(i)||s.includes("refund")?{standard:"ORDER_REFUND",intent:"lifecycle",label:n,confidence:.85}:/track package|shipping/.test(i)?{standard:"TRACK_PACKAGE",intent:"lifecycle",label:n,confidence:.8}:/write review/.test(i)||i.includes("star")&&/^[1-5]/.test(i)?{standard:"RATE_PRODUCT",intent:"engagement",label:n,confidence:.8}:i.includes("search")||s.includes("search")?{standard:"SEARCH",intent:"search",label:n,confidence:.7}:{standard:"GENERIC",intent:"interaction",label:n,confidence:.5}})(e),s="A"===e.tagName;o.track("Interaction",{element:e.tagName.toLowerCase(),id:e.id,destination:s?e.href:void 0},{standardEvent:i.standard,intent:i.intent,rawLabel:i.label,confidence:i.confidence})}},n=t=>{const e=t.target;(t=>"password"===t.getAttribute("type")||"hidden"===t.getAttribute("type")||/password|cvc|card|cc-num|ssn|credit|hidden/i.test(t.getAttribute("name")||t.id||""))(e)||"focusin"!==t.type||e.dataset.tracked||(e.dataset.tracked="true",o.track("Form Start",{field:e.name||e.id},{standardEvent:"FORM_START",intent:"identity"}))},i=()=>{const t=new URLSearchParams(window.location.search);t.has("q")&&o.track("Search Query",{query:t.get("q")},{standardEvent:"SEARCH",intent:"search"}),requestAnimationFrame(()=>o.page())},s=history.pushState;return history.pushState=(...t)=>{s.apply(history,t),i()},window.addEventListener("popstate",i),window.addEventListener("click",t,!0),window.addEventListener("focusin",n,!0),i(),()=>{history.pushState=s,window.removeEventListener("popstate",i),window.removeEventListener("click",t,!0),window.removeEventListener("focusin",n,!0)}},[e.tracking.autoTrack]),n.jsx(E.Provider,{value:o,children:t})},exports.default=g,exports.init=t=>(R||(R=new g(t)),R),exports.useAnalytics=()=>{const t=i.useContext(E);if(!t)throw new Error("useAnalytics must be used within EngageProProvider");return t};
package/dist/index.js CHANGED
@@ -408,6 +408,22 @@ class Transport {
408
408
  const DEFAULT_INGEST_ENDPOINT = "https://engage-api.bluenath.com/api/v1/tracking/ingest";
409
409
  const FIXED_INGEST_PATH = "/api/v1/tracking/ingest";
410
410
  const ALLOWED_DEV_HOSTS = /* @__PURE__ */ new Set(["localhost", "127.0.0.1"]);
411
+ const DEFAULT_CURRENCY = "USD";
412
+ const SYMBOL_TO_CURRENCY = {
413
+ $: "USD",
414
+ US$: "USD",
415
+ USD: "USD",
416
+ "₹": "INR",
417
+ RS: "INR",
418
+ "RS.": "INR",
419
+ INR: "INR",
420
+ "€": "EUR",
421
+ EUR: "EUR",
422
+ "£": "GBP",
423
+ GBP: "GBP",
424
+ "¥": "JPY",
425
+ JPY: "JPY"
426
+ };
411
427
  const resolveIngestEndpoint = (apiHost) => {
412
428
  if (!apiHost) return DEFAULT_INGEST_ENDPOINT;
413
429
  try {
@@ -427,6 +443,25 @@ const resolveIngestEndpoint = (apiHost) => {
427
443
  return DEFAULT_INGEST_ENDPOINT;
428
444
  }
429
445
  };
446
+ const parseCurrencyToken = (value) => {
447
+ if (typeof value !== "string") return void 0;
448
+ const trimmed = value.trim().toUpperCase();
449
+ if (!trimmed) return void 0;
450
+ if (SYMBOL_TO_CURRENCY[trimmed]) return SYMBOL_TO_CURRENCY[trimmed];
451
+ if (trimmed.includes("₹") || trimmed.startsWith("RS")) return "INR";
452
+ if (trimmed.includes("$") && !trimmed.includes("CAD")) return "USD";
453
+ if (trimmed.includes("€")) return "EUR";
454
+ if (trimmed.includes("£")) return "GBP";
455
+ if (trimmed.includes("¥")) return "JPY";
456
+ return /^[A-Z]{3}$/.test(trimmed) ? trimmed : void 0;
457
+ };
458
+ const parseRevenueAmount = (value) => {
459
+ if (typeof value === "number") return Number.isFinite(value) ? value : 0;
460
+ const normalized = value.trim();
461
+ const numeric = normalized.replace(/[^0-9.+-]/g, "");
462
+ const parsed = Number(numeric);
463
+ return Number.isFinite(parsed) ? parsed : 0;
464
+ };
430
465
  class EngagePro {
431
466
  constructor(config) {
432
467
  __publicField(this, "config");
@@ -469,6 +504,28 @@ class EngagePro {
469
504
  ...intelligence
470
505
  });
471
506
  });
507
+ __publicField(this, "trackRevenue", (amount, properties, intelligence) => {
508
+ const parsedAmount = Math.max(0, parseRevenueAmount(amount));
509
+ const currency = parseCurrencyToken(properties == null ? void 0 : properties.currency) || parseCurrencyToken(properties == null ? void 0 : properties.currencyCode) || parseCurrencyToken(properties == null ? void 0 : properties.currencySymbol) || (typeof amount === "string" ? parseCurrencyToken(amount) : void 0) || DEFAULT_CURRENCY;
510
+ this.track(
511
+ "PURCHASE",
512
+ {
513
+ ...properties || {},
514
+ value: parsedAmount,
515
+ amount: parsedAmount,
516
+ valuePaise: Math.round(parsedAmount * 100),
517
+ amountPaise: Math.round(parsedAmount * 100),
518
+ currency,
519
+ currencyCode: currency
520
+ },
521
+ {
522
+ standardEvent: "PURCHASE",
523
+ intent: "commerce",
524
+ confidence: 1,
525
+ ...intelligence
526
+ }
527
+ );
528
+ });
472
529
  this.config = config;
473
530
  this.transport = new Transport(resolveIngestEndpoint(config.apiHost));
474
531
  this.context = new Context({
@@ -484,12 +541,15 @@ class EngagePro {
484
541
  }
485
542
  // Internal Helper
486
543
  processEvent(data) {
487
- var _a, _b, _c, _d, _e, _f;
488
544
  const baseContext = this.context.getPayload();
489
- const ref = ((_a = data.properties) == null ? void 0 : _a.ref) || new URLSearchParams(baseContext.page.search || "").get("ref") || void 0;
545
+ const refValue = data.properties.ref;
546
+ const ref = (typeof refValue === "string" ? refValue : void 0) || new URLSearchParams(baseContext.page.search || "").get("ref") || void 0;
490
547
  const refParts = this.parseRef(ref);
491
- const valueCandidate = ((_b = data.properties) == null ? void 0 : _b.value) ?? ((_c = data.properties) == null ? void 0 : _c.amount);
548
+ const valueCandidate = data.properties.value ?? data.properties.amount ?? data.properties.valuePaise ?? data.properties.amountPaise;
492
549
  const value = Number(valueCandidate);
550
+ const campaignIdValue = data.properties.campaignId;
551
+ const creatorIdValue = data.properties.creatorId;
552
+ const currencyValue = data.properties.currency;
493
553
  const payload = {
494
554
  event: data.event,
495
555
  properties: data.properties,
@@ -503,10 +563,11 @@ class EngagePro {
503
563
  messageId: v4(),
504
564
  writeKey: this.config.writeKey,
505
565
  ref,
506
- campaignId: ((_d = data.properties) == null ? void 0 : _d.campaignId) || refParts.campaignId,
507
- creatorId: ((_e = data.properties) == null ? void 0 : _e.creatorId) || refParts.creatorId,
508
- value: Number.isFinite(value) ? value : void 0,
509
- currency: ((_f = data.properties) == null ? void 0 : _f.currency) || "INR",
566
+ campaignId: (typeof campaignIdValue === "string" ? campaignIdValue : void 0) || refParts.campaignId,
567
+ creatorId: (typeof creatorIdValue === "string" ? creatorIdValue : void 0) || refParts.creatorId,
568
+ value: Number.isFinite(value) ? Math.round(value) : void 0,
569
+ valuePaise: Number.isFinite(value) ? Math.round(value * 100) : void 0,
570
+ currency: (typeof currencyValue === "string" ? currencyValue : void 0) || DEFAULT_CURRENCY,
510
571
  // Identity
511
572
  userId: baseContext.user.id || void 0,
512
573
  anonymousId: baseContext.user.anonymousId,
@@ -39,7 +39,7 @@ export interface AnalyticsContext {
39
39
  }
40
40
  export interface AnalyticsEvent {
41
41
  event: string;
42
- properties?: Record<string, any>;
42
+ properties?: Record<string, unknown>;
43
43
  standardEvent?: StandardEvent;
44
44
  intent?: IntentType;
45
45
  confidence?: number;
@@ -53,7 +53,13 @@ export interface AnalyticsEvent {
53
53
  creatorId?: string;
54
54
  ref?: string;
55
55
  value?: number;
56
+ amount?: number;
57
+ valuePaise?: number;
58
+ amountPaise?: number;
56
59
  currency?: string;
60
+ currencyCode?: string;
61
+ currencySymbol?: string;
62
+ baseCurrency?: string;
57
63
  context?: Partial<AnalyticsContext>;
58
64
  }
59
65
  export interface EngageConfig {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bluenath/engage",
3
- "version": "2.0.0",
3
+ "version": "2.0.2",
4
4
  "type": "module",
5
5
  "main": "./dist/index.cjs",
6
6
  "module": "./dist/index.js",